2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
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.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
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.
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
68 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
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,
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,
85 * System calls related to processes and protection
88 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/ucred.h>
92 #include <sys/proc_internal.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>
100 #include <security/audit/audit.h>
103 #include <security/mac_framework.h>
106 #include <sys/mount_internal.h>
107 #include <sys/sysproto.h>
108 #include <mach/message.h>
109 #include <mach/host_security.h>
111 #include <kern/host.h>
112 #include <kern/task.h> /* for current_task() */
113 #include <kern/assert.h>
117 * Credential debugging; we can track entry into a function that might
118 * change a credential, and we can track actual credential changes that
121 * Note: Does *NOT* currently include per-thread credential changes
124 #define DEBUG_CRED_ENTER printf
125 #define DEBUG_CRED_CHANGE printf
126 #else /* !DEBUG_CRED */
127 #define DEBUG_CRED_ENTER(fmt, ...) do {} while (0)
128 #define DEBUG_CRED_CHANGE(fmt, ...) do {} while (0)
129 #endif /* !DEBUG_CRED */
131 #if DEVELOPMENT || DEBUG
132 extern void task_importance_update_owner_info(task_t
);
139 * Description: (dis)allow this process to hold task, thread, or execption
140 * ports of processes about to exec.
142 * Parameters: uap->flag New value for flag
144 * Returns: int Previous value of flag
146 * XXX: Belongs in kern_proc.c
149 setprivexec(proc_t p
, struct setprivexec_args
*uap
, int32_t *retval
)
151 AUDIT_ARG(value32
, uap
->flag
);
152 *retval
= p
->p_debugger
;
153 p
->p_debugger
= (uap
->flag
!= 0);
161 * Description: get the process ID
165 * Returns: pid_t Current process ID
167 * XXX: Belongs in kern_proc.c
170 getpid(proc_t p
, __unused
struct getpid_args
*uap
, int32_t *retval
)
180 * Description: get the parent process ID
184 * Returns: pid_t Parent process ID
186 * XXX: Belongs in kern_proc.c
189 getppid(proc_t p
, __unused
struct getppid_args
*uap
, int32_t *retval
)
199 * Description: get the process group ID of the calling process
203 * Returns: pid_t Process group ID
205 * XXX: Belongs in kern_proc.c
208 getpgrp(proc_t p
, __unused
struct getpgrp_args
*uap
, int32_t *retval
)
210 *retval
= p
->p_pgrpid
;
218 * Description: Get an arbitary pid's process group id
220 * Parameters: uap->pid The target pid
223 * ESRCH No such process
225 * Notes: We are permitted to return EPERM in the case that the target
226 * process is not in the same session as the calling process,
227 * which could be a security consideration
229 * XXX: Belongs in kern_proc.c
232 getpgid(proc_t p
, struct getpgid_args
*uap
, int32_t *retval
)
242 if ((pt
= proc_find(uap
->pid
)) == 0) {
247 *retval
= pt
->p_pgrpid
;
258 * Description: Get an arbitary pid's session leaders process group ID
260 * Parameters: uap->pid The target pid
263 * ESRCH No such process
265 * Notes: We are permitted to return EPERM in the case that the target
266 * process is not in the same session as the calling process,
267 * which could be a security consideration
269 * XXX: Belongs in kern_proc.c
272 getsid(proc_t p
, struct getsid_args
*uap
, int32_t *retval
)
276 struct session
* sessp
;
283 if ((pt
= proc_find(uap
->pid
)) == 0) {
288 sessp
= proc_session(pt
);
289 *retval
= sessp
->s_sid
;
302 * Description: get real user ID for caller
306 * Returns: uid_t The real uid of the caller
309 getuid(__unused proc_t p
, __unused
struct getuid_args
*uap
, int32_t *retval
)
311 *retval
= kauth_getruid();
319 * Description: get effective user ID for caller
323 * Returns: uid_t The effective uid of the caller
326 geteuid(__unused proc_t p
, __unused
struct geteuid_args
*uap
, int32_t *retval
)
328 *retval
= kauth_getuid();
336 * Description: Return the per-thread override identity.
338 * Parameters: uap->uidp Address of uid_t to get uid
339 * uap->gidp Address of gid_t to get gid
342 * ESRCH No per thread identity active
345 gettid(__unused proc_t p
, struct gettid_args
*uap
, int32_t *retval
)
347 struct uthread
*uthread
= get_bsdthread_info(current_thread());
351 * If this thread is not running with an override identity, we can't
352 * return one to the caller, so return an error instead.
354 if (!(uthread
->uu_flag
& UT_SETUID
)) {
358 if ((error
= suword(uap
->uidp
, kauth_cred_getruid(uthread
->uu_ucred
)))) {
361 if ((error
= suword(uap
->gidp
, kauth_cred_getrgid(uthread
->uu_ucred
)))) {
373 * Description: get the real group ID for the calling process
377 * Returns: gid_t The real gid of the caller
380 getgid(__unused proc_t p
, __unused
struct getgid_args
*uap
, int32_t *retval
)
382 *retval
= kauth_getrgid();
390 * Description: get the effective group ID for the calling process
394 * Returns: gid_t The effective gid of the caller
396 * Notes: As an implementation detail, the effective gid is stored as
397 * the first element of the supplementary group list.
399 * This could be implemented in Libc instead because of the above
403 getegid(__unused proc_t p
, __unused
struct getegid_args
*uap
, int32_t *retval
)
405 *retval
= kauth_getgid();
413 * Description: get the list of supplementary groups for the calling process
415 * Parameters: uap->gidsetsize # of gid_t's in user buffer
416 * uap->gidset Pointer to user buffer
419 * EINVAL User buffer too small
420 * copyout:EFAULT User buffer invalid
425 * Notes: The caller may specify a 0 value for gidsetsize, and we will
426 * then return how large a buffer is required (in gid_t's) to
427 * contain the answer at the time of the call. Otherwise, we
428 * return the number of gid_t's catually copied to user space.
430 * When called with a 0 gidsetsize from a multithreaded program,
431 * there is no guarantee that another thread may not change the
432 * number of supplementary groups, and therefore a subsequent
433 * call could still fail, unless the maximum possible buffer
434 * size is supplied by the user.
436 * As an implementation detail, the effective gid is stored as
437 * the first element of the supplementary group list, and will
438 * be returned by this call.
441 getgroups(__unused proc_t p
, struct getgroups_args
*uap
, int32_t *retval
)
448 /* grab reference while we muck around with the credential */
449 cred
= kauth_cred_get_with_ref();
450 pcred
= posix_cred_get(cred
);
452 if ((ngrp
= uap
->gidsetsize
) == 0) {
453 *retval
= pcred
->cr_ngroups
;
454 kauth_cred_unref(&cred
);
457 if (ngrp
< pcred
->cr_ngroups
) {
458 kauth_cred_unref(&cred
);
461 ngrp
= pcred
->cr_ngroups
;
462 if ((error
= copyout((caddr_t
)pcred
->cr_groups
,
464 ngrp
* sizeof(gid_t
)))) {
465 kauth_cred_unref(&cred
);
468 kauth_cred_unref(&cred
);
475 * Return the per-thread/per-process supplementary groups list.
477 * XXX implement getsgroups
482 getsgroups(__unused proc_t p
, __unused
struct getsgroups_args
*uap
, __unused
int32_t *retval
)
488 * Return the per-thread/per-process whiteout groups list.
490 * XXX implement getwgroups
495 getwgroups(__unused proc_t p
, __unused
struct getwgroups_args
*uap
, __unused
int32_t *retval
)
503 * Description: Core implementation of setsid().
506 setsid_internal(proc_t p
)
508 struct pgrp
* pg
= PGRP_NULL
;
510 if (p
->p_pgrpid
== p
->p_pid
|| (pg
= pgfind(p
->p_pid
)) || p
->p_lflag
& P_LINVFORK
) {
511 if (pg
!= PGRP_NULL
) {
516 /* enter pgrp works with its own pgrp refcount */
517 (void)enterpgrp(p
, p
->p_pid
, 1);
525 * Description: Create a new session and set the process group ID to the
531 * EPERM Permission denied
533 * Notes: If the calling process is not the process group leader; there
534 * is no existing process group with its ID, and we are not
535 * currently in vfork, then this function will create a new
536 * session, a new process group, and put the caller in the
537 * process group (as the sole member) and make it the session
538 * leader (as the sole process in the session).
540 * The existing controlling tty (if any) will be dissociated
541 * from the process, and the next non-O_NOCTTY open of a tty
542 * will establish a new controlling tty.
544 * XXX: Belongs in kern_proc.c
547 setsid(proc_t p
, __unused
struct setsid_args
*uap
, int32_t *retval
)
549 int rc
= setsid_internal(p
);
560 * Description: set process group ID for job control
562 * Parameters: uap->pid Process to change
563 * uap->pgid Process group to join or create
566 * ESRCH pid is not the caller or a child of
568 * enterpgrp:ESRCH No such process
569 * EACCES Permission denied due to exec
570 * EINVAL Invalid argument
571 * EPERM The target process is not in the same
572 * session as the calling process
573 * EPERM The target process is a session leader
574 * EPERM pid and pgid are not the same, and
575 * there is no process in the calling
576 * process whose process group ID matches
579 * Notes: This function will cause the target process to either join
580 * an existing process process group, or create a new process
581 * group in the session of the calling process. It cannot be
582 * used to change the process group ID of a process which is
583 * already a session leader.
585 * If the target pid is 0, the pid of the calling process is
586 * substituted as the new target; if pgid is 0, the target pid
587 * is used as the target process group ID.
589 * Legacy: This system call entry point is also used to implement the
590 * legacy library routine setpgrp(), which under POSIX
592 * XXX: Belongs in kern_proc.c
595 setpgid(proc_t curp
, struct setpgid_args
*uap
, __unused
int32_t *retval
)
597 proc_t targp
= PROC_NULL
; /* target process */
598 struct pgrp
*pg
= PGRP_NULL
; /* target pgrp */
602 struct session
* curp_sessp
= SESSION_NULL
;
603 struct session
* targp_sessp
= SESSION_NULL
;
605 curp_sessp
= proc_session(curp
);
607 if (uap
->pid
!= 0 && uap
->pid
!= curp
->p_pid
) {
608 if ((targp
= proc_find(uap
->pid
)) == 0 || !inferior(targp
)) {
609 if (targp
!= PROC_NULL
) {
616 targp_sessp
= proc_session(targp
);
617 if (targp_sessp
!= curp_sessp
) {
621 if (targp
->p_flag
& P_EXEC
) {
627 targp_sessp
= proc_session(targp
);
630 if (SESS_LEADER(targp
, targp_sessp
)) {
634 if (targp_sessp
!= SESSION_NULL
) {
635 session_rele(targp_sessp
);
636 targp_sessp
= SESSION_NULL
;
643 if (uap
->pgid
== 0) {
644 uap
->pgid
= targp
->p_pid
;
645 } else if (uap
->pgid
!= targp
->p_pid
) {
646 if ((pg
= pgfind(uap
->pgid
)) == 0) {
650 samesess
= (pg
->pg_session
!= curp_sessp
);
657 error
= enterpgrp(targp
, uap
->pgid
, 0);
659 if (targp_sessp
!= SESSION_NULL
) {
660 session_rele(targp_sessp
);
662 if (curp_sessp
!= SESSION_NULL
) {
663 session_rele(curp_sessp
);
675 * Description: Is current process tainted by uid or gid changes system call
679 * Returns: 0 Not tainted
682 * Notes: A process is considered tainted if it was created as a retult
683 * of an execve call from an imnage that had either the SUID or
684 * SGID bit set on the executable, or if it has changed any of its
685 * real, effective, or saved user or group IDs since beginning
689 proc_issetugid(proc_t p
)
691 return (p
->p_flag
& P_SUGID
) ? 1 : 0;
695 issetugid(proc_t p
, __unused
struct issetugid_args
*uap
, int32_t *retval
)
698 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
699 * we use P_SUGID because we consider changing the owners as
700 * "tainting" as well.
701 * This is significant for procs that start as root and "become"
702 * a user without an exec - programs cannot know *everything*
703 * that libc *might* have put in their data segment.
706 *retval
= proc_issetugid(p
);
714 * Description: Set user ID system call
716 * Parameters: uap->uid uid to set
719 * suser:EPERM Permission denied
721 * Notes: If called by a privileged process, this function will set the
722 * real, effective, and saved uid to the requested value.
724 * If called from an unprivileged process, but uid is equal to the
725 * real or saved uid, then the effective uid will be set to the
726 * requested value, but the real and saved uid will not change.
728 * If the credential is changed as a result of this call, then we
729 * flag the process as having set privilege since the last exec.
732 setuid(proc_t p
, struct setuid_args
*uap
, __unused
int32_t *retval
)
735 uid_t svuid
= KAUTH_UID_NONE
;
736 uid_t ruid
= KAUTH_UID_NONE
;
737 uid_t gmuid
= KAUTH_UID_NONE
;
739 kauth_cred_t my_cred
, my_new_cred
;
740 posix_cred_t my_pcred
;
744 /* get current credential and take a reference while we muck with it */
745 my_cred
= kauth_cred_proc_ref(p
);
746 my_pcred
= posix_cred_get(my_cred
);
748 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
);
752 if (uid
!= my_pcred
->cr_ruid
&& /* allow setuid(getuid()) */
753 uid
!= my_pcred
->cr_svuid
&& /* allow setuid(saved uid) */
754 (error
= suser(my_cred
, &p
->p_acflag
))) {
755 kauth_cred_unref(&my_cred
);
760 * If we are privileged, then set the saved and real UID too;
761 * otherwise, just set the effective UID
763 if (suser(my_cred
, &p
->p_acflag
) == 0) {
767 svuid
= KAUTH_UID_NONE
;
768 ruid
= KAUTH_UID_NONE
;
771 * Only set the gmuid if the current cred has not opt'ed out;
772 * this normally only happens when calling setgroups() instead
773 * of initgroups() to set an explicit group list, or one of the
774 * other group manipulation functions is invoked and results in
775 * a dislocation (i.e. the credential group membership changes
776 * to something other than the default list for the user, as
777 * in entering a group or leaving an exclusion group).
779 if (!(my_pcred
->cr_flags
& CRF_NOMEMBERD
)) {
784 * Set the credential with new info. If there is no change,
785 * we get back the same credential we passed in; if there is
786 * a change, we drop the reference on the credential we
787 * passed in. The subsequent compare is safe, because it is
788 * a pointer compare rather than a contents compare.
790 my_new_cred
= kauth_cred_setresuid(my_cred
, ruid
, uid
, svuid
, gmuid
);
791 if (my_cred
!= my_new_cred
) {
792 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
);
795 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
796 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
797 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
798 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
799 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
800 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
802 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
803 (void)chgproccnt(ruid
, 1);
808 * We need to protect for a race where another thread
809 * also changed the credential after we took our
810 * reference. If p_ucred has changed then we should
811 * restart this again with the new cred.
813 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
815 if (p
->p_ucred
!= my_cred
) {
816 proc_ucred_unlock(p
);
818 * We didn't successfully switch to the new ruid, so decrement
819 * the procs/uid count that we incremented above.
821 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
822 (void)chgproccnt(ruid
, -1);
824 kauth_cred_unref(&my_new_cred
);
825 my_cred
= kauth_cred_proc_ref(p
);
826 my_pcred
= posix_cred_get(my_cred
);
830 p
->p_ucred
= my_new_cred
;
831 /* update cred on proc */
832 PROC_UPDATE_CREDS_ONPROC(p
);
834 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
835 proc_ucred_unlock(p
);
837 * If we've updated the ruid, decrement the count of procs running
838 * under the previous ruid
840 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
841 (void)chgproccnt(my_pcred
->cr_ruid
, -1);
846 /* Drop old proc reference or our extra reference */
847 kauth_cred_unref(&my_cred
);
849 set_security_token(p
);
857 * Description: Set effective user ID system call
859 * Parameters: uap->euid effective uid to set
862 * suser:EPERM Permission denied
864 * Notes: If called by a privileged process, or called from an
865 * unprivileged process but euid is equal to the real or saved
866 * uid, then the effective uid will be set to the requested
867 * value, but the real and saved uid will not change.
869 * If the credential is changed as a result of this call, then we
870 * flag the process as having set privilege since the last exec.
873 seteuid(proc_t p
, struct seteuid_args
*uap
, __unused
int32_t *retval
)
877 kauth_cred_t my_cred
, my_new_cred
;
878 posix_cred_t my_pcred
;
880 DEBUG_CRED_ENTER("seteuid: %d\n", uap
->euid
);
883 AUDIT_ARG(euid
, euid
);
885 my_cred
= kauth_cred_proc_ref(p
);
886 my_pcred
= posix_cred_get(my_cred
);
889 if (euid
!= my_pcred
->cr_ruid
&& euid
!= my_pcred
->cr_svuid
&&
890 (error
= suser(my_cred
, &p
->p_acflag
))) {
891 kauth_cred_unref(&my_cred
);
896 * Set the credential with new info. If there is no change,
897 * we get back the same credential we passed in; if there is
898 * a change, we drop the reference on the credential we
899 * passed in. The subsequent compare is safe, because it is
900 * a pointer compare rather than a contents compare.
902 my_new_cred
= kauth_cred_setresuid(my_cred
, KAUTH_UID_NONE
, euid
, KAUTH_UID_NONE
, my_pcred
->cr_gmuid
);
904 if (my_cred
!= my_new_cred
) {
905 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
);
909 * We need to protect for a race where another thread
910 * also changed the credential after we took our
911 * reference. If p_ucred has changed then we
912 * should restart this again with the new cred.
914 if (p
->p_ucred
!= my_cred
) {
915 proc_ucred_unlock(p
);
916 kauth_cred_unref(&my_new_cred
);
917 my_cred
= kauth_cred_proc_ref(p
);
918 my_pcred
= posix_cred_get(my_cred
);
922 p
->p_ucred
= my_new_cred
;
923 /* update cred on proc */
924 PROC_UPDATE_CREDS_ONPROC(p
);
925 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
926 proc_ucred_unlock(p
);
930 /* drop old proc reference or our extra reference */
931 kauth_cred_unref(&my_cred
);
933 set_security_token(p
);
941 * Description: Set real and effective user ID system call
943 * Parameters: uap->ruid real uid to set
944 * uap->euid effective uid to set
947 * suser:EPERM Permission denied
949 * Notes: A value of -1 is a special case indicating that the uid for
950 * which that value is specified not be changed. If both values
951 * are specified as -1, no action is taken.
953 * If called by a privileged process, the real and effective uid
954 * will be set to the new value(s) specified.
956 * If called from an unprivileged process, the real uid may be
957 * set to the current value of the real uid, or to the current
958 * value of the saved uid. The effective uid may be set to the
959 * current value of any of the effective, real, or saved uid.
961 * If the newly requested real uid or effective uid does not
962 * match the saved uid, then set the saved uid to the new
963 * effective uid (potentially unrecoverably dropping saved
966 * If the credential is changed as a result of this call, then we
967 * flag the process as having set privilege since the last exec.
970 setreuid(proc_t p
, struct setreuid_args
*uap
, __unused
int32_t *retval
)
974 kauth_cred_t my_cred
, my_new_cred
;
975 posix_cred_t my_pcred
;
977 DEBUG_CRED_ENTER("setreuid %d %d\n", uap
->ruid
, uap
->euid
);
981 if (ruid
== (uid_t
)-1) {
982 ruid
= KAUTH_UID_NONE
;
984 if (euid
== (uid_t
)-1) {
985 euid
= KAUTH_UID_NONE
;
987 AUDIT_ARG(euid
, euid
);
988 AUDIT_ARG(ruid
, ruid
);
990 my_cred
= kauth_cred_proc_ref(p
);
991 my_pcred
= posix_cred_get(my_cred
);
994 if (((ruid
!= KAUTH_UID_NONE
&& /* allow no change of ruid */
995 ruid
!= my_pcred
->cr_ruid
&& /* allow ruid = ruid */
996 ruid
!= my_pcred
->cr_uid
&& /* allow ruid = euid */
997 ruid
!= my_pcred
->cr_svuid
) || /* allow ruid = svuid */
998 (euid
!= KAUTH_UID_NONE
&& /* allow no change of euid */
999 euid
!= my_pcred
->cr_uid
&& /* allow euid = euid */
1000 euid
!= my_pcred
->cr_ruid
&& /* allow euid = ruid */
1001 euid
!= my_pcred
->cr_svuid
)) && /* allow euid = svuid */
1002 (error
= suser(my_cred
, &p
->p_acflag
))) { /* allow root user any */
1003 kauth_cred_unref(&my_cred
);
1008 uid_t svuid
= KAUTH_UID_NONE
;
1010 new_euid
= my_pcred
->cr_uid
;
1012 * Set the credential with new info. If there is no change,
1013 * we get back the same credential we passed in; if there is
1014 * a change, we drop the reference on the credential we
1015 * passed in. The subsequent compare is safe, because it is
1016 * a pointer compare rather than a contents compare.
1018 if (euid
!= KAUTH_UID_NONE
&& my_pcred
->cr_uid
!= euid
) {
1019 /* changing the effective UID */
1021 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1024 * If the newly requested real uid or effective uid does
1025 * not match the saved uid, then set the saved uid to the
1026 * new effective uid. We are protected from escalation
1027 * by the prechecking.
1029 if (my_pcred
->cr_svuid
!= uap
->ruid
&&
1030 my_pcred
->cr_svuid
!= uap
->euid
) {
1032 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1035 my_new_cred
= kauth_cred_setresuid(my_cred
, ruid
, euid
, svuid
, my_pcred
->cr_gmuid
);
1037 if (my_cred
!= my_new_cred
) {
1038 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
);
1041 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
1042 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
1043 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
1044 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
1045 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
1046 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
1048 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1049 (void)chgproccnt(ruid
, 1);
1054 * We need to protect for a race where another thread
1055 * also changed the credential after we took our
1056 * reference. If p_ucred has changed then we should
1057 * restart this again with the new cred.
1059 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
1061 if (p
->p_ucred
!= my_cred
) {
1062 proc_ucred_unlock(p
);
1063 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1065 * We didn't successfully switch to the new ruid, so decrement
1066 * the procs/uid count that we incremented above.
1068 (void)chgproccnt(ruid
, -1);
1070 kauth_cred_unref(&my_new_cred
);
1071 my_cred
= kauth_cred_proc_ref(p
);
1072 my_pcred
= posix_cred_get(my_cred
);
1077 p
->p_ucred
= my_new_cred
;
1078 /* update cred on proc */
1079 PROC_UPDATE_CREDS_ONPROC(p
);
1080 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1081 proc_ucred_unlock(p
);
1083 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1085 * We switched to a new ruid, so decrement the count of procs running
1086 * under the previous ruid
1088 (void)chgproccnt(my_pcred
->cr_ruid
, -1);
1093 /* drop old proc reference or our extra reference */
1094 kauth_cred_unref(&my_cred
);
1096 set_security_token(p
);
1104 * Description: Set group ID system call
1106 * Parameters: uap->gid gid to set
1108 * Returns: 0 Success
1109 * suser:EPERM Permission denied
1111 * Notes: If called by a privileged process, this function will set the
1112 * real, effective, and saved gid to the requested value.
1114 * If called from an unprivileged process, but gid is equal to the
1115 * real or saved gid, then the effective gid will be set to the
1116 * requested value, but the real and saved gid will not change.
1118 * If the credential is changed as a result of this call, then we
1119 * flag the process as having set privilege since the last exec.
1121 * As an implementation detail, the effective gid is stored as
1122 * the first element of the supplementary group list, and
1123 * therefore the effective group list may be reordered to keep
1124 * the supplementary group list unchanged.
1127 setgid(proc_t p
, struct setgid_args
*uap
, __unused
int32_t *retval
)
1130 gid_t rgid
= KAUTH_GID_NONE
;
1131 gid_t svgid
= KAUTH_GID_NONE
;
1133 kauth_cred_t my_cred
, my_new_cred
;
1134 posix_cred_t my_pcred
;
1136 DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p
->p_pid
, (p
->p_pptr
? p
->p_pptr
->p_pid
: 0), uap
->gid
);
1139 AUDIT_ARG(gid
, gid
);
1141 /* get current credential and take a reference while we muck with it */
1142 my_cred
= kauth_cred_proc_ref(p
);
1143 my_pcred
= posix_cred_get(my_cred
);
1146 if (gid
!= my_pcred
->cr_rgid
&& /* allow setgid(getgid()) */
1147 gid
!= my_pcred
->cr_svgid
&& /* allow setgid(saved gid) */
1148 (error
= suser(my_cred
, &p
->p_acflag
))) {
1149 kauth_cred_unref(&my_cred
);
1154 * If we are privileged, then set the saved and real GID too;
1155 * otherwise, just set the effective GID
1157 if (suser(my_cred
, &p
->p_acflag
) == 0) {
1161 svgid
= KAUTH_GID_NONE
;
1162 rgid
= KAUTH_GID_NONE
;
1166 * Set the credential with new info. If there is no change,
1167 * we get back the same credential we passed in; if there is
1168 * a change, we drop the reference on the credential we
1169 * passed in. The subsequent compare is safe, because it is
1170 * a pointer compare rather than a contents compare.
1172 my_new_cred
= kauth_cred_setresgid(my_cred
, rgid
, gid
, svgid
);
1173 if (my_cred
!= my_new_cred
) {
1174 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
);
1178 * We need to protect for a race where another thread
1179 * also changed the credential after we took our
1180 * reference. If p_ucred has changed then we
1181 * should restart this again with the new cred.
1183 if (p
->p_ucred
!= my_cred
) {
1184 proc_ucred_unlock(p
);
1185 kauth_cred_unref(&my_new_cred
);
1187 my_cred
= kauth_cred_proc_ref(p
);
1188 my_pcred
= posix_cred_get(my_cred
);
1191 p
->p_ucred
= my_new_cred
;
1192 /* update cred on proc */
1193 PROC_UPDATE_CREDS_ONPROC(p
);
1194 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1195 proc_ucred_unlock(p
);
1199 /* Drop old proc reference or our extra reference */
1200 kauth_cred_unref(&my_cred
);
1202 set_security_token(p
);
1210 * Description: Set effective group ID system call
1212 * Parameters: uap->egid effective gid to set
1214 * Returns: 0 Success
1217 * Notes: If called by a privileged process, or called from an
1218 * unprivileged process but egid is equal to the real or saved
1219 * gid, then the effective gid will be set to the requested
1220 * value, but the real and saved gid will not change.
1222 * If the credential is changed as a result of this call, then we
1223 * flag the process as having set privilege since the last exec.
1225 * As an implementation detail, the effective gid is stored as
1226 * the first element of the supplementary group list, and
1227 * therefore the effective group list may be reordered to keep
1228 * the supplementary group list unchanged.
1231 setegid(proc_t p
, struct setegid_args
*uap
, __unused
int32_t *retval
)
1235 kauth_cred_t my_cred
, my_new_cred
;
1236 posix_cred_t my_pcred
;
1238 DEBUG_CRED_ENTER("setegid %d\n", uap
->egid
);
1241 AUDIT_ARG(egid
, egid
);
1243 /* get current credential and take a reference while we muck with it */
1244 my_cred
= kauth_cred_proc_ref(p
);
1245 my_pcred
= posix_cred_get(my_cred
);
1249 if (egid
!= my_pcred
->cr_rgid
&&
1250 egid
!= my_pcred
->cr_svgid
&&
1251 (error
= suser(my_cred
, &p
->p_acflag
))) {
1252 kauth_cred_unref(&my_cred
);
1256 * Set the credential with new info. If there is no change,
1257 * we get back the same credential we passed in; if there is
1258 * a change, we drop the reference on the credential we
1259 * passed in. The subsequent compare is safe, because it is
1260 * a pointer compare rather than a contents compare.
1262 my_new_cred
= kauth_cred_setresgid(my_cred
, KAUTH_GID_NONE
, egid
, KAUTH_GID_NONE
);
1263 if (my_cred
!= my_new_cred
) {
1264 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
);
1268 * We need to protect for a race where another thread
1269 * also changed the credential after we took our
1270 * reference. If p_ucred has changed then we
1271 * should restart this again with the new cred.
1273 if (p
->p_ucred
!= my_cred
) {
1274 proc_ucred_unlock(p
);
1275 kauth_cred_unref(&my_new_cred
);
1277 my_cred
= kauth_cred_proc_ref(p
);
1278 my_pcred
= posix_cred_get(my_cred
);
1281 p
->p_ucred
= my_new_cred
;
1282 /* update cred on proc */
1283 PROC_UPDATE_CREDS_ONPROC(p
);
1284 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1285 proc_ucred_unlock(p
);
1290 /* Drop old proc reference or our extra reference */
1291 kauth_cred_unref(&my_cred
);
1293 set_security_token(p
);
1300 * Description: Set real and effective group ID system call
1302 * Parameters: uap->rgid real gid to set
1303 * uap->egid effective gid to set
1305 * Returns: 0 Success
1306 * suser:EPERM Permission denied
1308 * Notes: A value of -1 is a special case indicating that the gid for
1309 * which that value is specified not be changed. If both values
1310 * are specified as -1, no action is taken.
1312 * If called by a privileged process, the real and effective gid
1313 * will be set to the new value(s) specified.
1315 * If called from an unprivileged process, the real gid may be
1316 * set to the current value of the real gid, or to the current
1317 * value of the saved gid. The effective gid may be set to the
1318 * current value of any of the effective, real, or saved gid.
1320 * If the new real and effective gid will not be equal, or the
1321 * new real or effective gid is not the same as the saved gid,
1322 * then the saved gid will be updated to reflect the new
1323 * effective gid (potentially unrecoverably dropping saved
1326 * If the credential is changed as a result of this call, then we
1327 * flag the process as having set privilege since the last exec.
1329 * As an implementation detail, the effective gid is stored as
1330 * the first element of the supplementary group list, and
1331 * therefore the effective group list may be reordered to keep
1332 * the supplementary group list unchanged.
1335 setregid(proc_t p
, struct setregid_args
*uap
, __unused
int32_t *retval
)
1339 kauth_cred_t my_cred
, my_new_cred
;
1340 posix_cred_t my_pcred
;
1342 DEBUG_CRED_ENTER("setregid %d %d\n", uap
->rgid
, uap
->egid
);
1347 if (rgid
== (uid_t
)-1) {
1348 rgid
= KAUTH_GID_NONE
;
1350 if (egid
== (uid_t
)-1) {
1351 egid
= KAUTH_GID_NONE
;
1353 AUDIT_ARG(egid
, egid
);
1354 AUDIT_ARG(rgid
, rgid
);
1356 /* get current credential and take a reference while we muck with it */
1357 my_cred
= kauth_cred_proc_ref(p
);
1358 my_pcred
= posix_cred_get(my_cred
);
1361 if (((rgid
!= KAUTH_UID_NONE
&& /* allow no change of rgid */
1362 rgid
!= my_pcred
->cr_rgid
&& /* allow rgid = rgid */
1363 rgid
!= my_pcred
->cr_gid
&& /* allow rgid = egid */
1364 rgid
!= my_pcred
->cr_svgid
) || /* allow rgid = svgid */
1365 (egid
!= KAUTH_UID_NONE
&& /* allow no change of egid */
1366 egid
!= my_pcred
->cr_groups
[0] && /* allow no change of egid */
1367 egid
!= my_pcred
->cr_gid
&& /* allow egid = egid */
1368 egid
!= my_pcred
->cr_rgid
&& /* allow egid = rgid */
1369 egid
!= my_pcred
->cr_svgid
)) && /* allow egid = svgid */
1370 (error
= suser(my_cred
, &p
->p_acflag
))) { /* allow root user any */
1371 kauth_cred_unref(&my_cred
);
1375 uid_t new_egid
= my_pcred
->cr_gid
;
1376 uid_t new_rgid
= my_pcred
->cr_rgid
;
1377 uid_t svgid
= KAUTH_UID_NONE
;
1381 * Set the credential with new info. If there is no change,
1382 * we get back the same credential we passed in; if there is
1383 * a change, we drop the reference on the credential we
1384 * passed in. The subsequent compare is safe, because it is
1385 * a pointer compare rather than a contents compare.
1387 if (egid
!= KAUTH_UID_NONE
&& my_pcred
->cr_gid
!= egid
) {
1388 /* changing the effective GID */
1390 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1392 if (rgid
!= KAUTH_UID_NONE
&& my_pcred
->cr_rgid
!= rgid
) {
1393 /* changing the real GID */
1395 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1398 * If the newly requested real gid or effective gid does
1399 * not match the saved gid, then set the saved gid to the
1400 * new effective gid. We are protected from escalation
1401 * by the prechecking.
1403 if (my_pcred
->cr_svgid
!= uap
->rgid
&&
1404 my_pcred
->cr_svgid
!= uap
->egid
) {
1406 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1409 my_new_cred
= kauth_cred_setresgid(my_cred
, rgid
, egid
, svgid
);
1410 if (my_cred
!= my_new_cred
) {
1411 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
);
1414 /* need to protect for a race where another thread
1415 * also changed the credential after we took our
1416 * reference. If p_ucred has changed then we
1417 * should restart this again with the new cred.
1419 if (p
->p_ucred
!= my_cred
) {
1420 proc_ucred_unlock(p
);
1421 kauth_cred_unref(&my_new_cred
);
1423 my_cred
= kauth_cred_proc_ref(p
);
1424 my_pcred
= posix_cred_get(my_cred
);
1427 p
->p_ucred
= my_new_cred
;
1428 /* update cred on proc */
1429 PROC_UPDATE_CREDS_ONPROC(p
);
1430 OSBitOrAtomic(P_SUGID
, &p
->p_flag
); /* XXX redundant? */
1431 proc_ucred_unlock(p
);
1435 /* Drop old proc reference or our extra reference */
1436 kauth_cred_unref(&my_cred
);
1438 set_security_token(p
);
1444 * Set the per-thread override identity. The first parameter can be the
1445 * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
1446 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1447 * means "revert to the per process credential"; otherwise, if permitted,
1448 * it changes the effective, real, and saved UIDs and GIDs for the current
1449 * thread to the requested UID and single GID, and clears all other GIDs.
1452 settid(proc_t p
, struct settid_args
*uap
, __unused
int32_t *retval
)
1455 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1461 AUDIT_ARG(uid
, uid
);
1462 AUDIT_ARG(gid
, gid
);
1464 if (proc_suser(p
) != 0) {
1468 if (uid
== KAUTH_UID_NONE
) {
1469 /* must already be assuming another identity in order to revert back */
1470 if ((uthread
->uu_flag
& UT_SETUID
) == 0) {
1474 /* revert to delayed binding of process credential */
1475 uc
= kauth_cred_proc_ref(p
);
1476 kauth_cred_unref(&uthread
->uu_ucred
);
1477 uthread
->uu_ucred
= uc
;
1478 uthread
->uu_flag
&= ~UT_SETUID
;
1480 kauth_cred_t my_cred
, my_new_cred
;
1482 /* cannot already be assuming another identity */
1483 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1488 * Get a new credential instance from the old if this one
1489 * changes; otherwise kauth_cred_setuidgid() returns the
1490 * same credential. We take an extra reference on the
1491 * current credential while we muck with it, so we can do
1492 * the post-compare for changes by pointer.
1494 kauth_cred_ref(uthread
->uu_ucred
);
1495 my_cred
= uthread
->uu_ucred
;
1496 my_new_cred
= kauth_cred_setuidgid(my_cred
, uid
, gid
);
1497 if (my_cred
!= my_new_cred
) {
1498 uthread
->uu_ucred
= my_new_cred
;
1500 uthread
->uu_flag
|= UT_SETUID
;
1502 /* Drop old uthread reference or our extra reference */
1503 kauth_cred_unref(&my_cred
);
1506 * XXX should potentially set per thread security token (there is
1508 * XXX it is unclear whether P_SUGID should be st at this point;
1509 * XXX in theory, it is being deprecated.
1516 * Set the per-thread override identity. Use this system call for a thread to
1517 * assume the identity of another process or to revert back to normal identity
1518 * of the current process.
1520 * When the "assume" argument is non zero the current thread will assume the
1521 * identity of the process represented by the pid argument.
1523 * When the assume argument is zero we revert back to our normal identity.
1526 settid_with_pid(proc_t p
, struct settid_with_pid_args
*uap
, __unused
int32_t *retval
)
1529 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1530 kauth_cred_t my_cred
, my_target_cred
, my_new_cred
;
1531 posix_cred_t my_target_pcred
;
1533 AUDIT_ARG(pid
, uap
->pid
);
1534 AUDIT_ARG(value32
, uap
->assume
);
1536 if (proc_suser(p
) != 0) {
1541 * XXX should potentially set per thread security token (there is
1543 * XXX it is unclear whether P_SUGID should be st at this point;
1544 * XXX in theory, it is being deprecated.
1548 * assume argument tells us to assume the identity of the process with the
1549 * id passed in the pid argument.
1551 if (uap
->assume
!= 0) {
1552 /* can't do this if we have already assumed an identity */
1553 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1557 target_proc
= proc_find(uap
->pid
);
1558 /* can't assume the identity of the kernel process */
1559 if (target_proc
== NULL
|| target_proc
== kernproc
) {
1560 if (target_proc
!= NULL
) {
1561 proc_rele(target_proc
);
1567 * Take a reference on the credential used in our target
1568 * process then use it as the identity for our current
1569 * thread. We take an extra reference on the current
1570 * credential while we muck with it, so we can do the
1571 * post-compare for changes by pointer.
1573 * The post-compare is needed for the case that our process
1574 * credential has been changed to be identical to our thread
1575 * credential following our assumption of a per-thread one,
1576 * since the credential cache will maintain a unique instance.
1578 kauth_cred_ref(uthread
->uu_ucred
);
1579 my_cred
= uthread
->uu_ucred
;
1580 my_target_cred
= kauth_cred_proc_ref(target_proc
);
1581 my_target_pcred
= posix_cred_get(my_target_cred
);
1582 my_new_cred
= kauth_cred_setuidgid(my_cred
, my_target_pcred
->cr_uid
, my_target_pcred
->cr_gid
);
1583 if (my_cred
!= my_new_cred
) {
1584 uthread
->uu_ucred
= my_new_cred
;
1587 uthread
->uu_flag
|= UT_SETUID
;
1589 /* Drop old uthread reference or our extra reference */
1590 proc_rele(target_proc
);
1591 kauth_cred_unref(&my_cred
);
1592 kauth_cred_unref(&my_target_cred
);
1598 * Otherwise, we are reverting back to normal mode of operation where
1599 * delayed binding of the process credential sets the credential in
1600 * the thread (uu_ucred)
1602 if ((uthread
->uu_flag
& UT_SETUID
) == 0) {
1606 /* revert to delayed binding of process credential */
1607 my_new_cred
= kauth_cred_proc_ref(p
);
1608 kauth_cred_unref(&uthread
->uu_ucred
);
1609 uthread
->uu_ucred
= my_new_cred
;
1610 uthread
->uu_flag
&= ~UT_SETUID
;
1619 * Description: Internal implementation for both the setgroups and initgroups
1622 * Parameters: gidsetsize Number of groups in set
1623 * gidset Pointer to group list
1624 * gmuid Base gid (initgroups only!)
1626 * Returns: 0 Success
1627 * suser:EPERM Permision denied
1628 * EINVAL Invalid gidsetsize value
1629 * copyin:EFAULT Bad gidset or gidsetsize is
1632 * Notes: When called from a thread running under an assumed per-thread
1633 * identity, this function will operate against the per-thread
1634 * credential, rather than against the process credential. In
1635 * this specific case, the process credential is verified to
1636 * still be privileged at the time of the call, rather than the
1637 * per-thread credential for this operation to be permitted.
1639 * This effectively means that setgroups/initigroups calls in
1640 * a thread running a per-thread credential should occur *after*
1641 * the settid call that created it, not before (unlike setuid,
1642 * which must be called after, since it will result in privilege
1645 * When called normally (i.e. no per-thread assumed identity),
1646 * the per process credential is updated per POSIX.
1648 * If the credential is changed as a result of this call, then we
1649 * flag the process as having set privilege since the last exec.
1652 setgroups1(proc_t p
, u_int ngrp
, user_addr_t gidset
, uid_t gmuid
, __unused
int32_t *retval
)
1654 gid_t newgroups
[NGROUPS
] = { 0 };
1657 DEBUG_CRED_ENTER("setgroups1 (%d/%d): %d 0x%016x %d\n", p
->p_pid
,
1658 (p
->p_pptr
? p
->p_pptr
->p_pid
: 0), ngrp
, gidset
, gmuid
);
1660 if (ngrp
> NGROUPS
) {
1665 error
= copyin(gidset
,
1666 (caddr_t
)newgroups
, ngrp
* sizeof(gid_t
));
1671 return setgroups_internal(p
, ngrp
, newgroups
, gmuid
);
1675 setgroups_internal(proc_t p
, u_int ngrp
, gid_t
*newgroups
, uid_t gmuid
)
1677 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1678 kauth_cred_t my_cred
, my_new_cred
;
1681 my_cred
= kauth_cred_proc_ref(p
);
1682 if ((error
= suser(my_cred
, &p
->p_acflag
))) {
1683 kauth_cred_unref(&my_cred
);
1692 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1694 int my_cred_flags
= uthread
->uu_ucred
->cr_flags
;
1695 #endif /* DEBUG_CRED */
1696 kauth_cred_unref(&my_cred
);
1699 * If this thread is under an assumed identity, set the
1700 * supplementary grouplist on the thread credential instead
1701 * of the process one. If we were the only reference holder,
1702 * the credential is updated in place, otherwise, our reference
1703 * is dropped and we get back a different cred with a reference
1704 * already held on it. Because this is per-thread, we don't
1705 * need the referencing/locking/retry required for per-process.
1707 my_cred
= uthread
->uu_ucred
;
1708 uthread
->uu_ucred
= kauth_cred_setgroups(my_cred
, &newgroups
[0], ngrp
, gmuid
);
1710 if (my_cred
!= uthread
->uu_ucred
) {
1711 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
);
1713 #endif /* DEBUG_CRED */
1716 * get current credential and take a reference while we muck
1721 * Set the credential with new info. If there is no
1722 * change, we get back the same credential we passed
1723 * in; if there is a change, we drop the reference on
1724 * the credential we passed in. The subsequent
1725 * compare is safe, because it is a pointer compare
1726 * rather than a contents compare.
1728 my_new_cred
= kauth_cred_setgroups(my_cred
, &newgroups
[0], ngrp
, gmuid
);
1729 if (my_cred
!= my_new_cred
) {
1730 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
);
1734 * We need to protect for a race where another
1735 * thread also changed the credential after we
1736 * took our reference. If p_ucred has
1737 * changed then we should restart this again
1738 * with the new cred.
1740 if (p
->p_ucred
!= my_cred
) {
1741 proc_ucred_unlock(p
);
1742 kauth_cred_unref(&my_new_cred
);
1743 my_cred
= kauth_cred_proc_ref(p
);
1747 p
->p_ucred
= my_new_cred
;
1748 /* update cred on proc */
1749 PROC_UPDATE_CREDS_ONPROC(p
);
1750 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1751 proc_ucred_unlock(p
);
1755 /* Drop old proc reference or our extra reference */
1756 AUDIT_ARG(groupset
, posix_cred_get(my_cred
)->cr_groups
, ngrp
);
1757 kauth_cred_unref(&my_cred
);
1760 set_security_token(p
);
1770 * Description: Initialize the default supplementary groups list and set the
1771 * gmuid for use by the external group resolver (if any)
1773 * Parameters: uap->gidsetsize Number of groups in set
1774 * uap->gidset Pointer to group list
1775 * uap->gmuid Base gid
1777 * Returns: 0 Success
1778 * setgroups1:EPERM Permision denied
1779 * setgroups1:EINVAL Invalid gidsetsize value
1780 * setgroups1:EFAULT Bad gidset or gidsetsize is
1782 * Notes: This function opts *IN* to memberd participation
1784 * The normal purpose of this function is for a privileged
1785 * process to indicate supplementary groups and identity for
1786 * participation in extended group membership resolution prior
1787 * to dropping privilege by assuming a specific user identity.
1789 * It is the first half of the primary mechanism whereby user
1790 * identity is established to the system by programs such as
1791 * /usr/bin/login. The second half is the drop of uid privilege
1792 * for a specific uid corresponding to the user.
1794 * See also: setgroups1()
1797 initgroups(proc_t p
, struct initgroups_args
*uap
, __unused
int32_t *retval
)
1799 DEBUG_CRED_ENTER("initgroups\n");
1801 return setgroups1(p
, uap
->gidsetsize
, uap
->gidset
, uap
->gmuid
, retval
);
1808 * Description: Initialize the default supplementary groups list
1810 * Parameters: gidsetsize Number of groups in set
1811 * gidset Pointer to group list
1813 * Returns: 0 Success
1814 * setgroups1:EPERM Permision denied
1815 * setgroups1:EINVAL Invalid gidsetsize value
1816 * setgroups1:EFAULT Bad gidset or gidsetsize is
1818 * Notes: This functions opts *OUT* of memberd participation.
1820 * This function exists for compatibility with POSIX. Most user
1821 * programs should use initgroups() instead to ensure correct
1822 * participation in group membership resolution when utilizing
1823 * a directory service for authentication.
1825 * It is identical to an initgroups() call with a gmuid argument
1826 * of KAUTH_UID_NONE.
1828 * See also: setgroups1()
1831 setgroups(proc_t p
, struct setgroups_args
*uap
, __unused
int32_t *retval
)
1833 DEBUG_CRED_ENTER("setgroups\n");
1835 return setgroups1(p
, uap
->gidsetsize
, uap
->gidset
, KAUTH_UID_NONE
, retval
);
1840 * Set the per-thread/per-process supplementary groups list.
1842 * XXX implement setsgroups
1847 setsgroups(__unused proc_t p
, __unused
struct setsgroups_args
*uap
, __unused
int32_t *retval
)
1853 * Set the per-thread/per-process whiteout groups list.
1855 * XXX implement setwgroups
1860 setwgroups(__unused proc_t p
, __unused
struct setwgroups_args
*uap
, __unused
int32_t *retval
)
1867 * Check if gid is a member of the group set.
1869 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1873 groupmember(gid_t gid
, kauth_cred_t cred
)
1877 if (kauth_cred_ismember_gid(cred
, gid
, &is_member
) == 0 && is_member
) {
1885 * Test whether the specified credentials imply "super-user"
1886 * privilege; if so, and we have accounting info, set the flag
1887 * indicating use of super-powers.
1888 * Returns 0 or error.
1890 * XXX This interface is going away; use kauth_cred_issuser() directly
1893 * Note: This interface exists to implement the "has used privilege"
1894 * bit (ASU) in the p_acflags field of the process, which is
1895 * only externalized via private sysctl and in process accounting
1896 * records. The flag is technically not required in either case.
1899 suser(kauth_cred_t cred
, u_short
*acflag
)
1902 if (!IS_VALID_CRED(cred
)) {
1906 if (kauth_cred_getuid(cred
) == 0) {
1919 * Description: Get login name, if available.
1921 * Parameters: uap->namebuf User buffer for return
1922 * uap->namelen User buffer length
1924 * Returns: 0 Success
1927 * Notes: Intended to obtain a string containing the user name of the
1928 * user associated with the controlling terminal for the calling
1931 * Not very useful on modern systems, due to inherent length
1932 * limitations for the static array in the session structure
1933 * which is used to store the login name.
1935 * Permitted to return NULL
1937 * XXX: Belongs in kern_proc.c
1940 getlogin(proc_t p
, struct getlogin_args
*uap
, __unused
int32_t *retval
)
1942 char buffer
[MAXLOGNAME
+ 1];
1943 struct session
* sessp
;
1945 bzero(buffer
, MAXLOGNAME
+ 1);
1947 sessp
= proc_session(p
);
1949 if (uap
->namelen
> MAXLOGNAME
) {
1950 uap
->namelen
= MAXLOGNAME
;
1953 if (sessp
!= SESSION_NULL
) {
1954 session_lock(sessp
);
1955 bcopy( sessp
->s_login
, buffer
, uap
->namelen
);
1956 session_unlock(sessp
);
1958 session_rele(sessp
);
1960 return copyout((caddr_t
)buffer
, uap
->namebuf
, uap
->namelen
);
1964 setlogin_internal(proc_t p
, const char login
[static MAXLOGNAME
])
1966 struct session
*sessp
= proc_session(p
);
1968 if (sessp
!= SESSION_NULL
) {
1969 session_lock(sessp
);
1970 bcopy(login
, sessp
->s_login
, MAXLOGNAME
);
1971 session_unlock(sessp
);
1972 session_rele(sessp
);
1979 * Description: Set login name.
1981 * Parameters: uap->namebuf User buffer containing name
1983 * Returns: 0 Success
1984 * suser:EPERM Permission denied
1985 * copyinstr:EFAULT User buffer invalid
1986 * copyinstr:EINVAL Supplied name was too long
1988 * Notes: This is a utility system call to support getlogin().
1990 * XXX: Belongs in kern_proc.c
1993 setlogin(proc_t p
, struct setlogin_args
*uap
, __unused
int32_t *retval
)
1997 char buffer
[MAXLOGNAME
+ 1];
1999 if ((error
= proc_suser(p
))) {
2003 bzero(&buffer
[0], MAXLOGNAME
+ 1);
2006 error
= copyinstr(uap
->namebuf
,
2007 (caddr_t
) &buffer
[0],
2008 MAXLOGNAME
- 1, (size_t *)&dummy
);
2010 setlogin_internal(p
, buffer
);
2013 AUDIT_ARG(text
, buffer
);
2014 } else if (error
== ENAMETOOLONG
) {
2021 /* Set the secrity token of the task with current euid and eguid */
2023 * XXX This needs to change to give the task a reference and/or an opaque
2027 set_security_token(proc_t p
)
2029 return set_security_token_task_internal(p
, p
->task
);
2033 proc_calc_audit_token(proc_t p
, kauth_cred_t my_cred
, audit_token_t
*audit_token
)
2035 posix_cred_t my_pcred
= posix_cred_get(my_cred
);
2038 * The current layout of the Mach audit token explicitly
2039 * adds these fields. But nobody should rely on such
2040 * a literal representation. Instead, the BSM library
2041 * provides a function to convert an audit token into
2042 * a BSM subject. Use of that mechanism will isolate
2043 * the user of the trailer from future representation
2046 audit_token
->val
[0] = my_cred
->cr_audit
.as_aia_p
->ai_auid
;
2047 audit_token
->val
[1] = my_pcred
->cr_uid
;
2048 audit_token
->val
[2] = my_pcred
->cr_gid
;
2049 audit_token
->val
[3] = my_pcred
->cr_ruid
;
2050 audit_token
->val
[4] = my_pcred
->cr_rgid
;
2051 audit_token
->val
[5] = p
->p_pid
;
2052 audit_token
->val
[6] = my_cred
->cr_audit
.as_aia_p
->ai_asid
;
2053 audit_token
->val
[7] = p
->p_idversion
;
2057 * Set the secrity token of the task with current euid and eguid
2058 * The function takes a proc and a task, where proc->task might point to a
2059 * different task if called from exec.
2063 set_security_token_task_internal(proc_t p
, void *t
)
2065 kauth_cred_t my_cred
;
2066 security_token_t sec_token
;
2067 audit_token_t audit_token
;
2068 host_priv_t host_priv
;
2072 * Don't allow a vfork child to override the parent's token settings
2073 * (since they share a task). Instead, the child will just have to
2074 * suffer along using the parent's token until the exec(). It's all
2075 * undefined behavior anyway, right?
2077 if (task
== current_task()) {
2079 uthread
= (uthread_t
)get_bsdthread_info(current_thread());
2080 if (uthread
->uu_flag
& UT_VFORK
) {
2085 my_cred
= kauth_cred_proc_ref(p
);
2087 proc_calc_audit_token(p
, my_cred
, &audit_token
);
2089 /* XXX mach_init doesn't have a p_ucred when it calls this function */
2090 if (IS_VALID_CRED(my_cred
)) {
2091 sec_token
.val
[0] = kauth_cred_getuid(my_cred
);
2092 sec_token
.val
[1] = kauth_cred_getgid(my_cred
);
2094 sec_token
.val
[0] = 0;
2095 sec_token
.val
[1] = 0;
2098 host_priv
= (sec_token
.val
[0]) ? HOST_PRIV_NULL
: host_priv_self();
2100 if (host_priv
!= HOST_PRIV_NULL
&& mac_system_check_host_priv(my_cred
)) {
2101 host_priv
= HOST_PRIV_NULL
;
2104 kauth_cred_unref(&my_cred
);
2106 #if DEVELOPMENT || DEBUG
2108 * Update the pid an proc name for importance base if any
2110 task_importance_update_owner_info(task
);
2113 return host_security_set_task_token(host_security_self(),
2117 host_priv
) != KERN_SUCCESS
;
2121 proc_parent_audit_token(proc_t p
, audit_token_t
*token_out
)
2124 kauth_cred_t my_cred
;
2129 my_cred
= kauth_cred_proc_ref(parent
);
2130 proc_calc_audit_token(parent
, my_cred
, token_out
);
2131 kauth_cred_unref(&my_cred
);
2137 int get_audit_token_pid(audit_token_t
*audit_token
);
2140 get_audit_token_pid(audit_token_t
*audit_token
)
2142 /* keep in-sync with set_security_token (above) */
2144 return (int)audit_token
->val
[5];
2151 * Fill in a struct xucred based on a kauth_cred_t.
2155 cru2x(kauth_cred_t cr
, struct xucred
*xcr
)
2157 posix_cred_t pcr
= posix_cred_get(cr
);
2159 bzero(xcr
, sizeof(*xcr
));
2160 xcr
->cr_version
= XUCRED_VERSION
;
2161 xcr
->cr_uid
= kauth_cred_getuid(cr
);
2162 xcr
->cr_ngroups
= pcr
->cr_ngroups
;
2163 bcopy(pcr
->cr_groups
, xcr
->cr_groups
, sizeof(xcr
->cr_groups
));