1 /*
2 * Copyright (c) 2015-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <sys/kernel.h>
30 #include <sys/commpage.h>
31 #include <sys/kernel_types.h>
32 #include <sys/persona.h>
33 #include <pexpert/pexpert.h>
34 #include <machine/cpu_capabilities.h>
35
36 #if CONFIG_PERSONAS
37 #include <machine/atomic.h>
38
39 #include <kern/assert.h>
40 #include <kern/simple_lock.h>
41 #include <kern/task.h>
42 #include <kern/zalloc.h>
43 #include <mach/thread_act.h>
44 #include <kern/thread.h>
45
46 #include <sys/param.h>
47 #include <sys/proc_internal.h>
48 #include <sys/kauth.h>
49 #include <sys/proc_info.h>
50 #include <sys/resourcevar.h>
51
52 #include <security/audit/audit.h>
53
54 #include <os/log.h>
55 #define pna_err(fmt, ...) \
56 os_log_error(OS_LOG_DEFAULT, "ERROR: " fmt, ## __VA_ARGS__)
57
58 #define MAX_PERSONAS 512
59
60 #define TEMP_PERSONA_ID 499
61
62 #define FIRST_PERSONA_ID 501
63 #define PERSONA_ID_STEP 10
64
65 #define PERSONA_ALLOC_TOKEN (0x7a0000ae)
66 #define PERSONA_INIT_TOKEN (0x7500005e)
67 #define PERSONA_MAGIC (0x0aa55aa0)
68 #define persona_initialized(p) ((p)->pna_valid == PERSONA_MAGIC || (p)->pna_valid == PERSONA_INIT_TOKEN)
69 #define persona_valid(p) ((p)->pna_valid == PERSONA_MAGIC)
70 #define persona_mkinvalid(p) ((p)->pna_valid = ~(PERSONA_MAGIC))
71
72 static LIST_HEAD(personalist, persona) all_personas;
73 static uint32_t g_total_personas;
74 const uint32_t g_max_personas = MAX_PERSONAS;
75
76 static uid_t g_next_persona_id;
77
78 LCK_GRP_DECLARE(persona_lck_grp, "personas");
79 LCK_MTX_DECLARE(all_personas_lock, &persona_lck_grp);
80
81 os_refgrp_decl(static, persona_refgrp, "persona", NULL);
82
83 static KALLOC_TYPE_DEFINE(persona_zone, struct persona, KT_DEFAULT);
84
85 #define lock_personas() lck_mtx_lock(&all_personas_lock)
86 #define unlock_personas() lck_mtx_unlock(&all_personas_lock)
87
88 extern void mach_kauth_cred_thread_update(void);
89
90 extern kern_return_t bank_get_bank_ledger_thread_group_and_persona(void *voucher,
91 void *bankledger, void **banktg, uint32_t *persona_id);
92 void
93 ipc_voucher_release(void *voucher);
94
95 static void
personas_bootstrap(void)96 personas_bootstrap(void)
97 {
98 struct ucred cred;
99 posix_cred_t pcred;
100
101 persona_dbg("Initializing persona subsystem");
102 LIST_INIT(&all_personas);
103 g_total_personas = 0;
104
105 g_next_persona_id = FIRST_PERSONA_ID;
106
107 /*
108 * setup the default credentials that a persona temporarily
109 * inherits (to work around kauth APIs)
110 */
111 bzero(&cred, sizeof(cred));
112 pcred = &cred.cr_posix;
113 pcred->cr_uid = pcred->cr_ruid = pcred->cr_svuid = TEMP_PERSONA_ID;
114 pcred->cr_rgid = pcred->cr_svgid = TEMP_PERSONA_ID;
115 pcred->cr_groups[0] = TEMP_PERSONA_ID;
116 pcred->cr_ngroups = 1;
117 pcred->cr_flags = CRF_NOMEMBERD;
118 pcred->cr_gmuid = KAUTH_UID_NONE;
119
120 #if CONFIG_AUDIT
121 /* posix_cred_create() sets this value to NULL */
122 cred.cr_audit.as_aia_p = audit_default_aia_p;
123 #endif
124 }
125 STARTUP(EARLY_BOOT, STARTUP_RANK_MIDDLE, personas_bootstrap);
126
127 struct persona *
persona_alloc(uid_t id,const char * login,persona_type_t type,char * path,uid_t uid,int * error)128 persona_alloc(uid_t id, const char *login, persona_type_t type, char *path, uid_t uid, int *error)
129 {
130 struct persona *persona;
131 int err = 0;
132
133 if (!login) {
134 pna_err("Must provide a login name for a new persona!");
135 if (error) {
136 *error = EINVAL;
137 }
138 return NULL;
139 }
140
141 if (type <= PERSONA_INVALID || type > PERSONA_TYPE_MAX) {
142 pna_err("Invalid type: %d", type);
143 if (error) {
144 *error = EINVAL;
145 }
146 return NULL;
147 }
148
149 persona = zalloc_flags(persona_zone, Z_WAITOK | Z_ZERO | Z_NOFAIL);
150
151 if (os_atomic_inc(&g_total_personas, relaxed) > MAX_PERSONAS) {
152 /* too many personas! */
153 pna_err("too many active personas!");
154 err = EBUSY;
155 goto out_error;
156 }
157
158 strncpy(persona->pna_login, login, sizeof(persona->pna_login) - 1);
159 persona_dbg("Starting persona allocation for: '%s'", persona->pna_login);
160
161 LIST_INIT(&persona->pna_members);
162 lck_mtx_init(&persona->pna_lock, &persona_lck_grp, LCK_ATTR_NULL);
163 os_ref_init(&persona->pna_refcount, &persona_refgrp);
164
165 persona->pna_type = type;
166 persona->pna_id = id;
167 persona->pna_valid = PERSONA_ALLOC_TOKEN;
168 persona->pna_path = path;
169 persona->pna_uid = uid;
170
171 /*
172 * NOTE: this persona has not been fully initialized. A subsequent
173 * call to persona_init_begin() followed by persona_init_end() will make
174 * the persona visible to the rest of the system.
175 */
176 if (error) {
177 *error = 0;
178 }
179 return persona;
180
181 out_error:
182 os_atomic_dec(&g_total_personas, relaxed);
183 zfree(persona_zone, persona);
184 if (error) {
185 *error = err;
186 }
187 return NULL;
188 }
189
190 /**
191 * persona_init_begin
192 *
193 * This function begins initialization of a persona. It first acquires the
194 * global persona list lock via lock_personas(), then selects an appropriate
195 * persona ID and sets up the persona's credentials. This function *must* be
196 * followed by a call to persona_init_end() which will mark the persona
197 * structure as valid
198 *
199 * Conditions:
200 * persona has been allocated via persona_alloc()
201 * nothing locked
202 *
203 * Returns:
204 * global persona list is locked (even on error)
205 */
206 int
persona_init_begin(struct persona * persona)207 persona_init_begin(struct persona *persona)
208 {
209 struct persona *tmp;
210 int err = 0;
211 uid_t id;
212
213 if (!persona || (persona->pna_valid != PERSONA_ALLOC_TOKEN)) {
214 return EINVAL;
215 }
216
217 id = persona->pna_id;
218
219 lock_personas();
220 try_again:
221 if (id == PERSONA_ID_NONE) {
222 persona->pna_id = g_next_persona_id;
223 }
224
225 persona_dbg("Beginning Initialization of %d:%d (%s)...", id, persona->pna_id, persona->pna_login);
226
227 err = 0;
228 LIST_FOREACH(tmp, &all_personas, pna_list) {
229 persona_lock(tmp);
230 if (id == PERSONA_ID_NONE && tmp->pna_id == persona->pna_id) {
231 persona_unlock(tmp);
232 /*
233 * someone else manually claimed this ID, and we're
234 * trying to allocate an ID for the caller: try again
235 */
236 g_next_persona_id += PERSONA_ID_STEP;
237 goto try_again;
238 }
239 if (strncmp(tmp->pna_login, persona->pna_login, sizeof(tmp->pna_login)) == 0 ||
240 tmp->pna_id == persona->pna_id) {
241 persona_unlock(tmp);
242 /*
243 * Disallow use of identical login names and re-use
244 * of previously allocated persona IDs
245 */
246 err = EEXIST;
247 break;
248 }
249 persona_unlock(tmp);
250 }
251 if (err) {
252 goto out;
253 }
254
255 /* if the kernel supplied the persona ID, increment for next time */
256 if (id == PERSONA_ID_NONE) {
257 g_next_persona_id += PERSONA_ID_STEP;
258 }
259
260 persona->pna_valid = PERSONA_INIT_TOKEN;
261
262 out:
263 if (err != 0) {
264 persona_dbg("ERROR:%d while initializing %d:%d (%s)...", err, id, persona->pna_id, persona->pna_login);
265 /*
266 * mark the persona with an error so that persona_init_end()
267 * will *not* add it to the global list.
268 */
269 persona->pna_id = PERSONA_ID_NONE;
270 }
271
272 /*
273 * leave the global persona list locked: it will be
274 * unlocked in a call to persona_init_end()
275 */
276 return err;
277 }
278
279 /**
280 * persona_init_end
281 *
282 * This function finalizes the persona initialization by marking it valid and
283 * adding it to the global list of personas. After unlocking the global list,
284 * the persona will be visible to the reset of the system. The function will
285 * only mark the persona valid if the input parameter 'error' is 0.
286 *
287 * Conditions:
288 * persona is initialized via persona_init_begin()
289 * global persona list is locked via lock_personas()
290 *
291 * Returns:
292 * global persona list is unlocked
293 */
294 void
persona_init_end(struct persona * persona,int error)295 persona_init_end(struct persona *persona, int error)
296 {
297 if (persona == NULL) {
298 return;
299 }
300
301 /*
302 * If the pna_valid member is set to the INIT_TOKEN value, then it has
303 * successfully gone through persona_init_begin(), and we can mark it
304 * valid and make it visible to the rest of the system. However, if
305 * there was an error either during initialization or otherwise, we
306 * need to decrement the global count of personas because this one
307 * will be disposed-of by the callers invocation of persona_put().
308 */
309 if (error != 0 || persona->pna_valid == PERSONA_ALLOC_TOKEN) {
310 persona_dbg("ERROR:%d after initialization of %d (%s)", error, persona->pna_id, persona->pna_login);
311 /* remove this persona from the global count */
312 os_atomic_dec(&g_total_personas, relaxed);
313 } else if (error == 0 &&
314 persona->pna_valid == PERSONA_INIT_TOKEN) {
315 persona->pna_valid = PERSONA_MAGIC;
316 LIST_INSERT_HEAD(&all_personas, persona, pna_list);
317 persona_dbg("Initialization of %d (%s) Complete.", persona->pna_id, persona->pna_login);
318 }
319
320 unlock_personas();
321 }
322
323 static struct persona *
persona_get_locked(struct persona * persona)324 persona_get_locked(struct persona *persona)
325 {
326 os_ref_retain_locked(&persona->pna_refcount);
327 return persona;
328 }
329
330 struct persona *
persona_get(struct persona * persona)331 persona_get(struct persona *persona)
332 {
333 struct persona *ret;
334 if (!persona) {
335 return NULL;
336 }
337 persona_lock(persona);
338 ret = persona_get_locked(persona);
339 persona_unlock(persona);
340
341 return ret;
342 }
343
344 struct persona *
proc_persona_get(proc_t p)345 proc_persona_get(proc_t p)
346 {
347 proc_lock(p);
348 struct persona *persona = persona_get(p->p_persona);
349 proc_unlock(p);
350
351 return persona;
352 }
353
354 void
persona_put(struct persona * persona)355 persona_put(struct persona *persona)
356 {
357 int destroy = 0;
358
359 if (!persona) {
360 return;
361 }
362
363 persona_lock(persona);
364 if (os_ref_release_locked(&persona->pna_refcount) == 0) {
365 destroy = 1;
366 }
367 persona_unlock(persona);
368
369 if (!destroy) {
370 return;
371 }
372
373 persona_dbg("Destroying persona %s", persona_desc(persona, 0));
374
375 /* remove it from the global list and decrement the count */
376 lock_personas();
377 persona_lock(persona);
378 if (persona_valid(persona)) {
379 LIST_REMOVE(persona, pna_list);
380 if (os_atomic_dec_orig(&g_total_personas, relaxed) == 0) {
381 panic("persona count underflow!");
382 }
383 persona_mkinvalid(persona);
384 }
385 if (persona->pna_path != NULL) {
386 zfree(ZV_NAMEI, persona->pna_path);
387 }
388 persona_unlock(persona);
389 unlock_personas();
390
391 assert(LIST_EMPTY(&persona->pna_members));
392 memset(persona, 0, sizeof(*persona));
393 zfree(persona_zone, persona);
394 }
395
396 uid_t
persona_get_id(struct persona * persona)397 persona_get_id(struct persona *persona)
398 {
399 if (persona) {
400 return persona->pna_id;
401 }
402 return PERSONA_ID_NONE;
403 }
404
405 struct persona *
persona_lookup(uid_t id)406 persona_lookup(uid_t id)
407 {
408 struct persona *persona, *tmp;
409
410 persona = NULL;
411
412 /*
413 * simple, linear lookup for now: there shouldn't be too many
414 * of these in memory at any given time.
415 */
416 lock_personas();
417 LIST_FOREACH(tmp, &all_personas, pna_list) {
418 persona_lock(tmp);
419 if (tmp->pna_id == id && persona_valid(tmp)) {
420 persona = persona_get_locked(tmp);
421 persona_unlock(tmp);
422 break;
423 }
424 persona_unlock(tmp);
425 }
426 unlock_personas();
427
428 return persona;
429 }
430
431 struct persona *
persona_lookup_and_invalidate(uid_t id)432 persona_lookup_and_invalidate(uid_t id)
433 {
434 struct persona *persona, *entry, *tmp;
435
436 persona = NULL;
437
438 lock_personas();
439 LIST_FOREACH_SAFE(entry, &all_personas, pna_list, tmp) {
440 persona_lock(entry);
441 if (entry->pna_id == id) {
442 if (persona_valid(entry)) {
443 persona = persona_get_locked(entry);
444 assert(persona != NULL);
445 LIST_REMOVE(persona, pna_list);
446 if (os_atomic_dec_orig(&g_total_personas, relaxed) == 0) {
447 panic("persona ref count underflow!");
448 }
449 persona_mkinvalid(persona);
450 }
451 persona_unlock(entry);
452 break;
453 }
454 persona_unlock(entry);
455 }
456 unlock_personas();
457
458 return persona;
459 }
460
461 int
persona_find_by_type(persona_type_t persona_type,struct persona ** persona,size_t * plen)462 persona_find_by_type(persona_type_t persona_type, struct persona **persona, size_t *plen)
463 {
464 return persona_find_all(NULL, PERSONA_ID_NONE, persona_type, persona, plen);
465 }
466
467 int
persona_find(const char * login,uid_t uid,struct persona ** persona,size_t * plen)468 persona_find(const char *login, uid_t uid,
469 struct persona **persona, size_t *plen)
470 {
471 return persona_find_all(login, uid, PERSONA_INVALID, persona, plen);
472 }
473
474 int
persona_find_all(const char * login,uid_t uid,persona_type_t persona_type,struct persona ** persona,size_t * plen)475 persona_find_all(const char *login, uid_t uid, persona_type_t persona_type,
476 struct persona **persona, size_t *plen)
477 {
478 struct persona *tmp;
479 int match = 0;
480 size_t found = 0;
481
482 if (login) {
483 match++;
484 }
485 if (uid != PERSONA_ID_NONE) {
486 match++;
487 }
488 if ((persona_type > PERSONA_INVALID) && (persona_type <= PERSONA_TYPE_MAX)) {
489 match++;
490 } else if (persona_type != PERSONA_INVALID) {
491 return EINVAL;
492 }
493
494 if (match == 0) {
495 return EINVAL;
496 }
497
498 persona_dbg("Searching with %d parameters (l:\"%s\", u:%d)",
499 match, login, uid);
500
501 lock_personas();
502 LIST_FOREACH(tmp, &all_personas, pna_list) {
503 int m = 0;
504 persona_lock(tmp);
505 if (login && strncmp(tmp->pna_login, login, sizeof(tmp->pna_login)) == 0) {
506 m++;
507 }
508 if (uid != PERSONA_ID_NONE && uid == tmp->pna_id) {
509 m++;
510 }
511 if (persona_type != PERSONA_INVALID && persona_type == tmp->pna_type) {
512 m++;
513 }
514 if (m == match) {
515 if (persona && *plen > found) {
516 persona[found] = persona_get_locked(tmp);
517 }
518 found++;
519 }
520 #ifdef PERSONA_DEBUG
521 if (m > 0) {
522 persona_dbg("ID:%d Matched %d/%d, found:%d, *plen:%d",
523 tmp->pna_id, m, match, (int)found, (int)*plen);
524 }
525 #endif
526 persona_unlock(tmp);
527 }
528 unlock_personas();
529
530 *plen = found;
531 if (!found) {
532 return ESRCH;
533 }
534 return 0;
535 }
536
537 struct persona *
persona_proc_get(pid_t pid)538 persona_proc_get(pid_t pid)
539 {
540 proc_t p = proc_find(pid);
541 if (!p) {
542 return NULL;
543 }
544
545 struct persona *persona = proc_persona_get(p);
546
547 proc_rele(p);
548
549 return persona;
550 }
551
552 uid_t
current_persona_get_id(void)553 current_persona_get_id(void)
554 {
555 uid_t current_persona_id = PERSONA_ID_NONE;
556 ipc_voucher_t voucher;
557
558 thread_get_mach_voucher(current_thread(), 0, &voucher);
559 /* returns a voucher ref */
560 if (voucher != IPC_VOUCHER_NULL) {
561 /*
562 * If the voucher doesn't contain a bank attribute, it uses
563 * the default bank task value to determine the persona id
564 * which is the same as the proc's persona id
565 */
566 bank_get_bank_ledger_thread_group_and_persona(voucher, NULL,
567 NULL, ¤t_persona_id);
568 ipc_voucher_release(voucher);
569 } else {
570 /* Fallback - get the proc's persona */
571 current_persona_id = proc_persona_id(current_proc());
572 }
573 return current_persona_id;
574 }
575
576 struct persona *
current_persona_get(void)577 current_persona_get(void)
578 {
579 struct persona *persona = NULL;
580 uid_t current_persona_id = PERSONA_ID_NONE;
581
582 current_persona_id = current_persona_get_id();
583 persona = persona_lookup(current_persona_id);
584 return persona;
585 }
586
587 /**
588 * inherit a persona from parent to child
589 */
590 int
persona_proc_inherit(proc_t child,proc_t parent)591 persona_proc_inherit(proc_t child, proc_t parent)
592 {
593 if (child->p_persona != NULL) {
594 persona_dbg("proc_inherit: child already in persona: %s",
595 persona_desc(child->p_persona, 0));
596 return -1;
597 }
598
599 /* no persona to inherit */
600 if (parent->p_persona == NULL) {
601 return 0;
602 }
603
604 return persona_proc_adopt(child, parent->p_persona, proc_ucred(parent));
605 }
606
607 typedef enum e_persona_reset_op {
608 PROC_REMOVE_PERSONA = 1,
609 PROC_RESET_OLD_PERSONA = 2,
610 } persona_reset_op_t;
611
612 /*
613 * internal cleanup routine for proc_set_cred_internal
614 *
615 */
616 static struct persona *
proc_reset_persona_internal(proc_t p,persona_reset_op_t op,struct persona * old_persona,struct persona * new_persona)617 proc_reset_persona_internal(proc_t p, persona_reset_op_t op,
618 struct persona *old_persona,
619 struct persona *new_persona)
620 {
621 #if (DEVELOPMENT || DEBUG)
622 persona_lock_assert_held(new_persona);
623 #endif
624
625 switch (op) {
626 case PROC_REMOVE_PERSONA:
627 old_persona = p->p_persona;
628 OS_FALLTHROUGH;
629 case PROC_RESET_OLD_PERSONA:
630 break;
631 default:
632 /* invalid arguments */
633 return NULL;
634 }
635
636 /* unlock the new persona (locked on entry) */
637 persona_unlock(new_persona);
638 /* lock the old persona and the process */
639 assert(old_persona != NULL);
640 persona_lock(old_persona);
641 proc_lock(p);
642
643 switch (op) {
644 case PROC_REMOVE_PERSONA:
645 LIST_REMOVE(p, p_persona_list);
646 p->p_persona = NULL;
647 break;
648 case PROC_RESET_OLD_PERSONA:
649 p->p_persona = old_persona;
650 LIST_INSERT_HEAD(&old_persona->pna_members, p, p_persona_list);
651 break;
652 }
653
654 proc_unlock(p);
655 persona_unlock(old_persona);
656
657 /* re-lock the new persona */
658 persona_lock(new_persona);
659 return old_persona;
660 }
661
662 /*
663 * Assumes persona is locked.
664 * On success, takes a reference to 'persona' and returns the
665 * previous persona the process had adopted. The caller is
666 * responsible to release the reference.
667 */
668 static struct persona *
proc_set_cred_internal(proc_t p,struct persona * persona,kauth_cred_t auth_override,int * rlim_error)669 proc_set_cred_internal(proc_t p, struct persona *persona,
670 kauth_cred_t auth_override, int *rlim_error)
671 {
672 assert(auth_override != NULL);
673
674 struct persona *old_persona = NULL;
675 kauth_cred_t new_cred;
676 uid_t new_uid;
677 uid_t new_cred_uid;
678 size_t count;
679 rlim_t nproc = proc_limitgetcur(p, RLIMIT_NPROC);
680 bool changed;
681 __block uid_t old_uid;
682
683 /*
684 * This operation must be done under the proc trans lock
685 * by the thread which took the trans lock!
686 */
687 assert(((p->p_lflag & P_LINTRANSIT) == P_LINTRANSIT) &&
688 p->p_transholder == current_thread());
689 assert(persona != NULL);
690
691 /* no work to do if we "re-adopt" the same persona */
692 if (p->p_persona == persona) {
693 return NULL;
694 }
695
696 /*
697 * If p is in a persona, then we need to remove 'p' from the list of
698 * processes in that persona. To do this, we need to drop the lock
699 * held on the incoming (new) persona and lock the old one.
700 */
701 if (p->p_persona) {
702 old_persona = proc_reset_persona_internal(p, PROC_REMOVE_PERSONA,
703 NULL, persona);
704 }
705
706 /*
707 * Check to see if we will hit a proc rlimit by moving the process
708 * into the persona. If so, we'll bail early before actually moving
709 * the process or changing its credentials.
710 */
711 new_uid = persona->pna_id;
712
713 if (new_uid != 0 &&
714 (rlim_t)chgproccnt(new_uid, 0) > nproc) {
715 pna_err("PID:%d hit proc rlimit in new persona(%d): %s",
716 proc_getpid(p), new_uid, persona_desc(persona, 1));
717
718 *rlim_error = EACCES;
719
720 if (old_persona) {
721 (void)proc_reset_persona_internal(p, PROC_RESET_OLD_PERSONA,
722 old_persona, persona);
723 }
724
725 return NULL;
726 }
727
728 *rlim_error = 0;
729
730 /*
731 * Select the appropriate credentials.
732 */
733 new_cred = auth_override;
734 new_cred_uid = kauth_cred_getuid(new_cred);
735
736 /*
737 * Set the new credentials on the proc
738 */
739 changed = proc_update_label(p, true, ^(kauth_cred_t cur_cred) {
740 old_uid = kauth_cred_getruid(cur_cred);
741
742 if (new_cred != cur_cred) {
743 kauth_cred_ref(new_cred);
744 kauth_cred_unref(&cur_cred);
745 }
746
747 return new_cred;
748 });
749
750 if (changed) {
751 /*
752 * Make sure current_thread()'s cred is updated now.
753 */
754 mach_kauth_cred_thread_update();
755 }
756
757 /*
758 * Update the proc count.
759 * If the UIDs are the same, then there is no work to do.
760 */
761 if (old_persona) {
762 old_uid = old_persona->pna_id;
763 }
764
765 if (new_uid != old_uid) {
766 count = chgproccnt(old_uid, -1);
767 persona_dbg("Decrement %s:%d proc_count to: %lu",
768 old_persona ? "Persona" : "UID", old_uid, count);
769
770 /*
771 * Increment the proc count on the UID associated with
772 * the new persona. Enforce the resource limit just
773 * as in fork1()
774 */
775 count = chgproccnt(new_uid, 1);
776 persona_dbg("Increment Persona:%d (UID:%d) proc_count to: %lu",
777 new_uid, new_cred_uid, count);
778 }
779
780 OSBitOrAtomic(P_ADOPTPERSONA, &p->p_flag);
781
782 proc_lock(p);
783 p->p_persona = persona_get_locked(persona);
784 LIST_INSERT_HEAD(&persona->pna_members, p, p_persona_list);
785 proc_unlock(p);
786
787 return old_persona;
788 }
789
790 int
persona_proc_adopt(proc_t p,struct persona * persona,kauth_cred_t auth_override)791 persona_proc_adopt(proc_t p, struct persona *persona, kauth_cred_t auth_override)
792 {
793 int error;
794 struct persona *old_persona;
795
796 if (!persona) {
797 return EINVAL;
798 }
799
800 persona_dbg("%d adopting Persona %d (%s)", proc_pid(p),
801 persona->pna_id, persona_desc(persona, 0));
802
803 persona_lock(persona);
804 if (!persona_valid(persona)) {
805 persona_dbg("Invalid persona (%s)!", persona_desc(persona, 1));
806 persona_unlock(persona);
807 return EINVAL;
808 }
809
810 /*
811 * assume the persona: this may drop and re-acquire the persona lock!
812 */
813 error = 0;
814 old_persona = proc_set_cred_internal(p, persona, auth_override, &error);
815
816 /* Only Multiuser Mode needs to update the session login name to the persona name */
817 #if XNU_TARGET_OS_IOS
818 uint32_t multiuser_flags = COMM_PAGE_READ(uint32_t, MULTIUSER_CONFIG);
819 /* set the login name of the session */
820 if (multiuser_flags & kIsMultiUserDevice) {
821 struct pgrp *pg;
822 struct session *sessp;
823
824 if ((pg = proc_pgrp(p, &sessp)) != PGRP_NULL) {
825 session_lock(sessp);
826 bcopy(persona->pna_login, sessp->s_login, MAXLOGNAME);
827 session_unlock(sessp);
828 pgrp_rele(pg);
829 }
830 }
831 #endif
832 persona_unlock(persona);
833
834 set_security_token(p);
835
836 /*
837 * Drop the reference to the old persona.
838 */
839 if (old_persona) {
840 persona_put(old_persona);
841 }
842
843 persona_dbg("%s", error == 0 ? "SUCCESS" : "FAILED");
844 return error;
845 }
846
847 int
persona_proc_drop(proc_t p)848 persona_proc_drop(proc_t p)
849 {
850 struct persona *persona = NULL;
851
852 persona_dbg("PID:%d, %s -> <none>", proc_getpid(p), persona_desc(p->p_persona, 0));
853
854 /*
855 * There are really no other credentials for us to assume,
856 * so we'll just continue running with the credentials
857 * we got from the persona.
858 */
859
860 /*
861 * the locks must be taken in reverse order here, so
862 * we have to be careful not to cause deadlock
863 */
864 try_again:
865 proc_lock(p);
866 if (p->p_persona) {
867 uid_t puid, ruid;
868 if (!persona_try_lock(p->p_persona)) {
869 proc_unlock(p);
870 mutex_pause(0); /* back-off time */
871 goto try_again;
872 }
873 persona = p->p_persona;
874 LIST_REMOVE(p, p_persona_list);
875 p->p_persona = NULL;
876
877 ruid = kauth_cred_getruid(proc_ucred(p));
878 puid = persona->pna_id;
879 proc_unlock(p);
880 (void)chgproccnt(ruid, 1);
881 (void)chgproccnt(puid, -1);
882 } else {
883 proc_unlock(p);
884 }
885
886 /*
887 * if the proc had a persona, then it is still locked here
888 * (preserving proper lock ordering)
889 */
890
891 if (persona) {
892 persona_unlock(persona);
893 persona_put(persona);
894 }
895
896 return 0;
897 }
898
899 int
persona_get_type(struct persona * persona)900 persona_get_type(struct persona *persona)
901 {
902 int type;
903
904 if (!persona) {
905 return PERSONA_INVALID;
906 }
907
908 persona_lock(persona);
909 if (!persona_valid(persona)) {
910 persona_unlock(persona);
911 return PERSONA_INVALID;
912 }
913 type = persona->pna_type;
914 persona_unlock(persona);
915
916 return type;
917 }
918
919 uid_t
persona_get_uid(struct persona * persona)920 persona_get_uid(struct persona *persona)
921 {
922 uid_t uid = KAUTH_UID_NONE;
923
924 if (!persona) {
925 return KAUTH_UID_NONE;
926 }
927
928 persona_lock(persona);
929 if (persona_valid(persona)) {
930 uid = persona->pna_uid;
931 }
932 persona_unlock(persona);
933
934 return uid;
935 }
936
937 boolean_t
persona_is_adoption_allowed(struct persona * persona)938 persona_is_adoption_allowed(struct persona *persona)
939 {
940 if (!persona) {
941 return FALSE;
942 }
943 int type = persona->pna_type;
944 return type == PERSONA_SYSTEM || type == PERSONA_SYSTEM_PROXY;
945 }
946
947 #else /* !CONFIG_PERSONAS */
948
949 /*
950 * symbol exports for kext compatibility
951 */
952
953 uid_t
persona_get_id(__unused struct persona * persona)954 persona_get_id(__unused struct persona *persona)
955 {
956 return PERSONA_ID_NONE;
957 }
958
959 uid_t
persona_get_uid(__unused struct persona * persona)960 persona_get_uid(__unused struct persona *persona)
961 {
962 return KAUTH_UID_NONE;
963 }
964
965 int
persona_get_type(__unused struct persona * persona)966 persona_get_type(__unused struct persona *persona)
967 {
968 return PERSONA_INVALID;
969 }
970
971 struct persona *
persona_lookup(__unused uid_t id)972 persona_lookup(__unused uid_t id)
973 {
974 return NULL;
975 }
976
977 int
persona_find(__unused const char * login,__unused uid_t uid,__unused struct persona ** persona,__unused size_t * plen)978 persona_find(__unused const char *login,
979 __unused uid_t uid,
980 __unused struct persona **persona,
981 __unused size_t *plen)
982 {
983 return ENOTSUP;
984 }
985
986 int
persona_find_by_type(__unused int persona_type,__unused struct persona ** persona,__unused size_t * plen)987 persona_find_by_type(__unused int persona_type,
988 __unused struct persona **persona,
989 __unused size_t *plen)
990 {
991 return ENOTSUP;
992 }
993
994 struct persona *
persona_proc_get(__unused pid_t pid)995 persona_proc_get(__unused pid_t pid)
996 {
997 return NULL;
998 }
999
1000 uid_t
current_persona_get_id(void)1001 current_persona_get_id(void)
1002 {
1003 return PERSONA_ID_NONE;
1004 }
1005
1006 struct persona *
current_persona_get(void)1007 current_persona_get(void)
1008 {
1009 return NULL;
1010 }
1011
1012 struct persona *
persona_get(struct persona * persona)1013 persona_get(struct persona *persona)
1014 {
1015 return persona;
1016 }
1017
1018 struct persona *
proc_persona_get(__unused proc_t p)1019 proc_persona_get(__unused proc_t p)
1020 {
1021 return NULL;
1022 }
1023
1024 void
persona_put(__unused struct persona * persona)1025 persona_put(__unused struct persona *persona)
1026 {
1027 return;
1028 }
1029
1030 boolean_t
persona_is_adoption_allowed(__unused struct persona * persona)1031 persona_is_adoption_allowed(__unused struct persona *persona)
1032 {
1033 return FALSE;
1034 }
1035 #endif
1036