2 * Copyright (c) 2015-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <sys/kernel.h>
29 #include <sys/kernel_types.h>
30 #include <sys/persona.h>
31 #include <pexpert/pexpert.h>
34 #include <machine/atomic.h>
36 #include <kern/assert.h>
37 #include <kern/simple_lock.h>
38 #include <kern/task.h>
39 #include <kern/zalloc.h>
40 #include <mach/thread_act.h>
41 #include <kern/thread.h>
43 #include <sys/param.h>
44 #include <sys/proc_internal.h>
45 #include <sys/kauth.h>
46 #include <sys/proc_info.h>
47 #include <sys/resourcevar.h>
50 #define pna_err(fmt, ...) \
51 os_log_error(OS_LOG_DEFAULT, "ERROR: " fmt, ## __VA_ARGS__)
53 #define MAX_PERSONAS 512
55 #define TEMP_PERSONA_ID 499
57 #define FIRST_PERSONA_ID 501
58 #define PERSONA_ID_STEP 10
60 #define PERSONA_ALLOC_TOKEN (0x7a0000ae)
61 #define PERSONA_INIT_TOKEN (0x7500005e)
62 #define PERSONA_MAGIC (0x0aa55aa0)
63 #define persona_initialized(p) ((p)->pna_valid == PERSONA_MAGIC || (p)->pna_valid == PERSONA_INIT_TOKEN)
64 #define persona_valid(p) ((p)->pna_valid == PERSONA_MAGIC)
65 #define persona_mkinvalid(p) ((p)->pna_valid = ~(PERSONA_MAGIC))
67 static LIST_HEAD(personalist
, persona
) all_personas
;
68 static uint32_t g_total_personas
;
69 const uint32_t g_max_personas
= MAX_PERSONAS
;
70 struct persona
*system_persona
= NULL
;
71 struct persona
*proxy_system_persona
= NULL
;
72 #if !defined(XNU_TARGET_OS_OSX)
73 int unique_persona
= 1;
75 int unique_persona
= 0;
78 static uid_t g_next_persona_id
;
80 LCK_GRP_DECLARE(persona_lck_grp
, "personas");
81 LCK_MTX_DECLARE(all_personas_lock
, &persona_lck_grp
);
83 os_refgrp_decl(static, persona_refgrp
, "persona", NULL
);
85 static ZONE_DECLARE(persona_zone
, "personas", sizeof(struct persona
), ZC_ZFREE_CLEARMEM
);
87 kauth_cred_t g_default_persona_cred
;
88 extern struct auditinfo_addr
* const audit_default_aia_p
;
90 #define lock_personas() lck_mtx_lock(&all_personas_lock)
91 #define unlock_personas() lck_mtx_unlock(&all_personas_lock)
93 extern void mach_kauth_cred_uthread_update(void);
95 extern kern_return_t
bank_get_bank_ledger_thread_group_and_persona(void *voucher
,
96 void *bankledger
, void **banktg
, uint32_t *persona_id
);
98 ipc_voucher_release(void *voucher
);
101 personas_bootstrap(void)
103 struct posix_cred pcred
;
104 int unique_persona_bootarg
;
106 persona_dbg("Initializing persona subsystem");
107 LIST_INIT(&all_personas
);
108 g_total_personas
= 0;
110 g_next_persona_id
= FIRST_PERSONA_ID
;
113 * setup the default credentials that a persona temporarily
114 * inherits (to work around kauth APIs)
116 bzero(&pcred
, sizeof(pcred
));
117 pcred
.cr_uid
= pcred
.cr_ruid
= pcred
.cr_svuid
= TEMP_PERSONA_ID
;
118 pcred
.cr_rgid
= pcred
.cr_svgid
= TEMP_PERSONA_ID
;
119 pcred
.cr_groups
[0] = TEMP_PERSONA_ID
;
120 pcred
.cr_ngroups
= 1;
121 pcred
.cr_flags
= CRF_NOMEMBERD
;
122 pcred
.cr_gmuid
= KAUTH_UID_NONE
;
124 g_default_persona_cred
= posix_cred_create(&pcred
);
125 if (!g_default_persona_cred
) {
126 panic("couldn't create default persona credentials!");
129 /* posix_cred_create() sets this value to NULL */
130 g_default_persona_cred
->cr_audit
.as_aia_p
= audit_default_aia_p
;
132 if (PE_parse_boot_argn("unique_persona", &unique_persona_bootarg
, sizeof(unique_persona_bootarg
))) {
133 unique_persona
= !!unique_persona_bootarg
;
138 persona_alloc(uid_t id
, const char *login
, persona_type_t type
, char *path
, int *error
)
140 struct persona
*persona
;
144 pna_err("Must provide a login name for a new persona!");
151 if (type
<= PERSONA_INVALID
|| type
> PERSONA_TYPE_MAX
) {
152 pna_err("Invalid type: %d", type
);
159 persona
= (struct persona
*)zalloc(persona_zone
);
167 bzero(persona
, sizeof(*persona
));
169 if (os_atomic_inc(&g_total_personas
, relaxed
) > MAX_PERSONAS
) {
170 /* too many personas! */
171 pna_err("too many active personas!");
176 strncpy(persona
->pna_login
, login
, sizeof(persona
->pna_login
) - 1);
177 persona_dbg("Starting persona allocation for: '%s'", persona
->pna_login
);
179 LIST_INIT(&persona
->pna_members
);
180 lck_mtx_init(&persona
->pna_lock
, &persona_lck_grp
, LCK_ATTR_NULL
);
181 os_ref_init(&persona
->pna_refcount
, &persona_refgrp
);
184 * Setup initial (temporary) kauth_cred structure
185 * We need to do this here because all kauth calls require
186 * an existing cred structure.
188 persona
->pna_cred
= kauth_cred_create(g_default_persona_cred
);
189 if (!persona
->pna_cred
) {
190 pna_err("could not copy initial credentials!");
195 persona
->pna_type
= type
;
196 persona
->pna_id
= id
;
197 persona
->pna_valid
= PERSONA_ALLOC_TOKEN
;
198 persona
->pna_path
= path
;
201 * NOTE: this persona has not been fully initialized. A subsequent
202 * call to persona_init_begin() followed by persona_init_end() will make
203 * the persona visible to the rest of the system.
211 os_atomic_dec(&g_total_personas
, relaxed
);
212 zfree(persona_zone
, persona
);
222 * This function begins initialization of a persona. It first acquires the
223 * global persona list lock via lock_personas(), then selects an appropriate
224 * persona ID and sets up the persona's credentials. This function *must* be
225 * followed by a call to persona_init_end() which will mark the persona
229 * persona has been allocated via persona_alloc()
233 * global persona list is locked (even on error)
236 persona_init_begin(struct persona
*persona
)
240 kauth_cred_t tmp_cred
;
244 if (!persona
|| (persona
->pna_valid
!= PERSONA_ALLOC_TOKEN
)) {
248 id
= persona
->pna_id
;
252 if (id
== PERSONA_ID_NONE
) {
253 persona
->pna_id
= g_next_persona_id
;
256 persona_dbg("Beginning Initialization of %d:%d (%s)...", id
, persona
->pna_id
, persona
->pna_login
);
259 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
261 if (id
== PERSONA_ID_NONE
&& tmp
->pna_id
== persona
->pna_id
) {
264 * someone else manually claimed this ID, and we're
265 * trying to allocate an ID for the caller: try again
267 g_next_persona_id
+= PERSONA_ID_STEP
;
270 if (strncmp(tmp
->pna_login
, persona
->pna_login
, sizeof(tmp
->pna_login
)) == 0 ||
271 tmp
->pna_id
== persona
->pna_id
) {
274 * Disallow use of identical login names and re-use
275 * of previously allocated persona IDs
286 /* ensure the cred has proper UID/GID defaults */
287 kauth_cred_ref(persona
->pna_cred
);
288 tmp_cred
= kauth_cred_setuidgid(persona
->pna_cred
,
291 kauth_cred_unref(&persona
->pna_cred
);
292 if (tmp_cred
!= persona
->pna_cred
) {
293 persona
->pna_cred
= tmp_cred
;
296 if (!persona
->pna_cred
) {
301 /* it should be a member of exactly 1 group (equal to its UID) */
302 new_group
= (gid_t
)persona
->pna_id
;
304 kauth_cred_ref(persona
->pna_cred
);
305 /* opt _out_ of memberd as a default */
306 tmp_cred
= kauth_cred_setgroups(persona
->pna_cred
,
307 &new_group
, 1, KAUTH_UID_NONE
);
308 kauth_cred_unref(&persona
->pna_cred
);
309 if (tmp_cred
!= persona
->pna_cred
) {
310 persona
->pna_cred
= tmp_cred
;
313 if (!persona
->pna_cred
) {
318 /* if the kernel supplied the persona ID, increment for next time */
319 if (id
== PERSONA_ID_NONE
) {
320 g_next_persona_id
+= PERSONA_ID_STEP
;
323 persona
->pna_valid
= PERSONA_INIT_TOKEN
;
327 persona_dbg("ERROR:%d while initializing %d:%d (%s)...", err
, id
, persona
->pna_id
, persona
->pna_login
);
329 * mark the persona with an error so that persona_init_end()
330 * will *not* add it to the global list.
332 persona
->pna_id
= PERSONA_ID_NONE
;
336 * leave the global persona list locked: it will be
337 * unlocked in a call to persona_init_end()
345 * This function finalizes the persona initialization by marking it valid and
346 * adding it to the global list of personas. After unlocking the global list,
347 * the persona will be visible to the reset of the system. The function will
348 * only mark the persona valid if the input parameter 'error' is 0.
351 * persona is initialized via persona_init_begin()
352 * global persona list is locked via lock_personas()
355 * global persona list is unlocked
358 persona_init_end(struct persona
*persona
, int error
)
360 if (persona
== NULL
) {
365 * If the pna_valid member is set to the INIT_TOKEN value, then it has
366 * successfully gone through persona_init_begin(), and we can mark it
367 * valid and make it visible to the rest of the system. However, if
368 * there was an error either during initialization or otherwise, we
369 * need to decrement the global count of personas because this one
370 * will be disposed-of by the callers invocation of persona_put().
372 if (error
!= 0 || persona
->pna_valid
== PERSONA_ALLOC_TOKEN
) {
373 persona_dbg("ERROR:%d after initialization of %d (%s)", error
, persona
->pna_id
, persona
->pna_login
);
374 /* remove this persona from the global count */
375 os_atomic_dec(&g_total_personas
, relaxed
);
376 } else if (error
== 0 &&
377 persona
->pna_valid
== PERSONA_INIT_TOKEN
) {
378 persona
->pna_valid
= PERSONA_MAGIC
;
379 LIST_INSERT_HEAD(&all_personas
, persona
, pna_list
);
380 persona_dbg("Initialization of %d (%s) Complete.", persona
->pna_id
, persona
->pna_login
);
387 * persona_verify_and_set_uniqueness
389 * This function checks the persona, if the one being spawned is of type
390 * PERSONA_SYSTEM or PERSONA_SYSTEM_PROXY, is unique.
393 * global persona list is locked on entry and return.
396 * EEXIST: if persona is system/system-proxy and is not unique.
400 persona_verify_and_set_uniqueness(struct persona
*persona
)
402 if (persona
== NULL
) {
406 if (!unique_persona
) {
410 if (persona
->pna_type
== PERSONA_SYSTEM
) {
411 if (system_persona
!= NULL
) {
414 system_persona
= persona
;
418 if (persona
->pna_type
== PERSONA_SYSTEM_PROXY
) {
419 if (proxy_system_persona
!= NULL
) {
422 proxy_system_persona
= persona
;
431 * This function checks if the persona spawned is unique.
438 persona_is_unique(struct persona
*persona
)
440 if (persona
== NULL
) {
444 if (!unique_persona
) {
448 if (persona
->pna_type
== PERSONA_SYSTEM
||
449 persona
->pna_type
== PERSONA_SYSTEM_PROXY
) {
456 static struct persona
*
457 persona_get_locked(struct persona
*persona
)
459 os_ref_retain_locked(&persona
->pna_refcount
);
464 persona_get(struct persona
*persona
)
470 persona_lock(persona
);
471 ret
= persona_get_locked(persona
);
472 persona_unlock(persona
);
478 persona_put(struct persona
*persona
)
486 persona_lock(persona
);
487 if (os_ref_release_locked(&persona
->pna_refcount
) == 0) {
490 persona_unlock(persona
);
496 persona_dbg("Destroying persona %s", persona_desc(persona
, 0));
498 /* release our credential reference */
499 if (persona
->pna_cred
) {
500 kauth_cred_unref(&persona
->pna_cred
);
503 /* remove it from the global list and decrement the count */
505 persona_lock(persona
);
506 if (persona_valid(persona
)) {
507 LIST_REMOVE(persona
, pna_list
);
508 if (os_atomic_dec_orig(&g_total_personas
, relaxed
) == 0) {
509 panic("persona count underflow!\n");
511 persona_mkinvalid(persona
);
513 if (persona
->pna_path
!= NULL
) {
514 zfree(ZV_NAMEI
, persona
->pna_path
);
516 persona_unlock(persona
);
519 assert(LIST_EMPTY(&persona
->pna_members
));
520 memset(persona
, 0, sizeof(*persona
));
521 zfree(persona_zone
, persona
);
525 persona_get_id(struct persona
*persona
)
528 return persona
->pna_id
;
530 return PERSONA_ID_NONE
;
534 persona_lookup(uid_t id
)
536 struct persona
*persona
, *tmp
;
541 * simple, linear lookup for now: there shouldn't be too many
542 * of these in memory at any given time.
545 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
547 if (tmp
->pna_id
== id
&& persona_valid(tmp
)) {
548 persona
= persona_get_locked(tmp
);
560 persona_lookup_and_invalidate(uid_t id
)
562 struct persona
*persona
, *entry
, *tmp
;
567 LIST_FOREACH_SAFE(entry
, &all_personas
, pna_list
, tmp
) {
569 if (entry
->pna_id
== id
) {
570 if (persona_valid(entry
) && !persona_is_unique(entry
)) {
571 persona
= persona_get_locked(entry
);
572 assert(persona
!= NULL
);
573 LIST_REMOVE(persona
, pna_list
);
574 if (os_atomic_dec_orig(&g_total_personas
, relaxed
) == 0) {
575 panic("persona ref count underflow!\n");
577 persona_mkinvalid(persona
);
579 persona_unlock(entry
);
582 persona_unlock(entry
);
590 persona_find_by_type(persona_type_t persona_type
, struct persona
**persona
, size_t *plen
)
592 return persona_find_all(NULL
, PERSONA_ID_NONE
, persona_type
, persona
, plen
);
596 persona_find(const char *login
, uid_t uid
,
597 struct persona
**persona
, size_t *plen
)
599 return persona_find_all(login
, uid
, PERSONA_INVALID
, persona
, plen
);
603 persona_find_all(const char *login
, uid_t uid
, persona_type_t persona_type
,
604 struct persona
**persona
, size_t *plen
)
613 if (uid
!= PERSONA_ID_NONE
) {
616 if ((persona_type
> PERSONA_INVALID
) && (persona_type
<= PERSONA_TYPE_MAX
)) {
618 } else if (persona_type
!= PERSONA_INVALID
) {
626 persona_dbg("Searching with %d parameters (l:\"%s\", u:%d)",
630 LIST_FOREACH(tmp
, &all_personas
, pna_list
) {
633 if (login
&& strncmp(tmp
->pna_login
, login
, sizeof(tmp
->pna_login
)) == 0) {
636 if (uid
!= PERSONA_ID_NONE
&& uid
== tmp
->pna_id
) {
639 if (persona_type
!= PERSONA_INVALID
&& persona_type
== tmp
->pna_type
) {
643 if (persona
&& *plen
> found
) {
644 persona
[found
] = persona_get_locked(tmp
);
650 persona_dbg("ID:%d Matched %d/%d, found:%d, *plen:%d",
651 tmp
->pna_id
, m
, match
, (int)found
, (int)*plen
);
666 persona_proc_get(pid_t pid
)
668 struct persona
*persona
;
669 proc_t p
= proc_find(pid
);
676 persona
= persona_get(p
->p_persona
);
685 current_persona_get(void)
687 struct persona
*persona
= NULL
;
688 uid_t current_persona_id
= PERSONA_ID_NONE
;
689 ipc_voucher_t voucher
;
691 thread_get_mach_voucher(current_thread(), 0, &voucher
);
692 /* returns a voucher ref */
693 if (voucher
!= IPC_VOUCHER_NULL
) {
695 * If the voucher doesn't contain a bank attribute, it uses
696 * the default bank task value to determine the persona id
697 * which is the same as the proc's persona id
699 bank_get_bank_ledger_thread_group_and_persona(voucher
, NULL
,
700 NULL
, ¤t_persona_id
);
701 ipc_voucher_release(voucher
);
702 persona
= persona_lookup(current_persona_id
);
704 /* Fallback - get the proc's persona */
705 proc_t p
= current_proc();
707 persona
= persona_get(p
->p_persona
);
714 * inherit a persona from parent to child
717 persona_proc_inherit(proc_t child
, proc_t parent
)
719 if (child
->p_persona
!= NULL
) {
720 persona_dbg("proc_inherit: child already in persona: %s",
721 persona_desc(child
->p_persona
, 0));
725 /* no persona to inherit */
726 if (parent
->p_persona
== NULL
) {
730 return persona_proc_adopt(child
, parent
->p_persona
, parent
->p_ucred
);
734 persona_proc_adopt_id(proc_t p
, uid_t id
, kauth_cred_t auth_override
)
737 struct persona
*persona
;
739 persona
= persona_lookup(id
);
744 ret
= persona_proc_adopt(p
, persona
, auth_override
);
746 /* put the reference from the lookup() */
747 persona_put(persona
);
753 typedef enum e_persona_reset_op
{
754 PROC_REMOVE_PERSONA
= 1,
755 PROC_RESET_OLD_PERSONA
= 2,
756 } persona_reset_op_t
;
759 * internal cleanup routine for proc_set_cred_internal
762 static struct persona
*
763 proc_reset_persona_internal(proc_t p
, persona_reset_op_t op
,
764 struct persona
*old_persona
,
765 struct persona
*new_persona
)
767 #if (DEVELOPMENT || DEBUG)
768 persona_lock_assert_held(new_persona
);
772 case PROC_REMOVE_PERSONA
:
773 old_persona
= p
->p_persona
;
775 case PROC_RESET_OLD_PERSONA
:
778 /* invalid arguments */
782 /* unlock the new persona (locked on entry) */
783 persona_unlock(new_persona
);
784 /* lock the old persona and the process */
785 assert(old_persona
!= NULL
);
786 persona_lock(old_persona
);
790 case PROC_REMOVE_PERSONA
:
791 LIST_REMOVE(p
, p_persona_list
);
794 case PROC_RESET_OLD_PERSONA
:
795 p
->p_persona
= old_persona
;
796 LIST_INSERT_HEAD(&old_persona
->pna_members
, p
, p_persona_list
);
801 persona_unlock(old_persona
);
803 /* re-lock the new persona */
804 persona_lock(new_persona
);
809 * Assumes persona is locked.
810 * On success, takes a reference to 'persona' and returns the
811 * previous persona the process had adopted. The caller is
812 * responsible to release the reference.
814 static struct persona
*
815 proc_set_cred_internal(proc_t p
, struct persona
*persona
,
816 kauth_cred_t auth_override
, int *rlim_error
)
818 struct persona
*old_persona
= NULL
;
819 kauth_cred_t my_cred
, my_new_cred
;
820 uid_t old_uid
, new_uid
;
822 rlim_t nproc
= proc_limitgetcur(p
, RLIMIT_NPROC
, TRUE
);
825 * This operation must be done under the proc trans lock
826 * by the thread which took the trans lock!
828 assert(((p
->p_lflag
& P_LINTRANSIT
) == P_LINTRANSIT
) &&
829 p
->p_transholder
== current_thread());
830 assert(persona
!= NULL
);
832 /* no work to do if we "re-adopt" the same persona */
833 if (p
->p_persona
== persona
) {
838 * If p is in a persona, then we need to remove 'p' from the list of
839 * processes in that persona. To do this, we need to drop the lock
840 * held on the incoming (new) persona and lock the old one.
843 old_persona
= proc_reset_persona_internal(p
, PROC_REMOVE_PERSONA
,
848 my_new_cred
= auth_override
;
850 my_new_cred
= persona
->pna_cred
;
854 panic("NULL credentials (persona:%p)", persona
);
859 kauth_cred_ref(my_new_cred
);
861 new_uid
= persona
->pna_id
;
864 * Check to see if we will hit a proc rlimit by moving the process
865 * into the persona. If so, we'll bail early before actually moving
866 * the process or changing its credentials.
869 (rlim_t
)chgproccnt(new_uid
, 0) > nproc
) {
870 pna_err("PID:%d hit proc rlimit in new persona(%d): %s",
871 p
->p_pid
, new_uid
, persona_desc(persona
, 1));
872 *rlim_error
= EACCES
;
874 (void)proc_reset_persona_internal(p
, PROC_RESET_OLD_PERSONA
,
875 old_persona
, persona
);
877 kauth_cred_unref(&my_new_cred
);
882 * Set the new credentials on the proc
885 my_cred
= kauth_cred_proc_ref(p
);
886 persona_dbg("proc_adopt PID:%d, %s -> %s",
888 persona_desc(old_persona
, 1),
889 persona_desc(persona
, 1));
891 old_uid
= kauth_cred_getruid(my_cred
);
893 if (my_cred
!= my_new_cred
) {
894 kauth_cred_t old_cred
= my_cred
;
898 * We need to protect against a race where another thread
899 * also changed the credential after we took our
900 * reference. If p_ucred has changed then we should
901 * restart this again with the new cred.
903 if (p
->p_ucred
!= my_cred
) {
904 proc_ucred_unlock(p
);
905 kauth_cred_unref(&my_cred
);
910 /* update the credential and take a ref for the proc */
911 kauth_cred_ref(my_new_cred
);
912 p
->p_ucred
= my_new_cred
;
914 /* update cred on proc (and current thread) */
915 mach_kauth_cred_uthread_update();
916 PROC_UPDATE_CREDS_ONPROC(p
);
918 /* drop the proc's old ref on the credential */
919 kauth_cred_unref(&old_cred
);
920 proc_ucred_unlock(p
);
923 /* drop this function's reference to the old cred */
924 kauth_cred_unref(&my_cred
);
927 * Update the proc count.
928 * If the UIDs are the same, then there is no work to do.
931 old_uid
= old_persona
->pna_id
;
934 if (new_uid
!= old_uid
) {
935 count
= chgproccnt(old_uid
, -1);
936 persona_dbg("Decrement %s:%d proc_count to: %lu",
937 old_persona
? "Persona" : "UID", old_uid
, count
);
940 * Increment the proc count on the UID associated with
941 * the new persona. Enforce the resource limit just
944 count
= chgproccnt(new_uid
, 1);
945 persona_dbg("Increment Persona:%d (UID:%d) proc_count to: %lu",
946 new_uid
, kauth_cred_getuid(my_new_cred
), count
);
949 OSBitOrAtomic(P_ADOPTPERSONA
, &p
->p_flag
);
952 p
->p_persona
= persona_get_locked(persona
);
953 LIST_INSERT_HEAD(&persona
->pna_members
, p
, p_persona_list
);
956 kauth_cred_unref(&my_new_cred
);
962 persona_proc_adopt(proc_t p
, struct persona
*persona
, kauth_cred_t auth_override
)
965 struct persona
*old_persona
;
971 persona_dbg("%d adopting Persona %d (%s)", proc_pid(p
),
972 persona
->pna_id
, persona_desc(persona
, 0));
974 persona_lock(persona
);
975 if (!persona
->pna_cred
|| !persona_valid(persona
)) {
976 persona_dbg("Invalid persona (%s): NULL credentials!", persona_desc(persona
, 1));
977 persona_unlock(persona
);
981 /* the persona credentials can no longer be adjusted */
982 persona
->pna_cred_locked
= 1;
985 * assume the persona: this may drop and re-acquire the persona lock!
988 old_persona
= proc_set_cred_internal(p
, persona
, auth_override
, &error
);
990 /* join the process group associated with the persona */
991 if (persona
->pna_pgid
) {
992 uid_t uid
= kauth_cred_getuid(persona
->pna_cred
);
993 persona_dbg(" PID:%d, pgid:%d%s",
994 p
->p_pid
, persona
->pna_pgid
,
995 persona
->pna_pgid
== uid
? ", new_session" : ".");
996 enterpgrp(p
, persona
->pna_pgid
, persona
->pna_pgid
== uid
);
999 /* Only Multiuser Mode needs to update the session login name to the persona name */
1000 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
1001 volatile uint32_t *multiuser_flag_address
= (volatile uint32_t *)(uintptr_t)(_COMM_PAGE_MULTIUSER_CONFIG
);
1002 uint32_t multiuser_flags
= *multiuser_flag_address
;
1003 /* set the login name of the session */
1004 if (multiuser_flags
) {
1005 struct session
* sessp
= proc_session(p
);
1006 if (sessp
!= SESSION_NULL
) {
1007 session_lock(sessp
);
1008 bcopy(persona
->pna_login
, sessp
->s_login
, MAXLOGNAME
);
1009 session_unlock(sessp
);
1010 session_rele(sessp
);
1014 persona_unlock(persona
);
1016 set_security_token(p
);
1019 * Drop the reference to the old persona.
1022 persona_put(old_persona
);
1025 persona_dbg("%s", error
== 0 ? "SUCCESS" : "FAILED");
1030 persona_proc_drop(proc_t p
)
1032 struct persona
*persona
= NULL
;
1034 persona_dbg("PID:%d, %s -> <none>", p
->p_pid
, persona_desc(p
->p_persona
, 0));
1037 * There are really no other credentials for us to assume,
1038 * so we'll just continue running with the credentials
1039 * we got from the persona.
1043 * the locks must be taken in reverse order here, so
1044 * we have to be careful not to cause deadlock
1050 if (!persona_try_lock(p
->p_persona
)) {
1052 mutex_pause(0); /* back-off time */
1055 persona
= p
->p_persona
;
1056 LIST_REMOVE(p
, p_persona_list
);
1057 p
->p_persona
= NULL
;
1059 ruid
= kauth_cred_getruid(p
->p_ucred
);
1060 puid
= kauth_cred_getuid(persona
->pna_cred
);
1062 (void)chgproccnt(ruid
, 1);
1063 (void)chgproccnt(puid
, -1);
1069 * if the proc had a persona, then it is still locked here
1070 * (preserving proper lock ordering)
1074 persona_unlock(persona
);
1075 persona_put(persona
);
1082 persona_get_type(struct persona
*persona
)
1087 return PERSONA_INVALID
;
1090 persona_lock(persona
);
1091 if (!persona_valid(persona
)) {
1092 persona_unlock(persona
);
1093 return PERSONA_INVALID
;
1095 type
= persona
->pna_type
;
1096 persona_unlock(persona
);
1102 persona_set_cred(struct persona
*persona
, kauth_cred_t cred
)
1105 kauth_cred_t my_cred
;
1106 if (!persona
|| !cred
) {
1110 persona_lock(persona
);
1111 if (!persona_initialized(persona
)) {
1115 if (persona
->pna_cred_locked
) {
1120 /* create a new cred from the passed-in cred */
1121 my_cred
= kauth_cred_create(cred
);
1123 /* ensure that the UID matches the persona ID */
1124 my_cred
= kauth_cred_setresuid(my_cred
, persona
->pna_id
,
1125 persona
->pna_id
, persona
->pna_id
,
1128 /* TODO: clear the saved GID?! */
1130 /* replace the persona's cred with the new one */
1131 if (persona
->pna_cred
) {
1132 kauth_cred_unref(&persona
->pna_cred
);
1134 persona
->pna_cred
= my_cred
;
1137 persona_unlock(persona
);
1142 persona_set_cred_from_proc(struct persona
*persona
, proc_t proc
)
1145 kauth_cred_t parent_cred
, my_cred
;
1146 if (!persona
|| !proc
) {
1150 persona_lock(persona
);
1151 if (!persona_initialized(persona
)) {
1155 if (persona
->pna_cred_locked
) {
1160 parent_cred
= kauth_cred_proc_ref(proc
);
1162 /* TODO: clear the saved UID/GID! */
1164 /* create a new cred from the proc's cred */
1165 my_cred
= kauth_cred_create(parent_cred
);
1167 /* ensure that the UID matches the persona ID */
1168 my_cred
= kauth_cred_setresuid(my_cred
, persona
->pna_id
,
1169 persona
->pna_id
, persona
->pna_id
,
1172 /* replace the persona's cred with the new one */
1173 if (persona
->pna_cred
) {
1174 kauth_cred_unref(&persona
->pna_cred
);
1176 persona
->pna_cred
= my_cred
;
1178 kauth_cred_unref(&parent_cred
);
1181 persona_unlock(persona
);
1186 persona_get_cred(struct persona
*persona
)
1188 kauth_cred_t cred
= NULL
;
1194 persona_lock(persona
);
1195 if (!persona_valid(persona
)) {
1199 if (persona
->pna_cred
) {
1200 kauth_cred_ref(persona
->pna_cred
);
1201 cred
= persona
->pna_cred
;
1205 persona_unlock(persona
);
1211 persona_get_uid(struct persona
*persona
)
1213 uid_t uid
= UID_MAX
;
1215 if (!persona
|| !persona
->pna_cred
) {
1219 persona_lock(persona
);
1220 if (persona_valid(persona
)) {
1221 uid
= kauth_cred_getuid(persona
->pna_cred
);
1222 assert(uid
== persona
->pna_id
);
1224 persona_unlock(persona
);
1230 persona_set_gid(struct persona
*persona
, gid_t gid
)
1233 kauth_cred_t my_cred
, new_cred
;
1235 if (!persona
|| !persona
->pna_cred
) {
1239 persona_lock(persona
);
1240 if (!persona_initialized(persona
)) {
1244 if (persona
->pna_cred_locked
) {
1249 my_cred
= persona
->pna_cred
;
1250 kauth_cred_ref(my_cred
);
1251 new_cred
= kauth_cred_setresgid(my_cred
, gid
, gid
, gid
);
1252 if (new_cred
!= my_cred
) {
1253 persona
->pna_cred
= new_cred
;
1255 kauth_cred_unref(&my_cred
);
1258 persona_unlock(persona
);
1263 persona_get_gid(struct persona
*persona
)
1265 gid_t gid
= GID_MAX
;
1267 if (!persona
|| !persona
->pna_cred
) {
1271 persona_lock(persona
);
1272 if (persona_valid(persona
)) {
1273 gid
= kauth_cred_getgid(persona
->pna_cred
);
1275 persona_unlock(persona
);
1281 persona_set_groups(struct persona
*persona
, gid_t
*groups
, size_t ngroups
, uid_t gmuid
)
1284 kauth_cred_t my_cred
, new_cred
;
1286 if (!persona
|| !persona
->pna_cred
) {
1289 if (ngroups
> NGROUPS_MAX
) {
1293 persona_lock(persona
);
1294 if (!persona_initialized(persona
)) {
1298 if (persona
->pna_cred_locked
) {
1303 my_cred
= persona
->pna_cred
;
1304 kauth_cred_ref(my_cred
);
1305 new_cred
= kauth_cred_setgroups(my_cred
, groups
, ngroups
, gmuid
);
1306 if (new_cred
!= my_cred
) {
1307 persona
->pna_cred
= new_cred
;
1309 kauth_cred_unref(&my_cred
);
1312 persona_unlock(persona
);
1317 persona_get_groups(struct persona
*persona
, size_t *ngroups
, gid_t
*groups
, size_t groups_sz
)
1320 if (!persona
|| !persona
->pna_cred
|| !groups
|| !ngroups
|| groups_sz
> NGROUPS
) {
1324 *ngroups
= groups_sz
;
1326 persona_lock(persona
);
1327 if (persona_valid(persona
)) {
1328 size_t kauth_ngroups
= groups_sz
;
1329 kauth_cred_getgroups(persona
->pna_cred
, groups
, &kauth_ngroups
);
1330 *ngroups
= (uint32_t)kauth_ngroups
;
1333 persona_unlock(persona
);
1339 persona_get_gmuid(struct persona
*persona
)
1341 uid_t gmuid
= KAUTH_UID_NONE
;
1343 if (!persona
|| !persona
->pna_cred
) {
1347 persona_lock(persona
);
1348 if (!persona_valid(persona
)) {
1352 posix_cred_t pcred
= posix_cred_get(persona
->pna_cred
);
1353 gmuid
= pcred
->cr_gmuid
;
1356 persona_unlock(persona
);
1361 persona_get_login(struct persona
*persona
, char login
[MAXLOGNAME
+ 1])
1364 if (!persona
|| !persona
->pna_cred
) {
1368 persona_lock(persona
);
1369 if (!persona_valid(persona
)) {
1373 strlcpy(login
, persona
->pna_login
, MAXLOGNAME
);
1377 persona_unlock(persona
);
1381 #else /* !CONFIG_PERSONAS */
1384 * symbol exports for kext compatibility
1387 struct persona
*system_persona
= NULL
;
1388 struct persona
*proxy_system_persona
= NULL
;
1389 int unique_persona
= 0;
1392 persona_get_id(__unused
struct persona
*persona
)
1394 return PERSONA_ID_NONE
;
1398 persona_get_type(__unused
struct persona
*persona
)
1400 return PERSONA_INVALID
;
1404 persona_get_cred(__unused
struct persona
*persona
)
1410 persona_lookup(__unused uid_t id
)
1416 persona_find(__unused
const char *login
,
1418 __unused
struct persona
**persona
,
1419 __unused
size_t *plen
)
1425 persona_find_by_type(__unused
int persona_type
,
1426 __unused
struct persona
**persona
,
1427 __unused
size_t *plen
)
1433 persona_proc_get(__unused pid_t pid
)
1439 current_persona_get(void)
1445 persona_get(struct persona
*persona
)
1451 persona_put(__unused
struct persona
*persona
)