xref: /xnu-8020.101.4/bsd/kern/kern_persona.c (revision e7776783b89a353188416a9a346c6cdb4928faad)
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 struct persona *system_persona = NULL;
76 struct persona *proxy_system_persona = NULL;
77 TUNABLE(bool, unique_persona, "unique_persona", true);
78 
79 static uid_t g_next_persona_id;
80 
81 LCK_GRP_DECLARE(persona_lck_grp, "personas");
82 LCK_MTX_DECLARE(all_personas_lock, &persona_lck_grp);
83 
84 os_refgrp_decl(static, persona_refgrp, "persona", NULL);
85 
86 static ZONE_DEFINE_TYPE(persona_zone, "personas", struct persona, ZC_ZFREE_CLEARMEM);
87 
88 static SECURITY_READ_ONLY_LATE(kauth_cred_t) g_default_persona_cred;
89 
90 #define lock_personas()    lck_mtx_lock(&all_personas_lock)
91 #define unlock_personas()  lck_mtx_unlock(&all_personas_lock)
92 
93 extern void mach_kauth_cred_thread_update(void);
94 
95 extern kern_return_t bank_get_bank_ledger_thread_group_and_persona(void *voucher,
96     void *bankledger, void **banktg, uint32_t *persona_id);
97 void
98 ipc_voucher_release(void *voucher);
99 
100 static void
personas_bootstrap(void)101 personas_bootstrap(void)
102 {
103 	struct ucred cred;
104 	posix_cred_t pcred;
105 
106 	persona_dbg("Initializing persona subsystem");
107 	LIST_INIT(&all_personas);
108 	g_total_personas = 0;
109 
110 	g_next_persona_id = FIRST_PERSONA_ID;
111 
112 	/*
113 	 * setup the default credentials that a persona temporarily
114 	 * inherits (to work around kauth APIs)
115 	 */
116 	bzero(&cred, sizeof(cred));
117 	pcred = &cred.cr_posix;
118 	pcred->cr_uid = pcred->cr_ruid = pcred->cr_svuid = TEMP_PERSONA_ID;
119 	pcred->cr_rgid = pcred->cr_svgid = TEMP_PERSONA_ID;
120 	pcred->cr_groups[0] = TEMP_PERSONA_ID;
121 	pcred->cr_ngroups = 1;
122 	pcred->cr_flags = CRF_NOMEMBERD;
123 	pcred->cr_gmuid = KAUTH_UID_NONE;
124 
125 #if CONFIG_AUDIT
126 	/* posix_cred_create() sets this value to NULL */
127 	cred.cr_audit.as_aia_p = audit_default_aia_p;
128 #endif
129 
130 	g_default_persona_cred = kauth_cred_create(&cred);
131 }
132 STARTUP(EARLY_BOOT, STARTUP_RANK_MIDDLE, personas_bootstrap);
133 
134 struct persona *
persona_alloc(uid_t id,const char * login,persona_type_t type,char * path,int * error)135 persona_alloc(uid_t id, const char *login, persona_type_t type, char *path, int *error)
136 {
137 	struct persona *persona;
138 	struct ucred persona_cred_model;
139 	kauth_cred_t cred;
140 	int err = 0;
141 
142 	if (!login) {
143 		pna_err("Must provide a login name for a new persona!");
144 		if (error) {
145 			*error = EINVAL;
146 		}
147 		return NULL;
148 	}
149 
150 	if (type <= PERSONA_INVALID || type > PERSONA_TYPE_MAX) {
151 		pna_err("Invalid type: %d", type);
152 		if (error) {
153 			*error = EINVAL;
154 		}
155 		return NULL;
156 	}
157 
158 	persona = zalloc_flags(persona_zone, Z_WAITOK | Z_ZERO | Z_NOFAIL);
159 
160 	if (os_atomic_inc(&g_total_personas, relaxed) > MAX_PERSONAS) {
161 		/* too many personas! */
162 		pna_err("too many active personas!");
163 		err = EBUSY;
164 		goto out_error;
165 	}
166 
167 	strncpy(persona->pna_login, login, sizeof(persona->pna_login) - 1);
168 	persona_dbg("Starting persona allocation for: '%s'", persona->pna_login);
169 
170 	LIST_INIT(&persona->pna_members);
171 	lck_mtx_init(&persona->pna_lock, &persona_lck_grp, LCK_ATTR_NULL);
172 	os_ref_init(&persona->pna_refcount, &persona_refgrp);
173 
174 	/*
175 	 * Setup initial (temporary) kauth_cred structure
176 	 * We need to do this here because all kauth calls require
177 	 * an existing cred structure.
178 	 */
179 	persona_cred_model = *g_default_persona_cred;
180 	cred = kauth_cred_create(&persona_cred_model);
181 
182 	kauth_cred_set_and_unref(&persona->pna_cred, &cred);
183 
184 	persona->pna_type = type;
185 	persona->pna_id = id;
186 	persona->pna_valid = PERSONA_ALLOC_TOKEN;
187 	persona->pna_path = path;
188 
189 	/*
190 	 * NOTE: this persona has not been fully initialized. A subsequent
191 	 * call to persona_init_begin() followed by persona_init_end() will make
192 	 * the persona visible to the rest of the system.
193 	 */
194 	if (error) {
195 		*error = 0;
196 	}
197 	return persona;
198 
199 out_error:
200 	os_atomic_dec(&g_total_personas, relaxed);
201 	zfree(persona_zone, persona);
202 	if (error) {
203 		*error = err;
204 	}
205 	return NULL;
206 }
207 
208 /**
209  * persona_init_begin
210  *
211  * This function begins initialization of a persona. It first acquires the
212  * global persona list lock via lock_personas(), then selects an appropriate
213  * persona ID and sets up the persona's credentials. This function *must* be
214  * followed by a call to persona_init_end() which will mark the persona
215  * structure as valid
216  *
217  * Conditions:
218  *      persona has been allocated via persona_alloc()
219  *      nothing locked
220  *
221  * Returns:
222  *      global persona list is locked (even on error)
223  */
224 int
persona_init_begin(struct persona * persona)225 persona_init_begin(struct persona *persona)
226 {
227 	struct persona *tmp;
228 	int err = 0;
229 	kauth_cred_t tmp_cred;
230 	gid_t new_group;
231 	uid_t id;
232 
233 	if (!persona || (persona->pna_valid != PERSONA_ALLOC_TOKEN)) {
234 		return EINVAL;
235 	}
236 
237 	id = persona->pna_id;
238 
239 	lock_personas();
240 try_again:
241 	if (id == PERSONA_ID_NONE) {
242 		persona->pna_id = g_next_persona_id;
243 	}
244 
245 	persona_dbg("Beginning Initialization of %d:%d (%s)...", id, persona->pna_id, persona->pna_login);
246 
247 	err = 0;
248 	LIST_FOREACH(tmp, &all_personas, pna_list) {
249 		persona_lock(tmp);
250 		if (id == PERSONA_ID_NONE && tmp->pna_id == persona->pna_id) {
251 			persona_unlock(tmp);
252 			/*
253 			 * someone else manually claimed this ID, and we're
254 			 * trying to allocate an ID for the caller: try again
255 			 */
256 			g_next_persona_id += PERSONA_ID_STEP;
257 			goto try_again;
258 		}
259 		if (strncmp(tmp->pna_login, persona->pna_login, sizeof(tmp->pna_login)) == 0 ||
260 		    tmp->pna_id == persona->pna_id) {
261 			persona_unlock(tmp);
262 			/*
263 			 * Disallow use of identical login names and re-use
264 			 * of previously allocated persona IDs
265 			 */
266 			err = EEXIST;
267 			break;
268 		}
269 		persona_unlock(tmp);
270 	}
271 	if (err) {
272 		goto out;
273 	}
274 
275 	/* ensure the cred has proper UID/GID defaults */
276 	kauth_cred_ref(persona->pna_cred);
277 	tmp_cred = kauth_cred_setuidgid(persona->pna_cred,
278 	    persona->pna_id,
279 	    persona->pna_id);
280 	kauth_cred_set_and_unref(&persona->pna_cred, &tmp_cred);
281 
282 	if (!persona->pna_cred) {
283 		err = EACCES;
284 		goto out;
285 	}
286 
287 	/* it should be a member of exactly 1 group (equal to its UID) */
288 	new_group = (gid_t)persona->pna_id;
289 
290 	/* opt _out_ of memberd as a default */
291 	kauth_cred_ref(persona->pna_cred);
292 	tmp_cred = kauth_cred_setgroups(persona->pna_cred,
293 	    &new_group, 1, KAUTH_UID_NONE);
294 	kauth_cred_set_and_unref(&persona->pna_cred, &tmp_cred);
295 
296 	if (!persona->pna_cred) {
297 		err = EACCES;
298 		goto out;
299 	}
300 
301 	/* if the kernel supplied the persona ID, increment for next time */
302 	if (id == PERSONA_ID_NONE) {
303 		g_next_persona_id += PERSONA_ID_STEP;
304 	}
305 
306 	persona->pna_valid = PERSONA_INIT_TOKEN;
307 
308 out:
309 	if (err != 0) {
310 		persona_dbg("ERROR:%d while initializing %d:%d (%s)...", err, id, persona->pna_id, persona->pna_login);
311 		/*
312 		 * mark the persona with an error so that persona_init_end()
313 		 * will *not* add it to the global list.
314 		 */
315 		persona->pna_id = PERSONA_ID_NONE;
316 	}
317 
318 	/*
319 	 * leave the global persona list locked: it will be
320 	 * unlocked in a call to persona_init_end()
321 	 */
322 	return err;
323 }
324 
325 /**
326  * persona_init_end
327  *
328  * This function finalizes the persona initialization by marking it valid and
329  * adding it to the global list of personas. After unlocking the global list,
330  * the persona will be visible to the reset of the system. The function will
331  * only mark the persona valid if the input parameter 'error' is 0.
332  *
333  * Conditions:
334  *      persona is initialized via persona_init_begin()
335  *      global persona list is locked via lock_personas()
336  *
337  * Returns:
338  *      global persona list is unlocked
339  */
340 void
persona_init_end(struct persona * persona,int error)341 persona_init_end(struct persona *persona, int error)
342 {
343 	if (persona == NULL) {
344 		return;
345 	}
346 
347 	/*
348 	 * If the pna_valid member is set to the INIT_TOKEN value, then it has
349 	 * successfully gone through persona_init_begin(), and we can mark it
350 	 * valid and make it visible to the rest of the system. However, if
351 	 * there was an error either during initialization or otherwise, we
352 	 * need to decrement the global count of personas because this one
353 	 * will be disposed-of by the callers invocation of persona_put().
354 	 */
355 	if (error != 0 || persona->pna_valid == PERSONA_ALLOC_TOKEN) {
356 		persona_dbg("ERROR:%d after initialization of %d (%s)", error, persona->pna_id, persona->pna_login);
357 		/* remove this persona from the global count */
358 		os_atomic_dec(&g_total_personas, relaxed);
359 	} else if (error == 0 &&
360 	    persona->pna_valid == PERSONA_INIT_TOKEN) {
361 		persona->pna_valid = PERSONA_MAGIC;
362 		LIST_INSERT_HEAD(&all_personas, persona, pna_list);
363 		persona_dbg("Initialization of %d (%s) Complete.", persona->pna_id, persona->pna_login);
364 	}
365 
366 	unlock_personas();
367 }
368 
369 /**
370  * persona_verify_and_set_uniqueness
371  *
372  * This function checks the persona, if the one being spawned is of type
373  * PERSONA_SYSTEM or PERSONA_SYSTEM_PROXY, is unique.
374  *
375  * Conditions:
376  *      global persona list is locked on entry and return.
377  *
378  * Returns:
379  *      EEXIST: if persona is system/system-proxy and is not unique.
380  *      0: Otherwise.
381  */
382 int
persona_verify_and_set_uniqueness(struct persona * persona)383 persona_verify_and_set_uniqueness(struct persona *persona)
384 {
385 	if (persona == NULL) {
386 		return EINVAL;
387 	}
388 
389 	if (!unique_persona) {
390 		return 0;
391 	}
392 
393 	if (persona->pna_type == PERSONA_SYSTEM) {
394 		if (system_persona != NULL) {
395 			return EEXIST;
396 		}
397 		system_persona = persona;
398 		return 0;
399 	}
400 
401 	if (persona->pna_type == PERSONA_SYSTEM_PROXY) {
402 		if (proxy_system_persona != NULL) {
403 			return EEXIST;
404 		}
405 		proxy_system_persona = persona;
406 		return 0;
407 	}
408 	return 0;
409 }
410 
411 /**
412  * persona_is_unique
413  *
414  * This function checks if the persona spawned is unique.
415  *
416  * Returns:
417  *      TRUE: if unique.
418  *      FALSE: otherwise.
419  */
420 boolean_t
persona_is_unique(struct persona * persona)421 persona_is_unique(struct persona *persona)
422 {
423 	if (persona == NULL) {
424 		return FALSE;
425 	}
426 
427 	if (!unique_persona) {
428 		return FALSE;
429 	}
430 
431 	if (persona->pna_type == PERSONA_SYSTEM ||
432 	    persona->pna_type == PERSONA_SYSTEM_PROXY) {
433 		return TRUE;
434 	}
435 
436 	return FALSE;
437 }
438 
439 static struct persona *
persona_get_locked(struct persona * persona)440 persona_get_locked(struct persona *persona)
441 {
442 	os_ref_retain_locked(&persona->pna_refcount);
443 	return persona;
444 }
445 
446 struct persona *
persona_get(struct persona * persona)447 persona_get(struct persona *persona)
448 {
449 	struct persona *ret;
450 	if (!persona) {
451 		return NULL;
452 	}
453 	persona_lock(persona);
454 	ret = persona_get_locked(persona);
455 	persona_unlock(persona);
456 
457 	return ret;
458 }
459 
460 void
persona_put(struct persona * persona)461 persona_put(struct persona *persona)
462 {
463 	int destroy = 0;
464 
465 	if (!persona) {
466 		return;
467 	}
468 
469 	persona_lock(persona);
470 	if (os_ref_release_locked(&persona->pna_refcount) == 0) {
471 		destroy = 1;
472 	}
473 	persona_unlock(persona);
474 
475 	if (!destroy) {
476 		return;
477 	}
478 
479 	persona_dbg("Destroying persona %s", persona_desc(persona, 0));
480 
481 	/* release our credential reference */
482 	kauth_cred_set(&persona->pna_cred, NOCRED);
483 
484 	/* remove it from the global list and decrement the count */
485 	lock_personas();
486 	persona_lock(persona);
487 	if (persona_valid(persona)) {
488 		LIST_REMOVE(persona, pna_list);
489 		if (os_atomic_dec_orig(&g_total_personas, relaxed) == 0) {
490 			panic("persona count underflow!");
491 		}
492 		persona_mkinvalid(persona);
493 	}
494 	if (persona->pna_path != NULL) {
495 		zfree(ZV_NAMEI, persona->pna_path);
496 	}
497 	persona_unlock(persona);
498 	unlock_personas();
499 
500 	assert(LIST_EMPTY(&persona->pna_members));
501 	memset(persona, 0, sizeof(*persona));
502 	zfree(persona_zone, persona);
503 }
504 
505 uid_t
persona_get_id(struct persona * persona)506 persona_get_id(struct persona *persona)
507 {
508 	if (persona) {
509 		return persona->pna_id;
510 	}
511 	return PERSONA_ID_NONE;
512 }
513 
514 struct persona *
persona_lookup(uid_t id)515 persona_lookup(uid_t id)
516 {
517 	struct persona *persona, *tmp;
518 
519 	persona = NULL;
520 
521 	/*
522 	 * simple, linear lookup for now: there shouldn't be too many
523 	 * of these in memory at any given time.
524 	 */
525 	lock_personas();
526 	LIST_FOREACH(tmp, &all_personas, pna_list) {
527 		persona_lock(tmp);
528 		if (tmp->pna_id == id && persona_valid(tmp)) {
529 			persona = persona_get_locked(tmp);
530 			persona_unlock(tmp);
531 			break;
532 		}
533 		persona_unlock(tmp);
534 	}
535 	unlock_personas();
536 
537 	return persona;
538 }
539 
540 struct persona *
persona_lookup_and_invalidate(uid_t id)541 persona_lookup_and_invalidate(uid_t id)
542 {
543 	struct persona *persona, *entry, *tmp;
544 
545 	persona = NULL;
546 
547 	lock_personas();
548 	LIST_FOREACH_SAFE(entry, &all_personas, pna_list, tmp) {
549 		persona_lock(entry);
550 		if (entry->pna_id == id) {
551 			if (persona_valid(entry) && !persona_is_unique(entry)) {
552 				persona = persona_get_locked(entry);
553 				assert(persona != NULL);
554 				LIST_REMOVE(persona, pna_list);
555 				if (os_atomic_dec_orig(&g_total_personas, relaxed) == 0) {
556 					panic("persona ref count underflow!");
557 				}
558 				persona_mkinvalid(persona);
559 			}
560 			persona_unlock(entry);
561 			break;
562 		}
563 		persona_unlock(entry);
564 	}
565 	unlock_personas();
566 
567 	return persona;
568 }
569 
570 int
persona_find_by_type(persona_type_t persona_type,struct persona ** persona,size_t * plen)571 persona_find_by_type(persona_type_t persona_type, struct persona **persona, size_t *plen)
572 {
573 	return persona_find_all(NULL, PERSONA_ID_NONE, persona_type, persona, plen);
574 }
575 
576 int
persona_find(const char * login,uid_t uid,struct persona ** persona,size_t * plen)577 persona_find(const char *login, uid_t uid,
578     struct persona **persona, size_t *plen)
579 {
580 	return persona_find_all(login, uid, PERSONA_INVALID, persona, plen);
581 }
582 
583 int
persona_find_all(const char * login,uid_t uid,persona_type_t persona_type,struct persona ** persona,size_t * plen)584 persona_find_all(const char *login, uid_t uid, persona_type_t persona_type,
585     struct persona **persona, size_t *plen)
586 {
587 	struct persona *tmp;
588 	int match = 0;
589 	size_t found = 0;
590 
591 	if (login) {
592 		match++;
593 	}
594 	if (uid != PERSONA_ID_NONE) {
595 		match++;
596 	}
597 	if ((persona_type > PERSONA_INVALID) && (persona_type <= PERSONA_TYPE_MAX)) {
598 		match++;
599 	} else if (persona_type != PERSONA_INVALID) {
600 		return EINVAL;
601 	}
602 
603 	if (match == 0) {
604 		return EINVAL;
605 	}
606 
607 	persona_dbg("Searching with %d parameters (l:\"%s\", u:%d)",
608 	    match, login, uid);
609 
610 	lock_personas();
611 	LIST_FOREACH(tmp, &all_personas, pna_list) {
612 		int m = 0;
613 		persona_lock(tmp);
614 		if (login && strncmp(tmp->pna_login, login, sizeof(tmp->pna_login)) == 0) {
615 			m++;
616 		}
617 		if (uid != PERSONA_ID_NONE && uid == tmp->pna_id) {
618 			m++;
619 		}
620 		if (persona_type != PERSONA_INVALID && persona_type == tmp->pna_type) {
621 			m++;
622 		}
623 		if (m == match) {
624 			if (persona && *plen > found) {
625 				persona[found] = persona_get_locked(tmp);
626 			}
627 			found++;
628 		}
629 #ifdef PERSONA_DEBUG
630 		if (m > 0) {
631 			persona_dbg("ID:%d Matched %d/%d, found:%d, *plen:%d",
632 			    tmp->pna_id, m, match, (int)found, (int)*plen);
633 		}
634 #endif
635 		persona_unlock(tmp);
636 	}
637 	unlock_personas();
638 
639 	*plen = found;
640 	if (!found) {
641 		return ESRCH;
642 	}
643 	return 0;
644 }
645 
646 struct persona *
persona_proc_get(pid_t pid)647 persona_proc_get(pid_t pid)
648 {
649 	struct persona *persona;
650 	proc_t p = proc_find(pid);
651 
652 	if (!p) {
653 		return NULL;
654 	}
655 
656 	proc_lock(p);
657 	persona = persona_get(p->p_persona);
658 	proc_unlock(p);
659 
660 	proc_rele(p);
661 
662 	return persona;
663 }
664 
665 uid_t
current_persona_get_id(void)666 current_persona_get_id(void)
667 {
668 	uid_t current_persona_id = PERSONA_ID_NONE;
669 	ipc_voucher_t voucher;
670 
671 	thread_get_mach_voucher(current_thread(), 0, &voucher);
672 	/* returns a voucher ref */
673 	if (voucher != IPC_VOUCHER_NULL) {
674 		/*
675 		 * If the voucher doesn't contain a bank attribute, it uses
676 		 * the default bank task value to determine the persona id
677 		 * which is the same as the proc's persona id
678 		 */
679 		bank_get_bank_ledger_thread_group_and_persona(voucher, NULL,
680 		    NULL, &current_persona_id);
681 		ipc_voucher_release(voucher);
682 	} else {
683 		/* Fallback - get the proc's persona */
684 		current_persona_id = proc_persona_id(current_proc());
685 	}
686 	return current_persona_id;
687 }
688 
689 struct persona *
current_persona_get(void)690 current_persona_get(void)
691 {
692 	struct persona *persona = NULL;
693 	uid_t current_persona_id = PERSONA_ID_NONE;
694 
695 	current_persona_id = current_persona_get_id();
696 	persona = persona_lookup(current_persona_id);
697 	return persona;
698 }
699 
700 /**
701  * inherit a persona from parent to child
702  */
703 int
persona_proc_inherit(proc_t child,proc_t parent)704 persona_proc_inherit(proc_t child, proc_t parent)
705 {
706 	if (child->p_persona != NULL) {
707 		persona_dbg("proc_inherit: child already in persona: %s",
708 		    persona_desc(child->p_persona, 0));
709 		return -1;
710 	}
711 
712 	/* no persona to inherit */
713 	if (parent->p_persona == NULL) {
714 		return 0;
715 	}
716 
717 	return persona_proc_adopt(child, parent->p_persona, proc_ucred(parent));
718 }
719 
720 int
persona_proc_adopt_id(proc_t p,uid_t id,kauth_cred_t auth_override)721 persona_proc_adopt_id(proc_t p, uid_t id, kauth_cred_t auth_override)
722 {
723 	int ret;
724 	struct persona *persona;
725 
726 	persona = persona_lookup(id);
727 	if (!persona) {
728 		return ESRCH;
729 	}
730 
731 	ret = persona_proc_adopt(p, persona, auth_override);
732 
733 	/* put the reference from the lookup() */
734 	persona_put(persona);
735 
736 	return ret;
737 }
738 
739 
740 typedef enum e_persona_reset_op {
741 	PROC_REMOVE_PERSONA = 1,
742 	PROC_RESET_OLD_PERSONA = 2,
743 } persona_reset_op_t;
744 
745 /*
746  * internal cleanup routine for proc_set_cred_internal
747  *
748  */
749 static struct persona *
proc_reset_persona_internal(proc_t p,persona_reset_op_t op,struct persona * old_persona,struct persona * new_persona)750 proc_reset_persona_internal(proc_t p, persona_reset_op_t op,
751     struct persona *old_persona,
752     struct persona *new_persona)
753 {
754 #if (DEVELOPMENT || DEBUG)
755 	persona_lock_assert_held(new_persona);
756 #endif
757 
758 	switch (op) {
759 	case PROC_REMOVE_PERSONA:
760 		old_persona = p->p_persona;
761 		OS_FALLTHROUGH;
762 	case PROC_RESET_OLD_PERSONA:
763 		break;
764 	default:
765 		/* invalid arguments */
766 		return NULL;
767 	}
768 
769 	/* unlock the new persona (locked on entry) */
770 	persona_unlock(new_persona);
771 	/* lock the old persona and the process */
772 	assert(old_persona != NULL);
773 	persona_lock(old_persona);
774 	proc_lock(p);
775 
776 	switch (op) {
777 	case PROC_REMOVE_PERSONA:
778 		LIST_REMOVE(p, p_persona_list);
779 		p->p_persona = NULL;
780 		break;
781 	case PROC_RESET_OLD_PERSONA:
782 		p->p_persona = old_persona;
783 		LIST_INSERT_HEAD(&old_persona->pna_members, p, p_persona_list);
784 		break;
785 	}
786 
787 	proc_unlock(p);
788 	persona_unlock(old_persona);
789 
790 	/* re-lock the new persona */
791 	persona_lock(new_persona);
792 	return old_persona;
793 }
794 
795 /*
796  * Assumes persona is locked.
797  * On success, takes a reference to 'persona' and returns the
798  * previous persona the process had adopted. The caller is
799  * responsible to release the reference.
800  */
801 static struct persona *
proc_set_cred_internal(proc_t p,struct persona * persona,kauth_cred_t auth_override,int * rlim_error)802 proc_set_cred_internal(proc_t p, struct persona *persona,
803     kauth_cred_t auth_override, int *rlim_error)
804 {
805 	struct persona *old_persona = NULL;
806 	kauth_cred_t new_cred;
807 	uid_t new_uid;
808 	uid_t new_cred_uid;
809 	size_t count;
810 	rlim_t nproc = proc_limitgetcur(p, RLIMIT_NPROC);
811 	bool changed;
812 	__block uid_t old_uid;
813 
814 	/*
815 	 * This operation must be done under the proc trans lock
816 	 * by the thread which took the trans lock!
817 	 */
818 	assert(((p->p_lflag & P_LINTRANSIT) == P_LINTRANSIT) &&
819 	    p->p_transholder == current_thread());
820 	assert(persona != NULL);
821 
822 	/* no work to do if we "re-adopt" the same persona */
823 	if (p->p_persona == persona) {
824 		return NULL;
825 	}
826 
827 	/*
828 	 * If p is in a persona, then we need to remove 'p' from the list of
829 	 * processes in that persona. To do this, we need to drop the lock
830 	 * held on the incoming (new) persona and lock the old one.
831 	 */
832 	if (p->p_persona) {
833 		old_persona = proc_reset_persona_internal(p, PROC_REMOVE_PERSONA,
834 		    NULL, persona);
835 	}
836 
837 	/*
838 	 * Check to see if we will hit a proc rlimit by moving the process
839 	 * into the persona. If so, we'll bail early before actually moving
840 	 * the process or changing its credentials.
841 	 */
842 	new_uid = persona->pna_id;
843 
844 	if (new_uid != 0 &&
845 	    (rlim_t)chgproccnt(new_uid, 0) > nproc) {
846 		pna_err("PID:%d hit proc rlimit in new persona(%d): %s",
847 		    proc_getpid(p), new_uid, persona_desc(persona, 1));
848 
849 		*rlim_error = EACCES;
850 
851 		if (old_persona) {
852 			(void)proc_reset_persona_internal(p, PROC_RESET_OLD_PERSONA,
853 			    old_persona, persona);
854 		}
855 
856 		return NULL;
857 	}
858 
859 	*rlim_error = 0;
860 
861 	/*
862 	 * Select the appropriate credentials.
863 	 */
864 	new_cred = auth_override ?: persona->pna_cred;
865 	if (!new_cred) {
866 		panic("NULL credentials (persona:%p)", persona);
867 	}
868 
869 	new_cred_uid = kauth_cred_getuid(new_cred);
870 
871 	/*
872 	 * Set the new credentials on the proc
873 	 */
874 	changed = proc_update_label(p, true, ^(kauth_cred_t cur_cred) {
875 		old_uid = kauth_cred_getruid(cur_cred);
876 
877 		if (new_cred != cur_cred) {
878 		        kauth_cred_ref(new_cred);
879 		        kauth_cred_unref(&cur_cred);
880 		}
881 
882 		return new_cred;
883 	});
884 
885 	if (changed) {
886 		/*
887 		 * Make sure current_thread()'s cred is updated now.
888 		 */
889 		mach_kauth_cred_thread_update();
890 	}
891 
892 	/*
893 	 * Update the proc count.
894 	 * If the UIDs are the same, then there is no work to do.
895 	 */
896 	if (old_persona) {
897 		old_uid = old_persona->pna_id;
898 	}
899 
900 	if (new_uid != old_uid) {
901 		count = chgproccnt(old_uid, -1);
902 		persona_dbg("Decrement %s:%d proc_count to: %lu",
903 		    old_persona ? "Persona" : "UID", old_uid, count);
904 
905 		/*
906 		 * Increment the proc count on the UID associated with
907 		 * the new persona. Enforce the resource limit just
908 		 * as in fork1()
909 		 */
910 		count = chgproccnt(new_uid, 1);
911 		persona_dbg("Increment Persona:%d (UID:%d) proc_count to: %lu",
912 		    new_uid, new_cred_uid, count);
913 	}
914 
915 	OSBitOrAtomic(P_ADOPTPERSONA, &p->p_flag);
916 
917 	proc_lock(p);
918 	p->p_persona = persona_get_locked(persona);
919 	LIST_INSERT_HEAD(&persona->pna_members, p, p_persona_list);
920 	proc_unlock(p);
921 
922 	return old_persona;
923 }
924 
925 int
persona_proc_adopt(proc_t p,struct persona * persona,kauth_cred_t auth_override)926 persona_proc_adopt(proc_t p, struct persona *persona, kauth_cred_t auth_override)
927 {
928 	int error;
929 	struct persona *old_persona;
930 
931 	if (!persona) {
932 		return EINVAL;
933 	}
934 
935 	persona_dbg("%d adopting Persona %d (%s)", proc_pid(p),
936 	    persona->pna_id, persona_desc(persona, 0));
937 
938 	persona_lock(persona);
939 	if (!persona->pna_cred || !persona_valid(persona)) {
940 		persona_dbg("Invalid persona (%s): NULL credentials!", persona_desc(persona, 1));
941 		persona_unlock(persona);
942 		return EINVAL;
943 	}
944 
945 	/* the persona credentials can no longer be adjusted */
946 	persona->pna_cred_locked = 1;
947 
948 	/*
949 	 * assume the persona: this may drop and re-acquire the persona lock!
950 	 */
951 	error = 0;
952 	old_persona = proc_set_cred_internal(p, persona, auth_override, &error);
953 
954 	/* join the process group associated with the persona */
955 	if (persona->pna_pgid) {
956 		uid_t uid = kauth_cred_getuid(persona->pna_cred);
957 		persona_dbg(" PID:%d, pgid:%d%s",
958 		    proc_getpid(p), persona->pna_pgid,
959 		    persona->pna_pgid == uid ? ", new_session" : ".");
960 		enterpgrp(p, persona->pna_pgid, persona->pna_pgid == uid);
961 	}
962 
963 	/* Only Multiuser Mode needs to update the session login name to the persona name */
964 #if XNU_TARGET_OS_IOS
965 	uint32_t multiuser_flags = COMM_PAGE_READ(uint32_t, MULTIUSER_CONFIG);
966 	/* set the login name of the session */
967 	if (multiuser_flags) {
968 		struct pgrp *pg;
969 		struct session *sessp;
970 
971 		if ((pg = proc_pgrp(p, &sessp)) != PGRP_NULL) {
972 			session_lock(sessp);
973 			bcopy(persona->pna_login, sessp->s_login, MAXLOGNAME);
974 			session_unlock(sessp);
975 			pgrp_rele(pg);
976 		}
977 	}
978 #endif
979 	persona_unlock(persona);
980 
981 	set_security_token(p);
982 
983 	/*
984 	 * Drop the reference to the old persona.
985 	 */
986 	if (old_persona) {
987 		persona_put(old_persona);
988 	}
989 
990 	persona_dbg("%s", error == 0 ? "SUCCESS" : "FAILED");
991 	return error;
992 }
993 
994 int
persona_proc_drop(proc_t p)995 persona_proc_drop(proc_t p)
996 {
997 	struct persona *persona = NULL;
998 
999 	persona_dbg("PID:%d, %s -> <none>", proc_getpid(p), persona_desc(p->p_persona, 0));
1000 
1001 	/*
1002 	 * There are really no other credentials for us to assume,
1003 	 * so we'll just continue running with the credentials
1004 	 * we got from the persona.
1005 	 */
1006 
1007 	/*
1008 	 * the locks must be taken in reverse order here, so
1009 	 * we have to be careful not to cause deadlock
1010 	 */
1011 try_again:
1012 	proc_lock(p);
1013 	if (p->p_persona) {
1014 		uid_t puid, ruid;
1015 		if (!persona_try_lock(p->p_persona)) {
1016 			proc_unlock(p);
1017 			mutex_pause(0); /* back-off time */
1018 			goto try_again;
1019 		}
1020 		persona = p->p_persona;
1021 		LIST_REMOVE(p, p_persona_list);
1022 		p->p_persona = NULL;
1023 
1024 		ruid = kauth_cred_getruid(proc_ucred(p));
1025 		puid = kauth_cred_getuid(persona->pna_cred);
1026 		proc_unlock(p);
1027 		(void)chgproccnt(ruid, 1);
1028 		(void)chgproccnt(puid, -1);
1029 	} else {
1030 		proc_unlock(p);
1031 	}
1032 
1033 	/*
1034 	 * if the proc had a persona, then it is still locked here
1035 	 * (preserving proper lock ordering)
1036 	 */
1037 
1038 	if (persona) {
1039 		persona_unlock(persona);
1040 		persona_put(persona);
1041 	}
1042 
1043 	return 0;
1044 }
1045 
1046 int
persona_get_type(struct persona * persona)1047 persona_get_type(struct persona *persona)
1048 {
1049 	int type;
1050 
1051 	if (!persona) {
1052 		return PERSONA_INVALID;
1053 	}
1054 
1055 	persona_lock(persona);
1056 	if (!persona_valid(persona)) {
1057 		persona_unlock(persona);
1058 		return PERSONA_INVALID;
1059 	}
1060 	type = persona->pna_type;
1061 	persona_unlock(persona);
1062 
1063 	return type;
1064 }
1065 
1066 int
persona_set_cred(struct persona * persona,kauth_cred_t cred)1067 persona_set_cred(struct persona *persona, kauth_cred_t cred)
1068 {
1069 	int ret = 0;
1070 	kauth_cred_t my_cred;
1071 	struct ucred model_cred;
1072 
1073 	if (!persona || !cred) {
1074 		return EINVAL;
1075 	}
1076 
1077 	persona_lock(persona);
1078 	if (!persona_initialized(persona)) {
1079 		ret = EINVAL;
1080 		goto out_unlock;
1081 	}
1082 	if (persona->pna_cred_locked) {
1083 		ret = EPERM;
1084 		goto out_unlock;
1085 	}
1086 
1087 	/* create a new cred from the passed-in cred */
1088 	model_cred = *cred;
1089 	my_cred = kauth_cred_create(&model_cred);
1090 
1091 	/* ensure that the UID matches the persona ID */
1092 	my_cred = kauth_cred_setresuid(my_cred, persona->pna_id,
1093 	    persona->pna_id, persona->pna_id,
1094 	    KAUTH_UID_NONE);
1095 
1096 	/* TODO: clear the saved GID?! */
1097 
1098 	/* replace the persona's cred with the new one */
1099 	kauth_cred_set_and_unref(&persona->pna_cred, &my_cred);
1100 
1101 out_unlock:
1102 	persona_unlock(persona);
1103 	return ret;
1104 }
1105 
1106 int
persona_set_cred_from_proc(struct persona * persona,proc_t proc)1107 persona_set_cred_from_proc(struct persona *persona, proc_t proc)
1108 {
1109 	int ret = 0;
1110 	kauth_cred_t parent_cred, my_cred;
1111 	struct ucred model_cred;
1112 
1113 	if (!persona || !proc) {
1114 		return EINVAL;
1115 	}
1116 
1117 	persona_lock(persona);
1118 	if (!persona_initialized(persona)) {
1119 		ret = EINVAL;
1120 		goto out_unlock;
1121 	}
1122 	if (persona->pna_cred_locked) {
1123 		ret = EPERM;
1124 		goto out_unlock;
1125 	}
1126 
1127 	parent_cred = kauth_cred_proc_ref(proc);
1128 
1129 	/* TODO: clear the saved UID/GID! */
1130 
1131 	/* create a new cred from the proc's cred */
1132 	model_cred = *parent_cred;
1133 	my_cred = kauth_cred_create(&model_cred);
1134 	kauth_cred_unref(&parent_cred);
1135 
1136 	/* ensure that the UID matches the persona ID */
1137 	my_cred = kauth_cred_setresuid(my_cred, persona->pna_id,
1138 	    persona->pna_id, persona->pna_id,
1139 	    KAUTH_UID_NONE);
1140 
1141 	/* replace the persona's cred with the new one */
1142 	kauth_cred_set_and_unref(&persona->pna_cred, &my_cred);
1143 
1144 out_unlock:
1145 	persona_unlock(persona);
1146 	return ret;
1147 }
1148 
1149 kauth_cred_t
persona_get_cred(struct persona * persona)1150 persona_get_cred(struct persona *persona)
1151 {
1152 	kauth_cred_t cred = NULL;
1153 
1154 	if (!persona) {
1155 		return NULL;
1156 	}
1157 
1158 	persona_lock(persona);
1159 	if (!persona_valid(persona)) {
1160 		goto out_unlock;
1161 	}
1162 
1163 	if (persona->pna_cred) {
1164 		kauth_cred_ref(persona->pna_cred);
1165 		cred = persona->pna_cred;
1166 	}
1167 
1168 out_unlock:
1169 	persona_unlock(persona);
1170 
1171 	return cred;
1172 }
1173 
1174 uid_t
persona_get_uid(struct persona * persona)1175 persona_get_uid(struct persona *persona)
1176 {
1177 	uid_t uid = UID_MAX;
1178 
1179 	if (!persona || !persona->pna_cred) {
1180 		return UID_MAX;
1181 	}
1182 
1183 	persona_lock(persona);
1184 	if (persona_valid(persona)) {
1185 		uid = kauth_cred_getuid(persona->pna_cred);
1186 		assert(uid == persona->pna_id);
1187 	}
1188 	persona_unlock(persona);
1189 
1190 	return uid;
1191 }
1192 
1193 int
persona_set_gid(struct persona * persona,gid_t gid)1194 persona_set_gid(struct persona *persona, gid_t gid)
1195 {
1196 	int ret = 0;
1197 	kauth_cred_t cred;
1198 
1199 	if (!persona || !persona->pna_cred) {
1200 		return EINVAL;
1201 	}
1202 
1203 	persona_lock(persona);
1204 	if (!persona_initialized(persona)) {
1205 		ret = EINVAL;
1206 		goto out_unlock;
1207 	}
1208 	if (persona->pna_cred_locked) {
1209 		ret = EPERM;
1210 		goto out_unlock;
1211 	}
1212 
1213 	cred = persona->pna_cred;
1214 	kauth_cred_ref(cred);
1215 	cred = kauth_cred_setresgid(cred, gid, gid, gid);
1216 	kauth_cred_set_and_unref(&persona->pna_cred, &cred);
1217 
1218 out_unlock:
1219 	persona_unlock(persona);
1220 	return ret;
1221 }
1222 
1223 gid_t
persona_get_gid(struct persona * persona)1224 persona_get_gid(struct persona *persona)
1225 {
1226 	gid_t gid = GID_MAX;
1227 
1228 	if (!persona || !persona->pna_cred) {
1229 		return GID_MAX;
1230 	}
1231 
1232 	persona_lock(persona);
1233 	if (persona_valid(persona)) {
1234 		gid = kauth_cred_getgid(persona->pna_cred);
1235 	}
1236 	persona_unlock(persona);
1237 
1238 	return gid;
1239 }
1240 
1241 int
persona_set_groups(struct persona * persona,gid_t * groups,size_t ngroups,uid_t gmuid)1242 persona_set_groups(struct persona *persona, gid_t *groups, size_t ngroups, uid_t gmuid)
1243 {
1244 	int ret = 0;
1245 	kauth_cred_t cred;
1246 
1247 	if (!persona || !persona->pna_cred) {
1248 		return EINVAL;
1249 	}
1250 	if (ngroups > NGROUPS_MAX) {
1251 		return EINVAL;
1252 	}
1253 
1254 	persona_lock(persona);
1255 	if (!persona_initialized(persona)) {
1256 		ret = EINVAL;
1257 		goto out_unlock;
1258 	}
1259 	if (persona->pna_cred_locked) {
1260 		ret = EPERM;
1261 		goto out_unlock;
1262 	}
1263 
1264 	cred = persona->pna_cred;
1265 	kauth_cred_ref(cred);
1266 	cred = kauth_cred_setgroups(cred, groups, ngroups, gmuid);
1267 	kauth_cred_set_and_unref(&persona->pna_cred, &cred);
1268 
1269 out_unlock:
1270 	persona_unlock(persona);
1271 	return ret;
1272 }
1273 
1274 int
persona_get_groups(struct persona * persona,size_t * ngroups,gid_t * groups,size_t groups_sz)1275 persona_get_groups(struct persona *persona, size_t *ngroups, gid_t *groups, size_t groups_sz)
1276 {
1277 	int ret = EINVAL;
1278 	if (!persona || !persona->pna_cred || !groups || !ngroups || groups_sz > NGROUPS) {
1279 		return EINVAL;
1280 	}
1281 
1282 	*ngroups = groups_sz;
1283 
1284 	persona_lock(persona);
1285 	if (persona_valid(persona)) {
1286 		size_t kauth_ngroups = groups_sz;
1287 		kauth_cred_getgroups(persona->pna_cred, groups, &kauth_ngroups);
1288 		*ngroups = (uint32_t)kauth_ngroups;
1289 		ret = 0;
1290 	}
1291 	persona_unlock(persona);
1292 
1293 	return ret;
1294 }
1295 
1296 uid_t
persona_get_gmuid(struct persona * persona)1297 persona_get_gmuid(struct persona *persona)
1298 {
1299 	uid_t gmuid = KAUTH_UID_NONE;
1300 
1301 	if (!persona || !persona->pna_cred) {
1302 		return gmuid;
1303 	}
1304 
1305 	persona_lock(persona);
1306 	if (!persona_valid(persona)) {
1307 		goto out_unlock;
1308 	}
1309 
1310 	posix_cred_t pcred = posix_cred_get(persona->pna_cred);
1311 	gmuid = pcred->cr_gmuid;
1312 
1313 out_unlock:
1314 	persona_unlock(persona);
1315 	return gmuid;
1316 }
1317 
1318 int
persona_get_login(struct persona * persona,char login[MAXLOGNAME+1])1319 persona_get_login(struct persona *persona, char login[MAXLOGNAME + 1])
1320 {
1321 	int ret = EINVAL;
1322 	if (!persona || !persona->pna_cred) {
1323 		return EINVAL;
1324 	}
1325 
1326 	persona_lock(persona);
1327 	if (!persona_valid(persona)) {
1328 		goto out_unlock;
1329 	}
1330 
1331 	strlcpy(login, persona->pna_login, MAXLOGNAME);
1332 	ret = 0;
1333 
1334 out_unlock:
1335 	persona_unlock(persona);
1336 	return ret;
1337 }
1338 
1339 #else /* !CONFIG_PERSONAS */
1340 
1341 /*
1342  * symbol exports for kext compatibility
1343  */
1344 
1345 struct persona *system_persona = NULL;
1346 struct persona *proxy_system_persona = NULL;
1347 int unique_persona = 0;
1348 
1349 uid_t
persona_get_id(__unused struct persona * persona)1350 persona_get_id(__unused struct persona *persona)
1351 {
1352 	return PERSONA_ID_NONE;
1353 }
1354 
1355 int
persona_get_type(__unused struct persona * persona)1356 persona_get_type(__unused struct persona *persona)
1357 {
1358 	return PERSONA_INVALID;
1359 }
1360 
1361 kauth_cred_t
persona_get_cred(__unused struct persona * persona)1362 persona_get_cred(__unused struct persona *persona)
1363 {
1364 	return NULL;
1365 }
1366 
1367 struct persona *
persona_lookup(__unused uid_t id)1368 persona_lookup(__unused uid_t id)
1369 {
1370 	return NULL;
1371 }
1372 
1373 int
persona_find(__unused const char * login,__unused uid_t uid,__unused struct persona ** persona,__unused size_t * plen)1374 persona_find(__unused const char *login,
1375     __unused uid_t uid,
1376     __unused struct persona **persona,
1377     __unused size_t *plen)
1378 {
1379 	return ENOTSUP;
1380 }
1381 
1382 int
persona_find_by_type(__unused int persona_type,__unused struct persona ** persona,__unused size_t * plen)1383 persona_find_by_type(__unused int persona_type,
1384     __unused struct persona **persona,
1385     __unused size_t *plen)
1386 {
1387 	return ENOTSUP;
1388 }
1389 
1390 struct persona *
persona_proc_get(__unused pid_t pid)1391 persona_proc_get(__unused pid_t pid)
1392 {
1393 	return NULL;
1394 }
1395 
1396 uid_t
current_persona_get_id(void)1397 current_persona_get_id(void)
1398 {
1399 	return PERSONA_ID_NONE;
1400 }
1401 
1402 struct persona *
current_persona_get(void)1403 current_persona_get(void)
1404 {
1405 	return NULL;
1406 }
1407 
1408 struct persona *
persona_get(struct persona * persona)1409 persona_get(struct persona *persona)
1410 {
1411 	return persona;
1412 }
1413 
1414 void
persona_put(__unused struct persona * persona)1415 persona_put(__unused struct persona *persona)
1416 {
1417 	return;
1418 }
1419 #endif
1420