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