xref: /xnu-8796.121.2/bsd/kern/kern_persona.c (revision c54f35ca767986246321eb901baf8f5ff7923f6a)
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, &current_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