]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_prot.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / kern / kern_prot.c
1 /*
2 * Copyright (c) 2000-2008 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 * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
30 *
31 *
32 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
33 * The Regents of the University of California. All rights reserved.
34 * (c) UNIX System Laboratories, Inc.
35 * All or some portions of this file are derived from material licensed
36 * to the University of California by American Telephone and Telegraph
37 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
38 * the permission of UNIX System Laboratories, Inc.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 * This product includes software developed by the University of
51 * California, Berkeley and its contributors.
52 * 4. Neither the name of the University nor the names of its contributors
53 * may be used to endorse or promote products derived from this software
54 * without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 *
68 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
69 *
70 *
71 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
72 * support for mandatory and extensible security protections. This notice
73 * is included in support of clause 2.2 (b) of the Apple Public License,
74 * Version 2.0.
75 *
76 *
77 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
78 * support for mandatory and extensible security protections. This notice
79 * is included in support of clause 2.2 (b) of the Apple Public License,
80 * Version 2.0.
81 *
82 */
83
84 /*
85 * System calls related to processes and protection
86 */
87
88 #include <sys/param.h>
89 #include <sys/acct.h>
90 #include <sys/systm.h>
91 #include <sys/ucred.h>
92 #include <sys/proc_internal.h>
93 #include <sys/user.h>
94 #include <sys/kauth.h>
95 #include <sys/timeb.h>
96 #include <sys/times.h>
97 #include <sys/malloc.h>
98 #include <sys/persona.h>
99
100 #include <security/audit/audit.h>
101
102 #if CONFIG_MACF
103 #include <security/mac_framework.h>
104 #endif
105
106 #include <sys/mount_internal.h>
107 #include <sys/sysproto.h>
108 #include <mach/message.h>
109 #include <mach/host_security.h>
110
111 #include <kern/host.h>
112 #include <kern/task.h> /* for current_task() */
113 #include <kern/assert.h>
114
115
116 /*
117 * Credential debugging; we can track entry into a function that might
118 * change a credential, and we can track actual credential changes that
119 * result.
120 *
121 * Note: Does *NOT* currently include per-thread credential changes
122 *
123 * We don't use kauth_cred_print() in current debugging, but it
124 * can be used if needed when debugging is active.
125 */
126 #if DEBUG_CRED
127 #define DEBUG_CRED_ENTER printf
128 #define DEBUG_CRED_CHANGE printf
129 extern void kauth_cred_print(kauth_cred_t cred);
130 #else /* !DEBUG_CRED */
131 #define DEBUG_CRED_ENTER(fmt, ...) do {} while (0)
132 #define DEBUG_CRED_CHANGE(fmt, ...) do {} while (0)
133 #endif /* !DEBUG_CRED */
134
135 #if DEVELOPMENT || DEBUG
136 extern void task_importance_update_owner_info(task_t);
137 #endif
138
139
140 /*
141 * setprivexec
142 *
143 * Description: (dis)allow this process to hold task, thread, or execption
144 * ports of processes about to exec.
145 *
146 * Parameters: uap->flag New value for flag
147 *
148 * Returns: int Previous value of flag
149 *
150 * XXX: Belongs in kern_proc.c
151 */
152 int
153 setprivexec(proc_t p, struct setprivexec_args *uap, int32_t *retval)
154 {
155 AUDIT_ARG(value32, uap->flag);
156 *retval = p->p_debugger;
157 p->p_debugger = (uap->flag != 0);
158 return 0;
159 }
160
161
162 /*
163 * getpid
164 *
165 * Description: get the process ID
166 *
167 * Parameters: (void)
168 *
169 * Returns: pid_t Current process ID
170 *
171 * XXX: Belongs in kern_proc.c
172 */
173 int
174 getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval)
175 {
176 *retval = p->p_pid;
177 return 0;
178 }
179
180
181 /*
182 * getppid
183 *
184 * Description: get the parent process ID
185 *
186 * Parameters: (void)
187 *
188 * Returns: pid_t Parent process ID
189 *
190 * XXX: Belongs in kern_proc.c
191 */
192 int
193 getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval)
194 {
195 *retval = p->p_ppid;
196 return 0;
197 }
198
199
200 /*
201 * getpgrp
202 *
203 * Description: get the process group ID of the calling process
204 *
205 * Parameters: (void)
206 *
207 * Returns: pid_t Process group ID
208 *
209 * XXX: Belongs in kern_proc.c
210 */
211 int
212 getpgrp(proc_t p, __unused struct getpgrp_args *uap, int32_t *retval)
213 {
214 *retval = p->p_pgrpid;
215 return 0;
216 }
217
218
219 /*
220 * getpgid
221 *
222 * Description: Get an arbitary pid's process group id
223 *
224 * Parameters: uap->pid The target pid
225 *
226 * Returns: 0 Success
227 * ESRCH No such process
228 *
229 * Notes: We are permitted to return EPERM in the case that the target
230 * process is not in the same session as the calling process,
231 * which could be a security consideration
232 *
233 * XXX: Belongs in kern_proc.c
234 */
235 int
236 getpgid(proc_t p, struct getpgid_args *uap, int32_t *retval)
237 {
238 proc_t pt;
239 int refheld = 0;
240
241 pt = p;
242 if (uap->pid == 0) {
243 goto found;
244 }
245
246 if ((pt = proc_find(uap->pid)) == 0) {
247 return ESRCH;
248 }
249 refheld = 1;
250 found:
251 *retval = pt->p_pgrpid;
252 if (refheld != 0) {
253 proc_rele(pt);
254 }
255 return 0;
256 }
257
258
259 /*
260 * getsid
261 *
262 * Description: Get an arbitary pid's session leaders process group ID
263 *
264 * Parameters: uap->pid The target pid
265 *
266 * Returns: 0 Success
267 * ESRCH No such process
268 *
269 * Notes: We are permitted to return EPERM in the case that the target
270 * process is not in the same session as the calling process,
271 * which could be a security consideration
272 *
273 * XXX: Belongs in kern_proc.c
274 */
275 int
276 getsid(proc_t p, struct getsid_args *uap, int32_t *retval)
277 {
278 proc_t pt;
279 int refheld = 0;
280 struct session * sessp;
281
282 pt = p;
283 if (uap->pid == 0) {
284 goto found;
285 }
286
287 if ((pt = proc_find(uap->pid)) == 0) {
288 return ESRCH;
289 }
290 refheld = 1;
291 found:
292 sessp = proc_session(pt);
293 *retval = sessp->s_sid;
294 session_rele(sessp);
295
296 if (refheld != 0) {
297 proc_rele(pt);
298 }
299 return 0;
300 }
301
302
303 /*
304 * getuid
305 *
306 * Description: get real user ID for caller
307 *
308 * Parameters: (void)
309 *
310 * Returns: uid_t The real uid of the caller
311 */
312 int
313 getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval)
314 {
315 *retval = kauth_getruid();
316 return 0;
317 }
318
319
320 /*
321 * geteuid
322 *
323 * Description: get effective user ID for caller
324 *
325 * Parameters: (void)
326 *
327 * Returns: uid_t The effective uid of the caller
328 */
329 int
330 geteuid(__unused proc_t p, __unused struct geteuid_args *uap, int32_t *retval)
331 {
332 *retval = kauth_getuid();
333 return 0;
334 }
335
336
337 /*
338 * gettid
339 *
340 * Description: Return the per-thread override identity.
341 *
342 * Parameters: uap->uidp Address of uid_t to get uid
343 * uap->gidp Address of gid_t to get gid
344 *
345 * Returns: 0 Success
346 * ESRCH No per thread identity active
347 */
348 int
349 gettid(__unused proc_t p, struct gettid_args *uap, int32_t *retval)
350 {
351 struct uthread *uthread = get_bsdthread_info(current_thread());
352 int error;
353
354 /*
355 * If this thread is not running with an override identity, we can't
356 * return one to the caller, so return an error instead.
357 */
358 if (!(uthread->uu_flag & UT_SETUID)) {
359 return ESRCH;
360 }
361
362 if ((error = suword(uap->uidp, kauth_cred_getruid(uthread->uu_ucred)))) {
363 return error;
364 }
365 if ((error = suword(uap->gidp, kauth_cred_getrgid(uthread->uu_ucred)))) {
366 return error;
367 }
368
369 *retval = 0;
370 return 0;
371 }
372
373
374 /*
375 * getgid
376 *
377 * Description: get the real group ID for the calling process
378 *
379 * Parameters: (void)
380 *
381 * Returns: gid_t The real gid of the caller
382 */
383 int
384 getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval)
385 {
386 *retval = kauth_getrgid();
387 return 0;
388 }
389
390
391 /*
392 * getegid
393 *
394 * Description: get the effective group ID for the calling process
395 *
396 * Parameters: (void)
397 *
398 * Returns: gid_t The effective gid of the caller
399 *
400 * Notes: As an implementation detail, the effective gid is stored as
401 * the first element of the supplementary group list.
402 *
403 * This could be implemented in Libc instead because of the above
404 * detail.
405 */
406 int
407 getegid(__unused proc_t p, __unused struct getegid_args *uap, int32_t *retval)
408 {
409 *retval = kauth_getgid();
410 return 0;
411 }
412
413
414 /*
415 * getgroups
416 *
417 * Description: get the list of supplementary groups for the calling process
418 *
419 * Parameters: uap->gidsetsize # of gid_t's in user buffer
420 * uap->gidset Pointer to user buffer
421 *
422 * Returns: 0 Success
423 * EINVAL User buffer too small
424 * copyout:EFAULT User buffer invalid
425 *
426 * Retval: -1 Error
427 * !0 # of groups
428 *
429 * Notes: The caller may specify a 0 value for gidsetsize, and we will
430 * then return how large a buffer is required (in gid_t's) to
431 * contain the answer at the time of the call. Otherwise, we
432 * return the number of gid_t's catually copied to user space.
433 *
434 * When called with a 0 gidsetsize from a multithreaded program,
435 * there is no guarantee that another thread may not change the
436 * number of supplementary groups, and therefore a subsequent
437 * call could still fail, unless the maximum possible buffer
438 * size is supplied by the user.
439 *
440 * As an implementation detail, the effective gid is stored as
441 * the first element of the supplementary group list, and will
442 * be returned by this call.
443 */
444 int
445 getgroups(__unused proc_t p, struct getgroups_args *uap, int32_t *retval)
446 {
447 int ngrp;
448 int error;
449 kauth_cred_t cred;
450 posix_cred_t pcred;
451
452 /* grab reference while we muck around with the credential */
453 cred = kauth_cred_get_with_ref();
454 pcred = posix_cred_get(cred);
455
456 if ((ngrp = uap->gidsetsize) == 0) {
457 *retval = pcred->cr_ngroups;
458 kauth_cred_unref(&cred);
459 return 0;
460 }
461 if (ngrp < pcred->cr_ngroups) {
462 kauth_cred_unref(&cred);
463 return EINVAL;
464 }
465 ngrp = pcred->cr_ngroups;
466 if ((error = copyout((caddr_t)pcred->cr_groups,
467 uap->gidset,
468 ngrp * sizeof(gid_t)))) {
469 kauth_cred_unref(&cred);
470 return error;
471 }
472 kauth_cred_unref(&cred);
473 *retval = ngrp;
474 return 0;
475 }
476
477
478 /*
479 * Return the per-thread/per-process supplementary groups list.
480 *
481 * XXX implement getsgroups
482 *
483 */
484
485 int
486 getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int32_t *retval)
487 {
488 return ENOTSUP;
489 }
490
491 /*
492 * Return the per-thread/per-process whiteout groups list.
493 *
494 * XXX implement getwgroups
495 *
496 */
497
498 int
499 getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int32_t *retval)
500 {
501 return ENOTSUP;
502 }
503
504 /*
505 * setsid_internal
506 *
507 * Description: Core implementation of setsid().
508 */
509 int
510 setsid_internal(proc_t p)
511 {
512 struct pgrp * pg = PGRP_NULL;
513
514 if (p->p_pgrpid == p->p_pid || (pg = pgfind(p->p_pid)) || p->p_lflag & P_LINVFORK) {
515 if (pg != PGRP_NULL) {
516 pg_rele(pg);
517 }
518 return EPERM;
519 } else {
520 /* enter pgrp works with its own pgrp refcount */
521 (void)enterpgrp(p, p->p_pid, 1);
522 return 0;
523 }
524 }
525
526 /*
527 * setsid
528 *
529 * Description: Create a new session and set the process group ID to the
530 * session ID
531 *
532 * Parameters: (void)
533 *
534 * Returns: 0 Success
535 * EPERM Permission denied
536 *
537 * Notes: If the calling process is not the process group leader; there
538 * is no existing process group with its ID, and we are not
539 * currently in vfork, then this function will create a new
540 * session, a new process group, and put the caller in the
541 * process group (as the sole member) and make it the session
542 * leader (as the sole process in the session).
543 *
544 * The existing controlling tty (if any) will be dissociated
545 * from the process, and the next non-O_NOCTTY open of a tty
546 * will establish a new controlling tty.
547 *
548 * XXX: Belongs in kern_proc.c
549 */
550 int
551 setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval)
552 {
553 int rc = setsid_internal(p);
554 if (rc == 0) {
555 *retval = p->p_pid;
556 }
557 return rc;
558 }
559
560
561 /*
562 * setpgid
563 *
564 * Description: set process group ID for job control
565 *
566 * Parameters: uap->pid Process to change
567 * uap->pgid Process group to join or create
568 *
569 * Returns: 0 Success
570 * ESRCH pid is not the caller or a child of
571 * the caller
572 * enterpgrp:ESRCH No such process
573 * EACCES Permission denied due to exec
574 * EINVAL Invalid argument
575 * EPERM The target process is not in the same
576 * session as the calling process
577 * EPERM The target process is a session leader
578 * EPERM pid and pgid are not the same, and
579 * there is no process in the calling
580 * process whose process group ID matches
581 * pgid
582 *
583 * Notes: This function will cause the target process to either join
584 * an existing process process group, or create a new process
585 * group in the session of the calling process. It cannot be
586 * used to change the process group ID of a process which is
587 * already a session leader.
588 *
589 * If the target pid is 0, the pid of the calling process is
590 * substituted as the new target; if pgid is 0, the target pid
591 * is used as the target process group ID.
592 *
593 * Legacy: This system call entry point is also used to implement the
594 * legacy library routine setpgrp(), which under POSIX
595 *
596 * XXX: Belongs in kern_proc.c
597 */
598 int
599 setpgid(proc_t curp, struct setpgid_args *uap, __unused int32_t *retval)
600 {
601 proc_t targp = PROC_NULL; /* target process */
602 struct pgrp *pg = PGRP_NULL; /* target pgrp */
603 int error = 0;
604 int refheld = 0;
605 int samesess = 0;
606 struct session * curp_sessp = SESSION_NULL;
607 struct session * targp_sessp = SESSION_NULL;
608
609 curp_sessp = proc_session(curp);
610
611 if (uap->pid != 0 && uap->pid != curp->p_pid) {
612 if ((targp = proc_find(uap->pid)) == 0 || !inferior(targp)) {
613 if (targp != PROC_NULL) {
614 refheld = 1;
615 }
616 error = ESRCH;
617 goto out;
618 }
619 refheld = 1;
620 targp_sessp = proc_session(targp);
621 if (targp_sessp != curp_sessp) {
622 error = EPERM;
623 goto out;
624 }
625 if (targp->p_flag & P_EXEC) {
626 error = EACCES;
627 goto out;
628 }
629 } else {
630 targp = curp;
631 targp_sessp = proc_session(targp);
632 }
633
634 if (SESS_LEADER(targp, targp_sessp)) {
635 error = EPERM;
636 goto out;
637 }
638 if (targp_sessp != SESSION_NULL) {
639 session_rele(targp_sessp);
640 targp_sessp = SESSION_NULL;
641 }
642
643 if (uap->pgid < 0) {
644 error = EINVAL;
645 goto out;
646 }
647 if (uap->pgid == 0) {
648 uap->pgid = targp->p_pid;
649 } else if (uap->pgid != targp->p_pid) {
650 if ((pg = pgfind(uap->pgid)) == 0) {
651 error = EPERM;
652 goto out;
653 }
654 samesess = (pg->pg_session != curp_sessp);
655 pg_rele(pg);
656 if (samesess != 0) {
657 error = EPERM;
658 goto out;
659 }
660 }
661 error = enterpgrp(targp, uap->pgid, 0);
662 out:
663 if (targp_sessp != SESSION_NULL) {
664 session_rele(targp_sessp);
665 }
666 if (curp_sessp != SESSION_NULL) {
667 session_rele(curp_sessp);
668 }
669 if (refheld != 0) {
670 proc_rele(targp);
671 }
672 return error;
673 }
674
675
676 /*
677 * issetugid
678 *
679 * Description: Is current process tainted by uid or gid changes system call
680 *
681 * Parameters: (void)
682 *
683 * Returns: 0 Not tainted
684 * 1 Tainted
685 *
686 * Notes: A process is considered tainted if it was created as a retult
687 * of an execve call from an imnage that had either the SUID or
688 * SGID bit set on the executable, or if it has changed any of its
689 * real, effective, or saved user or group IDs since beginning
690 * execution.
691 */
692 int
693 proc_issetugid(proc_t p)
694 {
695 return (p->p_flag & P_SUGID) ? 1 : 0;
696 }
697
698 int
699 issetugid(proc_t p, __unused struct issetugid_args *uap, int32_t *retval)
700 {
701 /*
702 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
703 * we use P_SUGID because we consider changing the owners as
704 * "tainting" as well.
705 * This is significant for procs that start as root and "become"
706 * a user without an exec - programs cannot know *everything*
707 * that libc *might* have put in their data segment.
708 */
709
710 *retval = proc_issetugid(p);
711 return 0;
712 }
713
714
715 /*
716 * setuid
717 *
718 * Description: Set user ID system call
719 *
720 * Parameters: uap->uid uid to set
721 *
722 * Returns: 0 Success
723 * suser:EPERM Permission denied
724 *
725 * Notes: If called by a privileged process, this function will set the
726 * real, effective, and saved uid to the requested value.
727 *
728 * If called from an unprivileged process, but uid is equal to the
729 * real or saved uid, then the effective uid will be set to the
730 * requested value, but the real and saved uid will not change.
731 *
732 * If the credential is changed as a result of this call, then we
733 * flag the process as having set privilege since the last exec.
734 */
735 int
736 setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval)
737 {
738 uid_t uid;
739 uid_t svuid = KAUTH_UID_NONE;
740 uid_t ruid = KAUTH_UID_NONE;
741 uid_t gmuid = KAUTH_UID_NONE;
742 int error;
743 kauth_cred_t my_cred, my_new_cred;
744 posix_cred_t my_pcred;
745
746 uid = uap->uid;
747
748 /* get current credential and take a reference while we muck with it */
749 my_cred = kauth_cred_proc_ref(p);
750 my_pcred = posix_cred_get(my_cred);
751
752 DEBUG_CRED_ENTER("setuid (%d/%d): %p %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), my_cred, uap->uid);
753 AUDIT_ARG(uid, uid);
754
755 for (;;) {
756 if (uid != my_pcred->cr_ruid && /* allow setuid(getuid()) */
757 uid != my_pcred->cr_svuid && /* allow setuid(saved uid) */
758 (error = suser(my_cred, &p->p_acflag))) {
759 kauth_cred_unref(&my_cred);
760 return error;
761 }
762
763 /*
764 * If we are privileged, then set the saved and real UID too;
765 * otherwise, just set the effective UID
766 */
767 if (suser(my_cred, &p->p_acflag) == 0) {
768 svuid = uid;
769 ruid = uid;
770 } else {
771 svuid = KAUTH_UID_NONE;
772 ruid = KAUTH_UID_NONE;
773 }
774 /*
775 * Only set the gmuid if the current cred has not opt'ed out;
776 * this normally only happens when calling setgroups() instead
777 * of initgroups() to set an explicit group list, or one of the
778 * other group manipulation functions is invoked and results in
779 * a dislocation (i.e. the credential group membership changes
780 * to something other than the default list for the user, as
781 * in entering a group or leaving an exclusion group).
782 */
783 if (!(my_pcred->cr_flags & CRF_NOMEMBERD)) {
784 gmuid = uid;
785 }
786
787 /*
788 * Set the credential with new info. If there is no change,
789 * we get back the same credential we passed in; if there is
790 * a change, we drop the reference on the credential we
791 * passed in. The subsequent compare is safe, because it is
792 * a pointer compare rather than a contents compare.
793 */
794 my_new_cred = kauth_cred_setresuid(my_cred, ruid, uid, svuid, gmuid);
795 if (my_cred != my_new_cred) {
796 DEBUG_CRED_CHANGE("setuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
797
798 /*
799 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
800 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
801 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
802 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
803 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
804 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
805 */
806 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
807 (void)chgproccnt(ruid, 1);
808 }
809
810 proc_ucred_lock(p);
811 /*
812 * We need to protect for a race where another thread
813 * also changed the credential after we took our
814 * reference. If p_ucred has changed then we should
815 * restart this again with the new cred.
816 *
817 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
818 */
819 if (p->p_ucred != my_cred) {
820 proc_ucred_unlock(p);
821 /*
822 * We didn't successfully switch to the new ruid, so decrement
823 * the procs/uid count that we incremented above.
824 */
825 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
826 (void)chgproccnt(ruid, -1);
827 }
828 kauth_cred_unref(&my_new_cred);
829 my_cred = kauth_cred_proc_ref(p);
830 my_pcred = posix_cred_get(my_cred);
831 /* try again */
832 continue;
833 }
834 p->p_ucred = my_new_cred;
835 /* update cred on proc */
836 PROC_UPDATE_CREDS_ONPROC(p);
837
838 OSBitOrAtomic(P_SUGID, &p->p_flag);
839 proc_ucred_unlock(p);
840 /*
841 * If we've updated the ruid, decrement the count of procs running
842 * under the previous ruid
843 */
844 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
845 (void)chgproccnt(my_pcred->cr_ruid, -1);
846 }
847 }
848 break;
849 }
850 /* Drop old proc reference or our extra reference */
851 kauth_cred_unref(&my_cred);
852
853 set_security_token(p);
854 return 0;
855 }
856
857
858 /*
859 * seteuid
860 *
861 * Description: Set effective user ID system call
862 *
863 * Parameters: uap->euid effective uid to set
864 *
865 * Returns: 0 Success
866 * suser:EPERM Permission denied
867 *
868 * Notes: If called by a privileged process, or called from an
869 * unprivileged process but euid is equal to the real or saved
870 * uid, then the effective uid will be set to the requested
871 * value, but the real and saved uid will not change.
872 *
873 * If the credential is changed as a result of this call, then we
874 * flag the process as having set privilege since the last exec.
875 */
876 int
877 seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval)
878 {
879 uid_t euid;
880 int error;
881 kauth_cred_t my_cred, my_new_cred;
882 posix_cred_t my_pcred;
883
884 DEBUG_CRED_ENTER("seteuid: %d\n", uap->euid);
885
886 euid = uap->euid;
887 AUDIT_ARG(euid, euid);
888
889 my_cred = kauth_cred_proc_ref(p);
890 my_pcred = posix_cred_get(my_cred);
891
892 for (;;) {
893 if (euid != my_pcred->cr_ruid && euid != my_pcred->cr_svuid &&
894 (error = suser(my_cred, &p->p_acflag))) {
895 kauth_cred_unref(&my_cred);
896 return error;
897 }
898
899 /*
900 * Set the credential with new info. If there is no change,
901 * we get back the same credential we passed in; if there is
902 * a change, we drop the reference on the credential we
903 * passed in. The subsequent compare is safe, because it is
904 * a pointer compare rather than a contents compare.
905 */
906 my_new_cred = kauth_cred_setresuid(my_cred, KAUTH_UID_NONE, euid, KAUTH_UID_NONE, my_pcred->cr_gmuid);
907
908 if (my_cred != my_new_cred) {
909 DEBUG_CRED_CHANGE("seteuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
910
911 proc_ucred_lock(p);
912 /*
913 * We need to protect for a race where another thread
914 * also changed the credential after we took our
915 * reference. If p_ucred has changed then we
916 * should restart this again with the new cred.
917 */
918 if (p->p_ucred != my_cred) {
919 proc_ucred_unlock(p);
920 kauth_cred_unref(&my_new_cred);
921 my_cred = kauth_cred_proc_ref(p);
922 my_pcred = posix_cred_get(my_cred);
923 /* try again */
924 continue;
925 }
926 p->p_ucred = my_new_cred;
927 /* update cred on proc */
928 PROC_UPDATE_CREDS_ONPROC(p);
929 OSBitOrAtomic(P_SUGID, &p->p_flag);
930 proc_ucred_unlock(p);
931 }
932 break;
933 }
934 /* drop old proc reference or our extra reference */
935 kauth_cred_unref(&my_cred);
936
937 set_security_token(p);
938 return 0;
939 }
940
941
942 /*
943 * setreuid
944 *
945 * Description: Set real and effective user ID system call
946 *
947 * Parameters: uap->ruid real uid to set
948 * uap->euid effective uid to set
949 *
950 * Returns: 0 Success
951 * suser:EPERM Permission denied
952 *
953 * Notes: A value of -1 is a special case indicating that the uid for
954 * which that value is specified not be changed. If both values
955 * are specified as -1, no action is taken.
956 *
957 * If called by a privileged process, the real and effective uid
958 * will be set to the new value(s) specified.
959 *
960 * If called from an unprivileged process, the real uid may be
961 * set to the current value of the real uid, or to the current
962 * value of the saved uid. The effective uid may be set to the
963 * current value of any of the effective, real, or saved uid.
964 *
965 * If the newly requested real uid or effective uid does not
966 * match the saved uid, then set the saved uid to the new
967 * effective uid (potentially unrecoverably dropping saved
968 * privilege).
969 *
970 * If the credential is changed as a result of this call, then we
971 * flag the process as having set privilege since the last exec.
972 */
973 int
974 setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval)
975 {
976 uid_t ruid, euid;
977 int error;
978 kauth_cred_t my_cred, my_new_cred;
979 posix_cred_t my_pcred;
980
981 DEBUG_CRED_ENTER("setreuid %d %d\n", uap->ruid, uap->euid);
982
983 ruid = uap->ruid;
984 euid = uap->euid;
985 if (ruid == (uid_t)-1) {
986 ruid = KAUTH_UID_NONE;
987 }
988 if (euid == (uid_t)-1) {
989 euid = KAUTH_UID_NONE;
990 }
991 AUDIT_ARG(euid, euid);
992 AUDIT_ARG(ruid, ruid);
993
994 my_cred = kauth_cred_proc_ref(p);
995 my_pcred = posix_cred_get(my_cred);
996
997 for (;;) {
998 if (((ruid != KAUTH_UID_NONE && /* allow no change of ruid */
999 ruid != my_pcred->cr_ruid && /* allow ruid = ruid */
1000 ruid != my_pcred->cr_uid && /* allow ruid = euid */
1001 ruid != my_pcred->cr_svuid) || /* allow ruid = svuid */
1002 (euid != KAUTH_UID_NONE && /* allow no change of euid */
1003 euid != my_pcred->cr_uid && /* allow euid = euid */
1004 euid != my_pcred->cr_ruid && /* allow euid = ruid */
1005 euid != my_pcred->cr_svuid)) && /* allow euid = svuid */
1006 (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
1007 kauth_cred_unref(&my_cred);
1008 return error;
1009 }
1010
1011 uid_t new_euid;
1012 uid_t svuid = KAUTH_UID_NONE;
1013
1014 new_euid = my_pcred->cr_uid;
1015 /*
1016 * Set the credential with new info. If there is no change,
1017 * we get back the same credential we passed in; if there is
1018 * a change, we drop the reference on the credential we
1019 * passed in. The subsequent compare is safe, because it is
1020 * a pointer compare rather than a contents compare.
1021 */
1022 if (euid != KAUTH_UID_NONE && my_pcred->cr_uid != euid) {
1023 /* changing the effective UID */
1024 new_euid = euid;
1025 OSBitOrAtomic(P_SUGID, &p->p_flag);
1026 }
1027 /*
1028 * If the newly requested real uid or effective uid does
1029 * not match the saved uid, then set the saved uid to the
1030 * new effective uid. We are protected from escalation
1031 * by the prechecking.
1032 */
1033 if (my_pcred->cr_svuid != uap->ruid &&
1034 my_pcred->cr_svuid != uap->euid) {
1035 svuid = new_euid;
1036 OSBitOrAtomic(P_SUGID, &p->p_flag);
1037 }
1038
1039 my_new_cred = kauth_cred_setresuid(my_cred, ruid, euid, svuid, my_pcred->cr_gmuid);
1040
1041 if (my_cred != my_new_cred) {
1042 DEBUG_CRED_CHANGE("setreuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
1043
1044 /*
1045 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
1046 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
1047 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
1048 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
1049 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
1050 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
1051 */
1052 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
1053 (void)chgproccnt(ruid, 1);
1054 }
1055
1056 proc_ucred_lock(p);
1057 /*
1058 * We need to protect for a race where another thread
1059 * also changed the credential after we took our
1060 * reference. If p_ucred has changed then we should
1061 * restart this again with the new cred.
1062 *
1063 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
1064 */
1065 if (p->p_ucred != my_cred) {
1066 proc_ucred_unlock(p);
1067 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
1068 /*
1069 * We didn't successfully switch to the new ruid, so decrement
1070 * the procs/uid count that we incremented above.
1071 */
1072 (void)chgproccnt(ruid, -1);
1073 }
1074 kauth_cred_unref(&my_new_cred);
1075 my_cred = kauth_cred_proc_ref(p);
1076 my_pcred = posix_cred_get(my_cred);
1077 /* try again */
1078 continue;
1079 }
1080
1081 p->p_ucred = my_new_cred;
1082 /* update cred on proc */
1083 PROC_UPDATE_CREDS_ONPROC(p);
1084 OSBitOrAtomic(P_SUGID, &p->p_flag);
1085 proc_ucred_unlock(p);
1086
1087 if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
1088 /*
1089 * We switched to a new ruid, so decrement the count of procs running
1090 * under the previous ruid
1091 */
1092 (void)chgproccnt(my_pcred->cr_ruid, -1);
1093 }
1094 }
1095 break;
1096 }
1097 /* drop old proc reference or our extra reference */
1098 kauth_cred_unref(&my_cred);
1099
1100 set_security_token(p);
1101 return 0;
1102 }
1103
1104
1105 /*
1106 * setgid
1107 *
1108 * Description: Set group ID system call
1109 *
1110 * Parameters: uap->gid gid to set
1111 *
1112 * Returns: 0 Success
1113 * suser:EPERM Permission denied
1114 *
1115 * Notes: If called by a privileged process, this function will set the
1116 * real, effective, and saved gid to the requested value.
1117 *
1118 * If called from an unprivileged process, but gid is equal to the
1119 * real or saved gid, then the effective gid will be set to the
1120 * requested value, but the real and saved gid will not change.
1121 *
1122 * If the credential is changed as a result of this call, then we
1123 * flag the process as having set privilege since the last exec.
1124 *
1125 * As an implementation detail, the effective gid is stored as
1126 * the first element of the supplementary group list, and
1127 * therefore the effective group list may be reordered to keep
1128 * the supplementary group list unchanged.
1129 */
1130 int
1131 setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval)
1132 {
1133 gid_t gid;
1134 gid_t rgid = KAUTH_GID_NONE;
1135 gid_t svgid = KAUTH_GID_NONE;
1136 int error;
1137 kauth_cred_t my_cred, my_new_cred;
1138 posix_cred_t my_pcred;
1139
1140 DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p->p_pid, (p->p_pptr ? p->p_pptr->p_pid : 0), uap->gid);
1141
1142 gid = uap->gid;
1143 AUDIT_ARG(gid, gid);
1144
1145 /* get current credential and take a reference while we muck with it */
1146 my_cred = kauth_cred_proc_ref(p);
1147 my_pcred = posix_cred_get(my_cred);
1148
1149 for (;;) {
1150 if (gid != my_pcred->cr_rgid && /* allow setgid(getgid()) */
1151 gid != my_pcred->cr_svgid && /* allow setgid(saved gid) */
1152 (error = suser(my_cred, &p->p_acflag))) {
1153 kauth_cred_unref(&my_cred);
1154 return error;
1155 }
1156
1157 /*
1158 * If we are privileged, then set the saved and real GID too;
1159 * otherwise, just set the effective GID
1160 */
1161 if (suser(my_cred, &p->p_acflag) == 0) {
1162 svgid = gid;
1163 rgid = gid;
1164 } else {
1165 svgid = KAUTH_GID_NONE;
1166 rgid = KAUTH_GID_NONE;
1167 }
1168
1169 /*
1170 * Set the credential with new info. If there is no change,
1171 * we get back the same credential we passed in; if there is
1172 * a change, we drop the reference on the credential we
1173 * passed in. The subsequent compare is safe, because it is
1174 * a pointer compare rather than a contents compare.
1175 */
1176 my_new_cred = kauth_cred_setresgid(my_cred, rgid, gid, svgid);
1177 if (my_cred != my_new_cred) {
1178 DEBUG_CRED_CHANGE("setgid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
1179
1180 proc_ucred_lock(p);
1181 /*
1182 * We need to protect for a race where another thread
1183 * also changed the credential after we took our
1184 * reference. If p_ucred has changed then we
1185 * should restart this again with the new cred.
1186 */
1187 if (p->p_ucred != my_cred) {
1188 proc_ucred_unlock(p);
1189 kauth_cred_unref(&my_new_cred);
1190 /* try again */
1191 my_cred = kauth_cred_proc_ref(p);
1192 my_pcred = posix_cred_get(my_cred);
1193 continue;
1194 }
1195 p->p_ucred = my_new_cred;
1196 /* update cred on proc */
1197 PROC_UPDATE_CREDS_ONPROC(p);
1198 OSBitOrAtomic(P_SUGID, &p->p_flag);
1199 proc_ucred_unlock(p);
1200 }
1201 break;
1202 }
1203 /* Drop old proc reference or our extra reference */
1204 kauth_cred_unref(&my_cred);
1205
1206 set_security_token(p);
1207 return 0;
1208 }
1209
1210
1211 /*
1212 * setegid
1213 *
1214 * Description: Set effective group ID system call
1215 *
1216 * Parameters: uap->egid effective gid to set
1217 *
1218 * Returns: 0 Success
1219 * suser:EPERM
1220 *
1221 * Notes: If called by a privileged process, or called from an
1222 * unprivileged process but egid is equal to the real or saved
1223 * gid, then the effective gid will be set to the requested
1224 * value, but the real and saved gid will not change.
1225 *
1226 * If the credential is changed as a result of this call, then we
1227 * flag the process as having set privilege since the last exec.
1228 *
1229 * As an implementation detail, the effective gid is stored as
1230 * the first element of the supplementary group list, and
1231 * therefore the effective group list may be reordered to keep
1232 * the supplementary group list unchanged.
1233 */
1234 int
1235 setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval)
1236 {
1237 gid_t egid;
1238 int error;
1239 kauth_cred_t my_cred, my_new_cred;
1240 posix_cred_t my_pcred;
1241
1242 DEBUG_CRED_ENTER("setegid %d\n", uap->egid);
1243
1244 egid = uap->egid;
1245 AUDIT_ARG(egid, egid);
1246
1247 /* get current credential and take a reference while we muck with it */
1248 my_cred = kauth_cred_proc_ref(p);
1249 my_pcred = posix_cred_get(my_cred);
1250
1251
1252 for (;;) {
1253 if (egid != my_pcred->cr_rgid &&
1254 egid != my_pcred->cr_svgid &&
1255 (error = suser(my_cred, &p->p_acflag))) {
1256 kauth_cred_unref(&my_cred);
1257 return error;
1258 }
1259 /*
1260 * Set the credential with new info. If there is no change,
1261 * we get back the same credential we passed in; if there is
1262 * a change, we drop the reference on the credential we
1263 * passed in. The subsequent compare is safe, because it is
1264 * a pointer compare rather than a contents compare.
1265 */
1266 my_new_cred = kauth_cred_setresgid(my_cred, KAUTH_GID_NONE, egid, KAUTH_GID_NONE);
1267 if (my_cred != my_new_cred) {
1268 DEBUG_CRED_CHANGE("setegid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
1269
1270 proc_ucred_lock(p);
1271 /*
1272 * We need to protect for a race where another thread
1273 * also changed the credential after we took our
1274 * reference. If p_ucred has changed then we
1275 * should restart this again with the new cred.
1276 */
1277 if (p->p_ucred != my_cred) {
1278 proc_ucred_unlock(p);
1279 kauth_cred_unref(&my_new_cred);
1280 /* try again */
1281 my_cred = kauth_cred_proc_ref(p);
1282 my_pcred = posix_cred_get(my_cred);
1283 continue;
1284 }
1285 p->p_ucred = my_new_cred;
1286 /* update cred on proc */
1287 PROC_UPDATE_CREDS_ONPROC(p);
1288 OSBitOrAtomic(P_SUGID, &p->p_flag);
1289 proc_ucred_unlock(p);
1290 }
1291 break;
1292 }
1293
1294 /* Drop old proc reference or our extra reference */
1295 kauth_cred_unref(&my_cred);
1296
1297 set_security_token(p);
1298 return 0;
1299 }
1300
1301 /*
1302 * setregid
1303 *
1304 * Description: Set real and effective group ID system call
1305 *
1306 * Parameters: uap->rgid real gid to set
1307 * uap->egid effective gid to set
1308 *
1309 * Returns: 0 Success
1310 * suser:EPERM Permission denied
1311 *
1312 * Notes: A value of -1 is a special case indicating that the gid for
1313 * which that value is specified not be changed. If both values
1314 * are specified as -1, no action is taken.
1315 *
1316 * If called by a privileged process, the real and effective gid
1317 * will be set to the new value(s) specified.
1318 *
1319 * If called from an unprivileged process, the real gid may be
1320 * set to the current value of the real gid, or to the current
1321 * value of the saved gid. The effective gid may be set to the
1322 * current value of any of the effective, real, or saved gid.
1323 *
1324 * If the new real and effective gid will not be equal, or the
1325 * new real or effective gid is not the same as the saved gid,
1326 * then the saved gid will be updated to reflect the new
1327 * effective gid (potentially unrecoverably dropping saved
1328 * privilege).
1329 *
1330 * If the credential is changed as a result of this call, then we
1331 * flag the process as having set privilege since the last exec.
1332 *
1333 * As an implementation detail, the effective gid is stored as
1334 * the first element of the supplementary group list, and
1335 * therefore the effective group list may be reordered to keep
1336 * the supplementary group list unchanged.
1337 */
1338 int
1339 setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval)
1340 {
1341 gid_t rgid, egid;
1342 int error;
1343 kauth_cred_t my_cred, my_new_cred;
1344 posix_cred_t my_pcred;
1345
1346 DEBUG_CRED_ENTER("setregid %d %d\n", uap->rgid, uap->egid);
1347
1348 rgid = uap->rgid;
1349 egid = uap->egid;
1350
1351 if (rgid == (uid_t)-1) {
1352 rgid = KAUTH_GID_NONE;
1353 }
1354 if (egid == (uid_t)-1) {
1355 egid = KAUTH_GID_NONE;
1356 }
1357 AUDIT_ARG(egid, egid);
1358 AUDIT_ARG(rgid, rgid);
1359
1360 /* get current credential and take a reference while we muck with it */
1361 my_cred = kauth_cred_proc_ref(p);
1362 my_pcred = posix_cred_get(my_cred);
1363
1364 for (;;) {
1365 if (((rgid != KAUTH_UID_NONE && /* allow no change of rgid */
1366 rgid != my_pcred->cr_rgid && /* allow rgid = rgid */
1367 rgid != my_pcred->cr_gid && /* allow rgid = egid */
1368 rgid != my_pcred->cr_svgid) || /* allow rgid = svgid */
1369 (egid != KAUTH_UID_NONE && /* allow no change of egid */
1370 egid != my_pcred->cr_groups[0] && /* allow no change of egid */
1371 egid != my_pcred->cr_gid && /* allow egid = egid */
1372 egid != my_pcred->cr_rgid && /* allow egid = rgid */
1373 egid != my_pcred->cr_svgid)) && /* allow egid = svgid */
1374 (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
1375 kauth_cred_unref(&my_cred);
1376 return error;
1377 }
1378
1379 uid_t new_egid = my_pcred->cr_gid;
1380 uid_t new_rgid = my_pcred->cr_rgid;
1381 uid_t svgid = KAUTH_UID_NONE;
1382
1383
1384 /*
1385 * Set the credential with new info. If there is no change,
1386 * we get back the same credential we passed in; if there is
1387 * a change, we drop the reference on the credential we
1388 * passed in. The subsequent compare is safe, because it is
1389 * a pointer compare rather than a contents compare.
1390 */
1391 if (egid != KAUTH_UID_NONE && my_pcred->cr_gid != egid) {
1392 /* changing the effective GID */
1393 new_egid = egid;
1394 OSBitOrAtomic(P_SUGID, &p->p_flag);
1395 }
1396 if (rgid != KAUTH_UID_NONE && my_pcred->cr_rgid != rgid) {
1397 /* changing the real GID */
1398 new_rgid = rgid;
1399 OSBitOrAtomic(P_SUGID, &p->p_flag);
1400 }
1401 /*
1402 * If the newly requested real gid or effective gid does
1403 * not match the saved gid, then set the saved gid to the
1404 * new effective gid. We are protected from escalation
1405 * by the prechecking.
1406 */
1407 if (my_pcred->cr_svgid != uap->rgid &&
1408 my_pcred->cr_svgid != uap->egid) {
1409 svgid = new_egid;
1410 OSBitOrAtomic(P_SUGID, &p->p_flag);
1411 }
1412
1413 my_new_cred = kauth_cred_setresgid(my_cred, rgid, egid, svgid);
1414 if (my_cred != my_new_cred) {
1415 DEBUG_CRED_CHANGE("setregid(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_pcred->cr_flags, my_new_cred, posix_cred_get(my_new_cred)->cr_flags);
1416
1417 proc_ucred_lock(p);
1418 /* need to protect for a race where another thread
1419 * also changed the credential after we took our
1420 * reference. If p_ucred has changed then we
1421 * should restart this again with the new cred.
1422 */
1423 if (p->p_ucred != my_cred) {
1424 proc_ucred_unlock(p);
1425 kauth_cred_unref(&my_new_cred);
1426 /* try again */
1427 my_cred = kauth_cred_proc_ref(p);
1428 my_pcred = posix_cred_get(my_cred);
1429 continue;
1430 }
1431 p->p_ucred = my_new_cred;
1432 /* update cred on proc */
1433 PROC_UPDATE_CREDS_ONPROC(p);
1434 OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
1435 proc_ucred_unlock(p);
1436 }
1437 break;
1438 }
1439 /* Drop old proc reference or our extra reference */
1440 kauth_cred_unref(&my_cred);
1441
1442 set_security_token(p);
1443 return 0;
1444 }
1445
1446
1447 /*
1448 * Set the per-thread override identity. The first parameter can be the
1449 * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
1450 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1451 * means "revert to the per process credential"; otherwise, if permitted,
1452 * it changes the effective, real, and saved UIDs and GIDs for the current
1453 * thread to the requested UID and single GID, and clears all other GIDs.
1454 */
1455 int
1456 settid(proc_t p, struct settid_args *uap, __unused int32_t *retval)
1457 {
1458 kauth_cred_t uc;
1459 struct uthread *uthread = get_bsdthread_info(current_thread());
1460 uid_t uid;
1461 gid_t gid;
1462
1463 uid = uap->uid;
1464 gid = uap->gid;
1465 AUDIT_ARG(uid, uid);
1466 AUDIT_ARG(gid, gid);
1467
1468 if (proc_suser(p) != 0) {
1469 return EPERM;
1470 }
1471
1472 if (uid == KAUTH_UID_NONE) {
1473 /* must already be assuming another identity in order to revert back */
1474 if ((uthread->uu_flag & UT_SETUID) == 0) {
1475 return EPERM;
1476 }
1477
1478 /* revert to delayed binding of process credential */
1479 uc = kauth_cred_proc_ref(p);
1480 kauth_cred_unref(&uthread->uu_ucred);
1481 uthread->uu_ucred = uc;
1482 uthread->uu_flag &= ~UT_SETUID;
1483 } else {
1484 kauth_cred_t my_cred, my_new_cred;
1485
1486 /* cannot already be assuming another identity */
1487 if ((uthread->uu_flag & UT_SETUID) != 0) {
1488 return EPERM;
1489 }
1490
1491 /*
1492 * Get a new credential instance from the old if this one
1493 * changes; otherwise kauth_cred_setuidgid() returns the
1494 * same credential. We take an extra reference on the
1495 * current credential while we muck with it, so we can do
1496 * the post-compare for changes by pointer.
1497 */
1498 kauth_cred_ref(uthread->uu_ucred);
1499 my_cred = uthread->uu_ucred;
1500 my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid);
1501 if (my_cred != my_new_cred) {
1502 uthread->uu_ucred = my_new_cred;
1503 }
1504 uthread->uu_flag |= UT_SETUID;
1505
1506 /* Drop old uthread reference or our extra reference */
1507 kauth_cred_unref(&my_cred);
1508 }
1509 /*
1510 * XXX should potentially set per thread security token (there is
1511 * XXX none).
1512 * XXX it is unclear whether P_SUGID should be st at this point;
1513 * XXX in theory, it is being deprecated.
1514 */
1515 return 0;
1516 }
1517
1518
1519 /*
1520 * Set the per-thread override identity. Use this system call for a thread to
1521 * assume the identity of another process or to revert back to normal identity
1522 * of the current process.
1523 *
1524 * When the "assume" argument is non zero the current thread will assume the
1525 * identity of the process represented by the pid argument.
1526 *
1527 * When the assume argument is zero we revert back to our normal identity.
1528 */
1529 int
1530 settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *retval)
1531 {
1532 proc_t target_proc;
1533 struct uthread *uthread = get_bsdthread_info(current_thread());
1534 kauth_cred_t my_cred, my_target_cred, my_new_cred;
1535 posix_cred_t my_target_pcred;
1536
1537 AUDIT_ARG(pid, uap->pid);
1538 AUDIT_ARG(value32, uap->assume);
1539
1540 if (proc_suser(p) != 0) {
1541 return EPERM;
1542 }
1543
1544 /*
1545 * XXX should potentially set per thread security token (there is
1546 * XXX none).
1547 * XXX it is unclear whether P_SUGID should be st at this point;
1548 * XXX in theory, it is being deprecated.
1549 */
1550
1551 /*
1552 * assume argument tells us to assume the identity of the process with the
1553 * id passed in the pid argument.
1554 */
1555 if (uap->assume != 0) {
1556 /* can't do this if we have already assumed an identity */
1557 if ((uthread->uu_flag & UT_SETUID) != 0) {
1558 return EPERM;
1559 }
1560
1561 target_proc = proc_find(uap->pid);
1562 /* can't assume the identity of the kernel process */
1563 if (target_proc == NULL || target_proc == kernproc) {
1564 if (target_proc != NULL) {
1565 proc_rele(target_proc);
1566 }
1567 return ESRCH;
1568 }
1569
1570 /*
1571 * Take a reference on the credential used in our target
1572 * process then use it as the identity for our current
1573 * thread. We take an extra reference on the current
1574 * credential while we muck with it, so we can do the
1575 * post-compare for changes by pointer.
1576 *
1577 * The post-compare is needed for the case that our process
1578 * credential has been changed to be identical to our thread
1579 * credential following our assumption of a per-thread one,
1580 * since the credential cache will maintain a unique instance.
1581 */
1582 kauth_cred_ref(uthread->uu_ucred);
1583 my_cred = uthread->uu_ucred;
1584 my_target_cred = kauth_cred_proc_ref(target_proc);
1585 my_target_pcred = posix_cred_get(my_target_cred);
1586 my_new_cred = kauth_cred_setuidgid(my_cred, my_target_pcred->cr_uid, my_target_pcred->cr_gid);
1587 if (my_cred != my_new_cred) {
1588 uthread->uu_ucred = my_new_cred;
1589 }
1590
1591 uthread->uu_flag |= UT_SETUID;
1592
1593 /* Drop old uthread reference or our extra reference */
1594 proc_rele(target_proc);
1595 kauth_cred_unref(&my_cred);
1596 kauth_cred_unref(&my_target_cred);
1597
1598 return 0;
1599 }
1600
1601 /*
1602 * Otherwise, we are reverting back to normal mode of operation where
1603 * delayed binding of the process credential sets the credential in
1604 * the thread (uu_ucred)
1605 */
1606 if ((uthread->uu_flag & UT_SETUID) == 0) {
1607 return EPERM;
1608 }
1609
1610 /* revert to delayed binding of process credential */
1611 my_new_cred = kauth_cred_proc_ref(p);
1612 kauth_cred_unref(&uthread->uu_ucred);
1613 uthread->uu_ucred = my_new_cred;
1614 uthread->uu_flag &= ~UT_SETUID;
1615
1616 return 0;
1617 }
1618
1619
1620 /*
1621 * setgroups1
1622 *
1623 * Description: Internal implementation for both the setgroups and initgroups
1624 * system calls
1625 *
1626 * Parameters: gidsetsize Number of groups in set
1627 * gidset Pointer to group list
1628 * gmuid Base gid (initgroups only!)
1629 *
1630 * Returns: 0 Success
1631 * suser:EPERM Permision denied
1632 * EINVAL Invalid gidsetsize value
1633 * copyin:EFAULT Bad gidset or gidsetsize is
1634 * too large
1635 *
1636 * Notes: When called from a thread running under an assumed per-thread
1637 * identity, this function will operate against the per-thread
1638 * credential, rather than against the process credential. In
1639 * this specific case, the process credential is verified to
1640 * still be privileged at the time of the call, rather than the
1641 * per-thread credential for this operation to be permitted.
1642 *
1643 * This effectively means that setgroups/initigroups calls in
1644 * a thread running a per-thread credential should occur *after*
1645 * the settid call that created it, not before (unlike setuid,
1646 * which must be called after, since it will result in privilege
1647 * being dropped).
1648 *
1649 * When called normally (i.e. no per-thread assumed identity),
1650 * the per process credential is updated per POSIX.
1651 *
1652 * If the credential is changed as a result of this call, then we
1653 * flag the process as having set privilege since the last exec.
1654 */
1655 static int
1656 setgroups1(proc_t p, u_int ngrp, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
1657 {
1658 gid_t newgroups[NGROUPS] = { 0 };
1659 int error;
1660
1661 DEBUG_CRED_ENTER("setgroups1 (%d/%d): %d 0x%016x %d\n", p->p_pid,
1662 (p->p_pptr ? p->p_pptr->p_pid : 0), ngrp, gidset, gmuid);
1663
1664 if (ngrp > NGROUPS) {
1665 return EINVAL;
1666 }
1667
1668 if (ngrp >= 1) {
1669 error = copyin(gidset,
1670 (caddr_t)newgroups, ngrp * sizeof(gid_t));
1671 if (error) {
1672 return error;
1673 }
1674 }
1675 return setgroups_internal(p, ngrp, newgroups, gmuid);
1676 }
1677
1678 int
1679 setgroups_internal(proc_t p, u_int ngrp, gid_t *newgroups, uid_t gmuid)
1680 {
1681 struct uthread *uthread = get_bsdthread_info(current_thread());
1682 kauth_cred_t my_cred, my_new_cred;
1683 int error;
1684
1685 my_cred = kauth_cred_proc_ref(p);
1686 if ((error = suser(my_cred, &p->p_acflag))) {
1687 kauth_cred_unref(&my_cred);
1688 return error;
1689 }
1690
1691 if (ngrp < 1) {
1692 ngrp = 1;
1693 newgroups[0] = 0;
1694 }
1695
1696 if ((uthread->uu_flag & UT_SETUID) != 0) {
1697 #if DEBUG_CRED
1698 int my_cred_flags = uthread->uu_ucred->cr_flags;
1699 #endif /* DEBUG_CRED */
1700 kauth_cred_unref(&my_cred);
1701
1702 /*
1703 * If this thread is under an assumed identity, set the
1704 * supplementary grouplist on the thread credential instead
1705 * of the process one. If we were the only reference holder,
1706 * the credential is updated in place, otherwise, our reference
1707 * is dropped and we get back a different cred with a reference
1708 * already held on it. Because this is per-thread, we don't
1709 * need the referencing/locking/retry required for per-process.
1710 */
1711 my_cred = uthread->uu_ucred;
1712 uthread->uu_ucred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
1713 #if DEBUG_CRED
1714 if (my_cred != uthread->uu_ucred) {
1715 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred_flags, uthread->uu_ucred, uthread->uu_ucred->cr_flags);
1716 }
1717 #endif /* DEBUG_CRED */
1718 } else {
1719 /*
1720 * get current credential and take a reference while we muck
1721 * with it
1722 */
1723 for (;;) {
1724 /*
1725 * Set the credential with new info. If there is no
1726 * change, we get back the same credential we passed
1727 * in; if there is a change, we drop the reference on
1728 * the credential we passed in. The subsequent
1729 * compare is safe, because it is a pointer compare
1730 * rather than a contents compare.
1731 */
1732 my_new_cred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
1733 if (my_cred != my_new_cred) {
1734 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
1735
1736 proc_ucred_lock(p);
1737 /*
1738 * We need to protect for a race where another
1739 * thread also changed the credential after we
1740 * took our reference. If p_ucred has
1741 * changed then we should restart this again
1742 * with the new cred.
1743 */
1744 if (p->p_ucred != my_cred) {
1745 proc_ucred_unlock(p);
1746 kauth_cred_unref(&my_new_cred);
1747 my_cred = kauth_cred_proc_ref(p);
1748 /* try again */
1749 continue;
1750 }
1751 p->p_ucred = my_new_cred;
1752 /* update cred on proc */
1753 PROC_UPDATE_CREDS_ONPROC(p);
1754 OSBitOrAtomic(P_SUGID, &p->p_flag);
1755 proc_ucred_unlock(p);
1756 }
1757 break;
1758 }
1759 /* Drop old proc reference or our extra reference */
1760 AUDIT_ARG(groupset, posix_cred_get(my_cred)->cr_groups, ngrp);
1761 kauth_cred_unref(&my_cred);
1762
1763
1764 set_security_token(p);
1765 }
1766
1767 return 0;
1768 }
1769
1770
1771 /*
1772 * initgroups
1773 *
1774 * Description: Initialize the default supplementary groups list and set the
1775 * gmuid for use by the external group resolver (if any)
1776 *
1777 * Parameters: uap->gidsetsize Number of groups in set
1778 * uap->gidset Pointer to group list
1779 * uap->gmuid Base gid
1780 *
1781 * Returns: 0 Success
1782 * setgroups1:EPERM Permision denied
1783 * setgroups1:EINVAL Invalid gidsetsize value
1784 * setgroups1:EFAULT Bad gidset or gidsetsize is
1785 *
1786 * Notes: This function opts *IN* to memberd participation
1787 *
1788 * The normal purpose of this function is for a privileged
1789 * process to indicate supplementary groups and identity for
1790 * participation in extended group membership resolution prior
1791 * to dropping privilege by assuming a specific user identity.
1792 *
1793 * It is the first half of the primary mechanism whereby user
1794 * identity is established to the system by programs such as
1795 * /usr/bin/login. The second half is the drop of uid privilege
1796 * for a specific uid corresponding to the user.
1797 *
1798 * See also: setgroups1()
1799 */
1800 int
1801 initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval)
1802 {
1803 DEBUG_CRED_ENTER("initgroups\n");
1804
1805 return setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval);
1806 }
1807
1808
1809 /*
1810 * setgroups
1811 *
1812 * Description: Initialize the default supplementary groups list
1813 *
1814 * Parameters: gidsetsize Number of groups in set
1815 * gidset Pointer to group list
1816 *
1817 * Returns: 0 Success
1818 * setgroups1:EPERM Permision denied
1819 * setgroups1:EINVAL Invalid gidsetsize value
1820 * setgroups1:EFAULT Bad gidset or gidsetsize is
1821 *
1822 * Notes: This functions opts *OUT* of memberd participation.
1823 *
1824 * This function exists for compatibility with POSIX. Most user
1825 * programs should use initgroups() instead to ensure correct
1826 * participation in group membership resolution when utilizing
1827 * a directory service for authentication.
1828 *
1829 * It is identical to an initgroups() call with a gmuid argument
1830 * of KAUTH_UID_NONE.
1831 *
1832 * See also: setgroups1()
1833 */
1834 int
1835 setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval)
1836 {
1837 DEBUG_CRED_ENTER("setgroups\n");
1838
1839 return setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval);
1840 }
1841
1842
1843 /*
1844 * Set the per-thread/per-process supplementary groups list.
1845 *
1846 * XXX implement setsgroups
1847 *
1848 */
1849
1850 int
1851 setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval)
1852 {
1853 return ENOTSUP;
1854 }
1855
1856 /*
1857 * Set the per-thread/per-process whiteout groups list.
1858 *
1859 * XXX implement setwgroups
1860 *
1861 */
1862
1863 int
1864 setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval)
1865 {
1866 return ENOTSUP;
1867 }
1868
1869
1870 /*
1871 * Check if gid is a member of the group set.
1872 *
1873 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1874 * XXX instead.
1875 */
1876 int
1877 groupmember(gid_t gid, kauth_cred_t cred)
1878 {
1879 int is_member;
1880
1881 if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member) {
1882 return 1;
1883 }
1884 return 0;
1885 }
1886
1887
1888 /*
1889 * Test whether the specified credentials imply "super-user"
1890 * privilege; if so, and we have accounting info, set the flag
1891 * indicating use of super-powers.
1892 * Returns 0 or error.
1893 *
1894 * XXX This interface is going away; use kauth_cred_issuser() directly
1895 * XXX instead.
1896 *
1897 * Note: This interface exists to implement the "has used privilege"
1898 * bit (ASU) in the p_acflags field of the process, which is
1899 * only externalized via private sysctl and in process accounting
1900 * records. The flag is technically not required in either case.
1901 */
1902 int
1903 suser(kauth_cred_t cred, u_short *acflag)
1904 {
1905 #if DIAGNOSTIC
1906 if (!IS_VALID_CRED(cred)) {
1907 panic("suser");
1908 }
1909 #endif
1910 if (kauth_cred_getuid(cred) == 0) {
1911 if (acflag) {
1912 *acflag |= ASU;
1913 }
1914 return 0;
1915 }
1916 return EPERM;
1917 }
1918
1919
1920 /*
1921 * getlogin
1922 *
1923 * Description: Get login name, if available.
1924 *
1925 * Parameters: uap->namebuf User buffer for return
1926 * uap->namelen User buffer length
1927 *
1928 * Returns: 0 Success
1929 * copyout:EFAULT
1930 *
1931 * Notes: Intended to obtain a string containing the user name of the
1932 * user associated with the controlling terminal for the calling
1933 * process.
1934 *
1935 * Not very useful on modern systems, due to inherent length
1936 * limitations for the static array in the session structure
1937 * which is used to store the login name.
1938 *
1939 * Permitted to return NULL
1940 *
1941 * XXX: Belongs in kern_proc.c
1942 */
1943 int
1944 getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval)
1945 {
1946 char buffer[MAXLOGNAME + 1];
1947 struct session * sessp;
1948
1949 bzero(buffer, MAXLOGNAME + 1);
1950
1951 sessp = proc_session(p);
1952
1953 if (uap->namelen > MAXLOGNAME) {
1954 uap->namelen = MAXLOGNAME;
1955 }
1956
1957 if (sessp != SESSION_NULL) {
1958 session_lock(sessp);
1959 bcopy( sessp->s_login, buffer, uap->namelen);
1960 session_unlock(sessp);
1961 }
1962 session_rele(sessp);
1963
1964 return copyout((caddr_t)buffer, uap->namebuf, uap->namelen);
1965 }
1966
1967 void
1968 setlogin_internal(proc_t p, const char login[static MAXLOGNAME])
1969 {
1970 struct session *sessp = proc_session(p);
1971
1972 if (sessp != SESSION_NULL) {
1973 session_lock(sessp);
1974 bcopy(login, sessp->s_login, MAXLOGNAME);
1975 session_unlock(sessp);
1976 session_rele(sessp);
1977 }
1978 }
1979
1980 /*
1981 * setlogin
1982 *
1983 * Description: Set login name.
1984 *
1985 * Parameters: uap->namebuf User buffer containing name
1986 *
1987 * Returns: 0 Success
1988 * suser:EPERM Permission denied
1989 * copyinstr:EFAULT User buffer invalid
1990 * copyinstr:EINVAL Supplied name was too long
1991 *
1992 * Notes: This is a utility system call to support getlogin().
1993 *
1994 * XXX: Belongs in kern_proc.c
1995 */
1996 int
1997 setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval)
1998 {
1999 int error;
2000 size_t dummy = 0;
2001 char buffer[MAXLOGNAME + 1];
2002
2003 if ((error = proc_suser(p))) {
2004 return error;
2005 }
2006
2007 bzero(&buffer[0], MAXLOGNAME + 1);
2008
2009
2010 error = copyinstr(uap->namebuf,
2011 (caddr_t) &buffer[0],
2012 MAXLOGNAME - 1, (size_t *)&dummy);
2013
2014 setlogin_internal(p, buffer);
2015
2016 if (!error) {
2017 AUDIT_ARG(text, buffer);
2018 } else if (error == ENAMETOOLONG) {
2019 error = EINVAL;
2020 }
2021 return error;
2022 }
2023
2024
2025 /* Set the secrity token of the task with current euid and eguid */
2026 /*
2027 * XXX This needs to change to give the task a reference and/or an opaque
2028 * XXX identifier.
2029 */
2030 int
2031 set_security_token(proc_t p)
2032 {
2033 return set_security_token_task_internal(p, p->task);
2034 }
2035
2036 static void
2037 proc_calc_audit_token(proc_t p, kauth_cred_t my_cred, audit_token_t *audit_token)
2038 {
2039 posix_cred_t my_pcred = posix_cred_get(my_cred);
2040
2041 /*
2042 * The current layout of the Mach audit token explicitly
2043 * adds these fields. But nobody should rely on such
2044 * a literal representation. Instead, the BSM library
2045 * provides a function to convert an audit token into
2046 * a BSM subject. Use of that mechanism will isolate
2047 * the user of the trailer from future representation
2048 * changes.
2049 */
2050 audit_token->val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
2051 audit_token->val[1] = my_pcred->cr_uid;
2052 audit_token->val[2] = my_pcred->cr_gid;
2053 audit_token->val[3] = my_pcred->cr_ruid;
2054 audit_token->val[4] = my_pcred->cr_rgid;
2055 audit_token->val[5] = p->p_pid;
2056 audit_token->val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
2057 audit_token->val[7] = p->p_idversion;
2058 }
2059
2060 /*
2061 * Set the secrity token of the task with current euid and eguid
2062 * The function takes a proc and a task, where proc->task might point to a
2063 * different task if called from exec.
2064 */
2065
2066 int
2067 set_security_token_task_internal(proc_t p, void *t)
2068 {
2069 kauth_cred_t my_cred;
2070 security_token_t sec_token;
2071 audit_token_t audit_token;
2072 host_priv_t host_priv;
2073 task_t task = t;
2074
2075 /*
2076 * Don't allow a vfork child to override the parent's token settings
2077 * (since they share a task). Instead, the child will just have to
2078 * suffer along using the parent's token until the exec(). It's all
2079 * undefined behavior anyway, right?
2080 */
2081 if (task == current_task()) {
2082 uthread_t uthread;
2083 uthread = (uthread_t)get_bsdthread_info(current_thread());
2084 if (uthread->uu_flag & UT_VFORK) {
2085 return 1;
2086 }
2087 }
2088
2089 my_cred = kauth_cred_proc_ref(p);
2090
2091 proc_calc_audit_token(p, my_cred, &audit_token);
2092
2093 /* XXX mach_init doesn't have a p_ucred when it calls this function */
2094 if (IS_VALID_CRED(my_cred)) {
2095 sec_token.val[0] = kauth_cred_getuid(my_cred);
2096 sec_token.val[1] = kauth_cred_getgid(my_cred);
2097 } else {
2098 sec_token.val[0] = 0;
2099 sec_token.val[1] = 0;
2100 }
2101
2102 host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
2103 #if CONFIG_MACF
2104 if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred)) {
2105 host_priv = HOST_PRIV_NULL;
2106 }
2107 #endif
2108 kauth_cred_unref(&my_cred);
2109
2110 #if DEVELOPMENT || DEBUG
2111 /*
2112 * Update the pid an proc name for importance base if any
2113 */
2114 task_importance_update_owner_info(task);
2115 #endif
2116
2117 return host_security_set_task_token(host_security_self(),
2118 task,
2119 sec_token,
2120 audit_token,
2121 host_priv) != KERN_SUCCESS;
2122 }
2123
2124 void
2125 proc_parent_audit_token(proc_t p, audit_token_t *token_out)
2126 {
2127 proc_t parent;
2128 kauth_cred_t my_cred;
2129
2130 proc_list_lock();
2131
2132 parent = p->p_pptr;
2133 my_cred = kauth_cred_proc_ref(parent);
2134 proc_calc_audit_token(parent, my_cred, token_out);
2135 kauth_cred_unref(&my_cred);
2136
2137 proc_list_unlock();
2138 }
2139
2140
2141 int get_audit_token_pid(audit_token_t *audit_token);
2142
2143 int
2144 get_audit_token_pid(audit_token_t *audit_token)
2145 {
2146 /* keep in-sync with set_security_token (above) */
2147 if (audit_token) {
2148 return (int)audit_token->val[5];
2149 }
2150 return -1;
2151 }
2152
2153
2154 /*
2155 * Fill in a struct xucred based on a kauth_cred_t.
2156 */
2157 __private_extern__
2158 void
2159 cru2x(kauth_cred_t cr, struct xucred *xcr)
2160 {
2161 posix_cred_t pcr = posix_cred_get(cr);
2162
2163 bzero(xcr, sizeof(*xcr));
2164 xcr->cr_version = XUCRED_VERSION;
2165 xcr->cr_uid = kauth_cred_getuid(cr);
2166 xcr->cr_ngroups = pcr->cr_ngroups;
2167 bcopy(pcr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
2168 }