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