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
123 * We don't use kauth_cred_print() in current debugging, but it
124 * can be used if needed when debugging is active.
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 */
135 #if DEVELOPMENT || DEBUG
136 extern void task_importance_update_owner_info(task_t
);
143 * Description: (dis)allow this process to hold task, thread, or execption
144 * ports of processes about to exec.
146 * Parameters: uap->flag New value for flag
148 * Returns: int Previous value of flag
150 * XXX: Belongs in kern_proc.c
153 setprivexec(proc_t p
, struct setprivexec_args
*uap
, int32_t *retval
)
155 AUDIT_ARG(value32
, uap
->flag
);
156 *retval
= p
->p_debugger
;
157 p
->p_debugger
= (uap
->flag
!= 0);
165 * Description: get the process ID
169 * Returns: pid_t Current process ID
171 * XXX: Belongs in kern_proc.c
174 getpid(proc_t p
, __unused
struct getpid_args
*uap
, int32_t *retval
)
185 * Description: get the parent process ID
189 * Returns: pid_t Parent process ID
191 * XXX: Belongs in kern_proc.c
194 getppid(proc_t p
, __unused
struct getppid_args
*uap
, int32_t *retval
)
205 * Description: get the process group ID of the calling process
209 * Returns: pid_t Process group ID
211 * XXX: Belongs in kern_proc.c
214 getpgrp(proc_t p
, __unused
struct getpgrp_args
*uap
, int32_t *retval
)
217 *retval
= p
->p_pgrpid
;
225 * Description: Get an arbitary pid's process group id
227 * Parameters: uap->pid The target pid
230 * ESRCH No such process
232 * Notes: We are permitted to return EPERM in the case that the target
233 * process is not in the same session as the calling process,
234 * which could be a security consideration
236 * XXX: Belongs in kern_proc.c
239 getpgid(proc_t p
, struct getpgid_args
*uap
, int32_t *retval
)
248 if ((pt
= proc_find(uap
->pid
)) == 0)
252 *retval
= pt
->p_pgrpid
;
262 * Description: Get an arbitary pid's session leaders process group ID
264 * Parameters: uap->pid The target pid
267 * ESRCH No such process
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
273 * XXX: Belongs in kern_proc.c
276 getsid(proc_t p
, struct getsid_args
*uap
, int32_t *retval
)
280 struct session
* sessp
;
286 if ((pt
= proc_find(uap
->pid
)) == 0)
290 sessp
= proc_session(pt
);
291 *retval
= sessp
->s_sid
;
303 * Description: get real user ID for caller
307 * Returns: uid_t The real uid of the caller
310 getuid(__unused proc_t p
, __unused
struct getuid_args
*uap
, int32_t *retval
)
313 *retval
= kauth_getruid();
321 * Description: get effective user ID for caller
325 * Returns: uid_t The effective uid of the caller
328 geteuid(__unused proc_t p
, __unused
struct geteuid_args
*uap
, int32_t *retval
)
331 *retval
= kauth_getuid();
339 * Description: Return the per-thread override identity.
341 * Parameters: uap->uidp Address of uid_t to get uid
342 * uap->gidp Address of gid_t to get gid
345 * ESRCH No per thread identity active
348 gettid(__unused proc_t p
, struct gettid_args
*uap
, int32_t *retval
)
350 struct uthread
*uthread
= get_bsdthread_info(current_thread());
354 * If this thread is not running with an override identity, we can't
355 * return one to the caller, so return an error instead.
357 if (!(uthread
->uu_flag
& UT_SETUID
))
360 if ((error
= suword(uap
->uidp
, kauth_cred_getruid(uthread
->uu_ucred
))))
362 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
)
383 *retval
= kauth_getrgid();
391 * Description: get the effective group ID for the calling process
395 * Returns: gid_t The effective gid of the caller
397 * Notes: As an implementation detail, the effective gid is stored as
398 * the first element of the supplementary group list.
400 * This could be implemented in Libc instead because of the above
404 getegid(__unused proc_t p
, __unused
struct getegid_args
*uap
, int32_t *retval
)
407 *retval
= kauth_getgid();
415 * Description: get the list of supplementary groups for the calling process
417 * Parameters: uap->gidsetsize # of gid_t's in user buffer
418 * uap->gidset Pointer to user buffer
421 * EINVAL User buffer too small
422 * copyout:EFAULT User buffer invalid
427 * Notes: The caller may specify a 0 value for gidsetsize, and we will
428 * then return how large a buffer is required (in gid_t's) to
429 * contain the answer at the time of the call. Otherwise, we
430 * return the number of gid_t's catually copied to user space.
432 * When called with a 0 gidsetsize from a multithreaded program,
433 * there is no guarantee that another thread may not change the
434 * number of supplementary groups, and therefore a subsequent
435 * call could still fail, unless the maximum possible buffer
436 * size is supplied by the user.
438 * As an implementation detail, the effective gid is stored as
439 * the first element of the supplementary group list, and will
440 * be returned by this call.
443 getgroups(__unused proc_t p
, struct getgroups_args
*uap
, int32_t *retval
)
450 /* grab reference while we muck around with the credential */
451 cred
= kauth_cred_get_with_ref();
452 pcred
= posix_cred_get(cred
);
454 if ((ngrp
= uap
->gidsetsize
) == 0) {
455 *retval
= pcred
->cr_ngroups
;
456 kauth_cred_unref(&cred
);
459 if (ngrp
< pcred
->cr_ngroups
) {
460 kauth_cred_unref(&cred
);
463 ngrp
= pcred
->cr_ngroups
;
464 if ((error
= copyout((caddr_t
)pcred
->cr_groups
,
466 ngrp
* sizeof(gid_t
)))) {
467 kauth_cred_unref(&cred
);
470 kauth_cred_unref(&cred
);
477 * Return the per-thread/per-process supplementary groups list.
479 * XXX implement getsgroups
484 getsgroups(__unused proc_t p
, __unused
struct getsgroups_args
*uap
, __unused
int32_t *retval
)
490 * Return the per-thread/per-process whiteout groups list.
492 * XXX implement getwgroups
497 getwgroups(__unused proc_t p
, __unused
struct getwgroups_args
*uap
, __unused
int32_t *retval
)
506 * Description: Create a new session and set the process group ID to the
512 * EPERM Permission denied
514 * Notes: If the calling process is not the process group leader; there
515 * is no existing process group with its ID, and we are not
516 * currently in vfork, then this function will create a new
517 * session, a new process group, and put the caller in the
518 * process group (as the sole member) and make it the session
519 * leader (as the sole process in the session).
521 * The existing controlling tty (if any) will be dissociated
522 * from the process, and the next non-O_NOCTTY open of a tty
523 * will establish a new controlling tty.
525 * XXX: Belongs in kern_proc.c
528 setsid(proc_t p
, __unused
struct setsid_args
*uap
, int32_t *retval
)
530 struct pgrp
* pg
= PGRP_NULL
;
532 if (p
->p_pgrpid
== p
->p_pid
|| (pg
= pgfind(p
->p_pid
)) || p
->p_lflag
& P_LINVFORK
) {
537 /* enter pgrp works with its own pgrp refcount */
538 (void)enterpgrp(p
, p
->p_pid
, 1);
548 * Description: set process group ID for job control
550 * Parameters: uap->pid Process to change
551 * uap->pgid Process group to join or create
554 * ESRCH pid is not the caller or a child of
556 * enterpgrp:ESRCH No such process
557 * EACCES Permission denied due to exec
558 * EINVAL Invalid argument
559 * EPERM The target process is not in the same
560 * session as the calling process
561 * EPERM The target process is a session leader
562 * EPERM pid and pgid are not the same, and
563 * there is no process in the calling
564 * process whose process group ID matches
567 * Notes: This function will cause the target process to either join
568 * an existing process process group, or create a new process
569 * group in the session of the calling process. It cannot be
570 * used to change the process group ID of a process which is
571 * already a session leader.
573 * If the target pid is 0, the pid of the calling process is
574 * substituted as the new target; if pgid is 0, the target pid
575 * is used as the target process group ID.
577 * Legacy: This system call entry point is also used to implement the
578 * legacy library routine setpgrp(), which under POSIX
580 * XXX: Belongs in kern_proc.c
583 setpgid(proc_t curp
, struct setpgid_args
*uap
, __unused
int32_t *retval
)
585 proc_t targp
= PROC_NULL
; /* target process */
586 struct pgrp
*pg
= PGRP_NULL
; /* target pgrp */
590 struct session
* curp_sessp
= SESSION_NULL
;
591 struct session
* targp_sessp
= SESSION_NULL
;
593 curp_sessp
= proc_session(curp
);
595 if (uap
->pid
!= 0 && uap
->pid
!= curp
->p_pid
) {
596 if ((targp
= proc_find(uap
->pid
)) == 0 || !inferior(targp
)) {
597 if (targp
!= PROC_NULL
)
603 targp_sessp
= proc_session(targp
);
604 if (targp_sessp
!= curp_sessp
) {
608 if (targp
->p_flag
& P_EXEC
) {
614 targp_sessp
= proc_session(targp
);
617 if (SESS_LEADER(targp
, targp_sessp
)) {
621 if (targp_sessp
!= SESSION_NULL
) {
622 session_rele(targp_sessp
);
623 targp_sessp
= SESSION_NULL
;
631 uap
->pgid
= targp
->p_pid
;
632 else if (uap
->pgid
!= targp
->p_pid
) {
633 if ((pg
= pgfind(uap
->pgid
)) == 0){
637 samesess
= (pg
->pg_session
!= curp_sessp
);
644 error
= enterpgrp(targp
, uap
->pgid
, 0);
646 if (targp_sessp
!= SESSION_NULL
)
647 session_rele(targp_sessp
);
648 if (curp_sessp
!= SESSION_NULL
)
649 session_rele(curp_sessp
);
659 * Description: Is current process tainted by uid or gid changes system call
663 * Returns: 0 Not tainted
666 * Notes: A process is considered tainted if it was created as a retult
667 * of an execve call from an imnage that had either the SUID or
668 * SGID bit set on the executable, or if it has changed any of its
669 * real, effective, or saved user or group IDs since beginning
673 issetugid(proc_t p
, __unused
struct issetugid_args
*uap
, int32_t *retval
)
676 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
677 * we use P_SUGID because we consider changing the owners as
678 * "tainting" as well.
679 * This is significant for procs that start as root and "become"
680 * a user without an exec - programs cannot know *everything*
681 * that libc *might* have put in their data segment.
684 *retval
= (p
->p_flag
& P_SUGID
) ? 1 : 0;
692 * Description: Set user ID system call
694 * Parameters: uap->uid uid to set
697 * suser:EPERM Permission denied
699 * Notes: If called by a privileged process, this function will set the
700 * real, effective, and saved uid to the requested value.
702 * If called from an unprivileged process, but uid is equal to the
703 * real or saved uid, then the effective uid will be set to the
704 * requested value, but the real and saved uid will not change.
706 * If the credential is changed as a result of this call, then we
707 * flag the process as having set privilege since the last exec.
710 setuid(proc_t p
, struct setuid_args
*uap
, __unused
int32_t *retval
)
713 uid_t svuid
= KAUTH_UID_NONE
;
714 uid_t ruid
= KAUTH_UID_NONE
;
715 uid_t gmuid
= KAUTH_UID_NONE
;
717 kauth_cred_t my_cred
, my_new_cred
;
718 posix_cred_t my_pcred
;
722 /* get current credential and take a reference while we muck with it */
723 my_cred
= kauth_cred_proc_ref(p
);
724 my_pcred
= posix_cred_get(my_cred
);
726 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
);
730 if (uid
!= my_pcred
->cr_ruid
&& /* allow setuid(getuid()) */
731 uid
!= my_pcred
->cr_svuid
&& /* allow setuid(saved uid) */
732 (error
= suser(my_cred
, &p
->p_acflag
))) {
733 kauth_cred_unref(&my_cred
);
738 * If we are privileged, then set the saved and real UID too;
739 * otherwise, just set the effective UID
741 if (suser(my_cred
, &p
->p_acflag
) == 0) {
745 svuid
= KAUTH_UID_NONE
;
746 ruid
= KAUTH_UID_NONE
;
749 * Only set the gmuid if the current cred has not opt'ed out;
750 * this normally only happens when calling setgroups() instead
751 * of initgroups() to set an explicit group list, or one of the
752 * other group manipulation functions is invoked and results in
753 * a dislocation (i.e. the credential group membership changes
754 * to something other than the default list for the user, as
755 * in entering a group or leaving an exclusion group).
757 if (!(my_pcred
->cr_flags
& CRF_NOMEMBERD
))
761 * Set the credential with new info. If there is no change,
762 * we get back the same credential we passed in; if there is
763 * a change, we drop the reference on the credential we
764 * passed in. The subsequent compare is safe, because it is
765 * a pointer compare rather than a contents compare.
767 my_new_cred
= kauth_cred_setresuid(my_cred
, ruid
, uid
, svuid
, gmuid
);
768 if (my_cred
!= my_new_cred
) {
770 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
);
773 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
774 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
775 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
776 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
777 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
778 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
780 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
781 (void)chgproccnt(ruid
, 1);
786 * We need to protect for a race where another thread
787 * also changed the credential after we took our
788 * reference. If p_ucred has changed then we should
789 * restart this again with the new cred.
791 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
793 if (p
->p_ucred
!= my_cred
) {
794 proc_ucred_unlock(p
);
796 * We didn't successfully switch to the new ruid, so decrement
797 * the procs/uid count that we incremented above.
799 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
800 (void)chgproccnt(ruid
, -1);
802 kauth_cred_unref(&my_new_cred
);
803 my_cred
= kauth_cred_proc_ref(p
);
804 my_pcred
= posix_cred_get(my_cred
);
808 p
->p_ucred
= my_new_cred
;
809 /* update cred on proc */
810 PROC_UPDATE_CREDS_ONPROC(p
);
812 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
813 proc_ucred_unlock(p
);
815 * If we've updated the ruid, decrement the count of procs running
816 * under the previous ruid
818 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
819 (void)chgproccnt(my_pcred
->cr_ruid
, -1);
824 /* Drop old proc reference or our extra reference */
825 kauth_cred_unref(&my_cred
);
827 set_security_token(p
);
835 * Description: Set effective user ID system call
837 * Parameters: uap->euid effective uid to set
840 * suser:EPERM Permission denied
842 * Notes: If called by a privileged process, or called from an
843 * unprivileged process but euid is equal to the real or saved
844 * uid, then the effective uid will be set to the requested
845 * value, but the real and saved uid will not change.
847 * If the credential is changed as a result of this call, then we
848 * flag the process as having set privilege since the last exec.
851 seteuid(proc_t p
, struct seteuid_args
*uap
, __unused
int32_t *retval
)
855 kauth_cred_t my_cred
, my_new_cred
;
856 posix_cred_t my_pcred
;
858 DEBUG_CRED_ENTER("seteuid: %d\n", uap
->euid
);
861 AUDIT_ARG(euid
, euid
);
863 my_cred
= kauth_cred_proc_ref(p
);
864 my_pcred
= posix_cred_get(my_cred
);
868 if (euid
!= my_pcred
->cr_ruid
&& euid
!= my_pcred
->cr_svuid
&&
869 (error
= suser(my_cred
, &p
->p_acflag
))) {
870 kauth_cred_unref(&my_cred
);
875 * Set the credential with new info. If there is no change,
876 * we get back the same credential we passed in; if there is
877 * a change, we drop the reference on the credential we
878 * passed in. The subsequent compare is safe, because it is
879 * a pointer compare rather than a contents compare.
881 my_new_cred
= kauth_cred_setresuid(my_cred
, KAUTH_UID_NONE
, euid
, KAUTH_UID_NONE
, my_pcred
->cr_gmuid
);
883 if (my_cred
!= my_new_cred
) {
885 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
);
889 * We need to protect for a race where another thread
890 * also changed the credential after we took our
891 * reference. If p_ucred has changed then we
892 * should restart this again with the new cred.
894 if (p
->p_ucred
!= my_cred
) {
895 proc_ucred_unlock(p
);
896 kauth_cred_unref(&my_new_cred
);
897 my_cred
= kauth_cred_proc_ref(p
);
898 my_pcred
= posix_cred_get(my_cred
);
902 p
->p_ucred
= my_new_cred
;
903 /* update cred on proc */
904 PROC_UPDATE_CREDS_ONPROC(p
);
905 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
906 proc_ucred_unlock(p
);
910 /* drop old proc reference or our extra reference */
911 kauth_cred_unref(&my_cred
);
913 set_security_token(p
);
921 * Description: Set real and effective user ID system call
923 * Parameters: uap->ruid real uid to set
924 * uap->euid effective uid to set
927 * suser:EPERM Permission denied
929 * Notes: A value of -1 is a special case indicating that the uid for
930 * which that value is specified not be changed. If both values
931 * are specified as -1, no action is taken.
933 * If called by a privileged process, the real and effective uid
934 * will be set to the new value(s) specified.
936 * If called from an unprivileged process, the real uid may be
937 * set to the current value of the real uid, or to the current
938 * value of the saved uid. The effective uid may be set to the
939 * current value of any of the effective, real, or saved uid.
941 * If the newly requested real uid or effective uid does not
942 * match the saved uid, then set the saved uid to the new
943 * effective uid (potentially unrecoverably dropping saved
946 * If the credential is changed as a result of this call, then we
947 * flag the process as having set privilege since the last exec.
950 setreuid(proc_t p
, struct setreuid_args
*uap
, __unused
int32_t *retval
)
954 kauth_cred_t my_cred
, my_new_cred
;
955 posix_cred_t my_pcred
;
957 DEBUG_CRED_ENTER("setreuid %d %d\n", uap
->ruid
, uap
->euid
);
961 if (ruid
== (uid_t
)-1)
962 ruid
= KAUTH_UID_NONE
;
963 if (euid
== (uid_t
)-1)
964 euid
= KAUTH_UID_NONE
;
965 AUDIT_ARG(euid
, euid
);
966 AUDIT_ARG(ruid
, ruid
);
968 my_cred
= kauth_cred_proc_ref(p
);
969 my_pcred
= posix_cred_get(my_cred
);
973 if (((ruid
!= KAUTH_UID_NONE
&& /* allow no change of ruid */
974 ruid
!= my_pcred
->cr_ruid
&& /* allow ruid = ruid */
975 ruid
!= my_pcred
->cr_uid
&& /* allow ruid = euid */
976 ruid
!= my_pcred
->cr_svuid
) || /* allow ruid = svuid */
977 (euid
!= KAUTH_UID_NONE
&& /* allow no change of euid */
978 euid
!= my_pcred
->cr_uid
&& /* allow euid = euid */
979 euid
!= my_pcred
->cr_ruid
&& /* allow euid = ruid */
980 euid
!= my_pcred
->cr_svuid
)) && /* allow euid = svuid */
981 (error
= suser(my_cred
, &p
->p_acflag
))) { /* allow root user any */
982 kauth_cred_unref(&my_cred
);
987 uid_t svuid
= KAUTH_UID_NONE
;
989 new_euid
= my_pcred
->cr_uid
;
991 * Set the credential with new info. If there is no change,
992 * we get back the same credential we passed in; if there is
993 * a change, we drop the reference on the credential we
994 * passed in. The subsequent compare is safe, because it is
995 * a pointer compare rather than a contents compare.
997 if (euid
!= KAUTH_UID_NONE
&& my_pcred
->cr_uid
!= euid
) {
998 /* changing the effective UID */
1000 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1003 * If the newly requested real uid or effective uid does
1004 * not match the saved uid, then set the saved uid to the
1005 * new effective uid. We are protected from escalation
1006 * by the prechecking.
1008 if (my_pcred
->cr_svuid
!= uap
->ruid
&&
1009 my_pcred
->cr_svuid
!= uap
->euid
) {
1011 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1014 my_new_cred
= kauth_cred_setresuid(my_cred
, ruid
, euid
, svuid
, my_pcred
->cr_gmuid
);
1016 if (my_cred
!= my_new_cred
) {
1018 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
);
1021 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
1022 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
1023 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
1024 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
1025 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
1026 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
1028 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1029 (void)chgproccnt(ruid
, 1);
1034 * We need to protect for a race where another thread
1035 * also changed the credential after we took our
1036 * reference. If p_ucred has changed then we should
1037 * restart this again with the new cred.
1039 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
1041 if (p
->p_ucred
!= my_cred
) {
1042 proc_ucred_unlock(p
);
1043 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1045 * We didn't successfully switch to the new ruid, so decrement
1046 * the procs/uid count that we incremented above.
1048 (void)chgproccnt(ruid
, -1);
1050 kauth_cred_unref(&my_new_cred
);
1051 my_cred
= kauth_cred_proc_ref(p
);
1052 my_pcred
= posix_cred_get(my_cred
);
1057 p
->p_ucred
= my_new_cred
;
1058 /* update cred on proc */
1059 PROC_UPDATE_CREDS_ONPROC(p
);
1060 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1061 proc_ucred_unlock(p
);
1063 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1065 * We switched to a new ruid, so decrement the count of procs running
1066 * under the previous ruid
1068 (void)chgproccnt(my_pcred
->cr_ruid
, -1);
1073 /* drop old proc reference or our extra reference */
1074 kauth_cred_unref(&my_cred
);
1076 set_security_token(p
);
1084 * Description: Set group ID system call
1086 * Parameters: uap->gid gid to set
1088 * Returns: 0 Success
1089 * suser:EPERM Permission denied
1091 * Notes: If called by a privileged process, this function will set the
1092 * real, effective, and saved gid to the requested value.
1094 * If called from an unprivileged process, but gid is equal to the
1095 * real or saved gid, then the effective gid will be set to the
1096 * requested value, but the real and saved gid will not change.
1098 * If the credential is changed as a result of this call, then we
1099 * flag the process as having set privilege since the last exec.
1101 * As an implementation detail, the effective gid is stored as
1102 * the first element of the supplementary group list, and
1103 * therefore the effective group list may be reordered to keep
1104 * the supplementary group list unchanged.
1107 setgid(proc_t p
, struct setgid_args
*uap
, __unused
int32_t *retval
)
1110 gid_t rgid
= KAUTH_GID_NONE
;
1111 gid_t svgid
= KAUTH_GID_NONE
;
1113 kauth_cred_t my_cred
, my_new_cred
;
1114 posix_cred_t my_pcred
;
1116 DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p
->p_pid
, (p
->p_pptr
? p
->p_pptr
->p_pid
: 0), uap
->gid
);
1119 AUDIT_ARG(gid
, gid
);
1121 /* get current credential and take a reference while we muck with it */
1122 my_cred
= kauth_cred_proc_ref(p
);
1123 my_pcred
= posix_cred_get(my_cred
);
1126 if (gid
!= my_pcred
->cr_rgid
&& /* allow setgid(getgid()) */
1127 gid
!= my_pcred
->cr_svgid
&& /* allow setgid(saved gid) */
1128 (error
= suser(my_cred
, &p
->p_acflag
))) {
1129 kauth_cred_unref(&my_cred
);
1134 * If we are privileged, then set the saved and real GID too;
1135 * otherwise, just set the effective GID
1137 if (suser(my_cred
, &p
->p_acflag
) == 0) {
1141 svgid
= KAUTH_GID_NONE
;
1142 rgid
= KAUTH_GID_NONE
;
1146 * Set the credential with new info. If there is no change,
1147 * we get back the same credential we passed in; if there is
1148 * a change, we drop the reference on the credential we
1149 * passed in. The subsequent compare is safe, because it is
1150 * a pointer compare rather than a contents compare.
1152 my_new_cred
= kauth_cred_setresgid(my_cred
, rgid
, gid
, svgid
);
1153 if (my_cred
!= my_new_cred
) {
1155 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
);
1159 * We need to protect for a race where another thread
1160 * also changed the credential after we took our
1161 * reference. If p_ucred has changed then we
1162 * should restart this again with the new cred.
1164 if (p
->p_ucred
!= my_cred
) {
1165 proc_ucred_unlock(p
);
1166 kauth_cred_unref(&my_new_cred
);
1168 my_cred
= kauth_cred_proc_ref(p
);
1169 my_pcred
= posix_cred_get(my_cred
);
1172 p
->p_ucred
= my_new_cred
;
1173 /* update cred on proc */
1174 PROC_UPDATE_CREDS_ONPROC(p
);
1175 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1176 proc_ucred_unlock(p
);
1180 /* Drop old proc reference or our extra reference */
1181 kauth_cred_unref(&my_cred
);
1183 set_security_token(p
);
1191 * Description: Set effective group ID system call
1193 * Parameters: uap->egid effective gid to set
1195 * Returns: 0 Success
1198 * Notes: If called by a privileged process, or called from an
1199 * unprivileged process but egid is equal to the real or saved
1200 * gid, then the effective gid will be set to the requested
1201 * value, but the real and saved gid will not change.
1203 * If the credential is changed as a result of this call, then we
1204 * flag the process as having set privilege since the last exec.
1206 * As an implementation detail, the effective gid is stored as
1207 * the first element of the supplementary group list, and
1208 * therefore the effective group list may be reordered to keep
1209 * the supplementary group list unchanged.
1212 setegid(proc_t p
, struct setegid_args
*uap
, __unused
int32_t *retval
)
1216 kauth_cred_t my_cred
, my_new_cred
;
1217 posix_cred_t my_pcred
;
1219 DEBUG_CRED_ENTER("setegid %d\n", uap
->egid
);
1222 AUDIT_ARG(egid
, egid
);
1224 /* get current credential and take a reference while we muck with it */
1225 my_cred
= kauth_cred_proc_ref(p
);
1226 my_pcred
= posix_cred_get(my_cred
);
1230 if (egid
!= my_pcred
->cr_rgid
&&
1231 egid
!= my_pcred
->cr_svgid
&&
1232 (error
= suser(my_cred
, &p
->p_acflag
))) {
1233 kauth_cred_unref(&my_cred
);
1237 * Set the credential with new info. If there is no change,
1238 * we get back the same credential we passed in; if there is
1239 * a change, we drop the reference on the credential we
1240 * passed in. The subsequent compare is safe, because it is
1241 * a pointer compare rather than a contents compare.
1243 my_new_cred
= kauth_cred_setresgid(my_cred
, KAUTH_GID_NONE
, egid
, KAUTH_GID_NONE
);
1244 if (my_cred
!= my_new_cred
) {
1246 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
);
1250 * We need to protect for a race where another thread
1251 * also changed the credential after we took our
1252 * reference. If p_ucred has changed then we
1253 * should restart this again with the new cred.
1255 if (p
->p_ucred
!= my_cred
) {
1256 proc_ucred_unlock(p
);
1257 kauth_cred_unref(&my_new_cred
);
1259 my_cred
= kauth_cred_proc_ref(p
);
1260 my_pcred
= posix_cred_get(my_cred
);
1263 p
->p_ucred
= my_new_cred
;
1264 /* update cred on proc */
1265 PROC_UPDATE_CREDS_ONPROC(p
);
1266 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1267 proc_ucred_unlock(p
);
1272 /* Drop old proc reference or our extra reference */
1273 kauth_cred_unref(&my_cred
);
1275 set_security_token(p
);
1282 * Description: Set real and effective group ID system call
1284 * Parameters: uap->rgid real gid to set
1285 * uap->egid effective gid to set
1287 * Returns: 0 Success
1288 * suser:EPERM Permission denied
1290 * Notes: A value of -1 is a special case indicating that the gid for
1291 * which that value is specified not be changed. If both values
1292 * are specified as -1, no action is taken.
1294 * If called by a privileged process, the real and effective gid
1295 * will be set to the new value(s) specified.
1297 * If called from an unprivileged process, the real gid may be
1298 * set to the current value of the real gid, or to the current
1299 * value of the saved gid. The effective gid may be set to the
1300 * current value of any of the effective, real, or saved gid.
1302 * If the new real and effective gid will not be equal, or the
1303 * new real or effective gid is not the same as the saved gid,
1304 * then the saved gid will be updated to reflect the new
1305 * effective gid (potentially unrecoverably dropping saved
1308 * If the credential is changed as a result of this call, then we
1309 * flag the process as having set privilege since the last exec.
1311 * As an implementation detail, the effective gid is stored as
1312 * the first element of the supplementary group list, and
1313 * therefore the effective group list may be reordered to keep
1314 * the supplementary group list unchanged.
1317 setregid(proc_t p
, struct setregid_args
*uap
, __unused
int32_t *retval
)
1321 kauth_cred_t my_cred
, my_new_cred
;
1322 posix_cred_t my_pcred
;
1324 DEBUG_CRED_ENTER("setregid %d %d\n", uap
->rgid
, uap
->egid
);
1329 if (rgid
== (uid_t
)-1)
1330 rgid
= KAUTH_GID_NONE
;
1331 if (egid
== (uid_t
)-1)
1332 egid
= KAUTH_GID_NONE
;
1333 AUDIT_ARG(egid
, egid
);
1334 AUDIT_ARG(rgid
, rgid
);
1336 /* get current credential and take a reference while we muck with it */
1337 my_cred
= kauth_cred_proc_ref(p
);
1338 my_pcred
= posix_cred_get(my_cred
);
1342 if (((rgid
!= KAUTH_UID_NONE
&& /* allow no change of rgid */
1343 rgid
!= my_pcred
->cr_rgid
&& /* allow rgid = rgid */
1344 rgid
!= my_pcred
->cr_gid
&& /* allow rgid = egid */
1345 rgid
!= my_pcred
->cr_svgid
) || /* allow rgid = svgid */
1346 (egid
!= KAUTH_UID_NONE
&& /* allow no change of egid */
1347 egid
!= my_pcred
->cr_groups
[0] && /* allow no change of egid */
1348 egid
!= my_pcred
->cr_gid
&& /* allow egid = egid */
1349 egid
!= my_pcred
->cr_rgid
&& /* allow egid = rgid */
1350 egid
!= my_pcred
->cr_svgid
)) && /* allow egid = svgid */
1351 (error
= suser(my_cred
, &p
->p_acflag
))) { /* allow root user any */
1352 kauth_cred_unref(&my_cred
);
1356 uid_t new_egid
= my_pcred
->cr_gid
;
1357 uid_t new_rgid
= my_pcred
->cr_rgid
;
1358 uid_t svgid
= KAUTH_UID_NONE
;
1362 * Set the credential with new info. If there is no change,
1363 * we get back the same credential we passed in; if there is
1364 * a change, we drop the reference on the credential we
1365 * passed in. The subsequent compare is safe, because it is
1366 * a pointer compare rather than a contents compare.
1368 if (egid
!= KAUTH_UID_NONE
&& my_pcred
->cr_gid
!= egid
) {
1369 /* changing the effective GID */
1371 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1373 if (rgid
!= KAUTH_UID_NONE
&& my_pcred
->cr_rgid
!= rgid
) {
1374 /* changing the real GID */
1376 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1379 * If the newly requested real gid or effective gid does
1380 * not match the saved gid, then set the saved gid to the
1381 * new effective gid. We are protected from escalation
1382 * by the prechecking.
1384 if (my_pcred
->cr_svgid
!= uap
->rgid
&&
1385 my_pcred
->cr_svgid
!= uap
->egid
) {
1387 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1390 my_new_cred
= kauth_cred_setresgid(my_cred
, rgid
, egid
, svgid
);
1391 if (my_cred
!= my_new_cred
) {
1393 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
);
1396 /* need to protect for a race where another thread
1397 * also changed the credential after we took our
1398 * reference. If p_ucred has changed then we
1399 * should restart this again with the new cred.
1401 if (p
->p_ucred
!= my_cred
) {
1402 proc_ucred_unlock(p
);
1403 kauth_cred_unref(&my_new_cred
);
1405 my_cred
= kauth_cred_proc_ref(p
);
1406 my_pcred
= posix_cred_get(my_cred
);
1409 p
->p_ucred
= my_new_cred
;
1410 /* update cred on proc */
1411 PROC_UPDATE_CREDS_ONPROC(p
);
1412 OSBitOrAtomic(P_SUGID
, &p
->p_flag
); /* XXX redundant? */
1413 proc_ucred_unlock(p
);
1417 /* Drop old proc reference or our extra reference */
1418 kauth_cred_unref(&my_cred
);
1420 set_security_token(p
);
1426 * Set the per-thread override identity. The first parameter can be the
1427 * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
1428 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1429 * means "revert to the per process credential"; otherwise, if permitted,
1430 * it changes the effective, real, and saved UIDs and GIDs for the current
1431 * thread to the requested UID and single GID, and clears all other GIDs.
1434 settid(proc_t p
, struct settid_args
*uap
, __unused
int32_t *retval
)
1437 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1443 AUDIT_ARG(uid
, uid
);
1444 AUDIT_ARG(gid
, gid
);
1446 if (proc_suser(p
) != 0)
1449 if (uid
== KAUTH_UID_NONE
) {
1451 /* must already be assuming another identity in order to revert back */
1452 if ((uthread
->uu_flag
& UT_SETUID
) == 0)
1455 /* revert to delayed binding of process credential */
1456 uc
= kauth_cred_proc_ref(p
);
1457 kauth_cred_unref(&uthread
->uu_ucred
);
1458 uthread
->uu_ucred
= uc
;
1459 uthread
->uu_flag
&= ~UT_SETUID
;
1461 kauth_cred_t my_cred
, my_new_cred
;
1463 /* cannot already be assuming another identity */
1464 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1469 * Get a new credential instance from the old if this one
1470 * changes; otherwise kauth_cred_setuidgid() returns the
1471 * same credential. We take an extra reference on the
1472 * current credential while we muck with it, so we can do
1473 * the post-compare for changes by pointer.
1475 kauth_cred_ref(uthread
->uu_ucred
);
1476 my_cred
= uthread
->uu_ucred
;
1477 my_new_cred
= kauth_cred_setuidgid(my_cred
, uid
, gid
);
1478 if (my_cred
!= my_new_cred
)
1479 uthread
->uu_ucred
= my_new_cred
;
1480 uthread
->uu_flag
|= UT_SETUID
;
1482 /* Drop old uthread reference or our extra reference */
1483 kauth_cred_unref(&my_cred
);
1486 * XXX should potentially set per thread security token (there is
1488 * XXX it is unclear whether P_SUGID should be st at this point;
1489 * XXX in theory, it is being deprecated.
1496 * Set the per-thread override identity. Use this system call for a thread to
1497 * assume the identity of another process or to revert back to normal identity
1498 * of the current process.
1500 * When the "assume" argument is non zero the current thread will assume the
1501 * identity of the process represented by the pid argument.
1503 * When the assume argument is zero we revert back to our normal identity.
1506 settid_with_pid(proc_t p
, struct settid_with_pid_args
*uap
, __unused
int32_t *retval
)
1509 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1510 kauth_cred_t my_cred
, my_target_cred
, my_new_cred
;
1511 posix_cred_t my_target_pcred
;
1513 AUDIT_ARG(pid
, uap
->pid
);
1514 AUDIT_ARG(value32
, uap
->assume
);
1516 if (proc_suser(p
) != 0) {
1521 * XXX should potentially set per thread security token (there is
1523 * XXX it is unclear whether P_SUGID should be st at this point;
1524 * XXX in theory, it is being deprecated.
1528 * assume argument tells us to assume the identity of the process with the
1529 * id passed in the pid argument.
1531 if (uap
->assume
!= 0) {
1532 /* can't do this if we have already assumed an identity */
1533 if ((uthread
->uu_flag
& UT_SETUID
) != 0)
1536 target_proc
= proc_find(uap
->pid
);
1537 /* can't assume the identity of the kernel process */
1538 if (target_proc
== NULL
|| target_proc
== kernproc
) {
1539 if (target_proc
!= NULL
)
1540 proc_rele(target_proc
);
1545 * Take a reference on the credential used in our target
1546 * process then use it as the identity for our current
1547 * thread. We take an extra reference on the current
1548 * credential while we muck with it, so we can do the
1549 * post-compare for changes by pointer.
1551 * The post-compare is needed for the case that our process
1552 * credential has been changed to be identical to our thread
1553 * credential following our assumption of a per-thread one,
1554 * since the credential cache will maintain a unique instance.
1556 kauth_cred_ref(uthread
->uu_ucred
);
1557 my_cred
= uthread
->uu_ucred
;
1558 my_target_cred
= kauth_cred_proc_ref(target_proc
);
1559 my_target_pcred
= posix_cred_get(my_target_cred
);
1560 my_new_cred
= kauth_cred_setuidgid(my_cred
, my_target_pcred
->cr_uid
, my_target_pcred
->cr_gid
);
1561 if (my_cred
!= my_new_cred
)
1562 uthread
->uu_ucred
= my_new_cred
;
1564 uthread
->uu_flag
|= UT_SETUID
;
1566 /* Drop old uthread reference or our extra reference */
1567 proc_rele(target_proc
);
1568 kauth_cred_unref(&my_cred
);
1569 kauth_cred_unref(&my_target_cred
);
1575 * Otherwise, we are reverting back to normal mode of operation where
1576 * delayed binding of the process credential sets the credential in
1577 * the thread (uu_ucred)
1579 if ((uthread
->uu_flag
& UT_SETUID
) == 0)
1582 /* revert to delayed binding of process credential */
1583 my_new_cred
= kauth_cred_proc_ref(p
);
1584 kauth_cred_unref(&uthread
->uu_ucred
);
1585 uthread
->uu_ucred
= my_new_cred
;
1586 uthread
->uu_flag
&= ~UT_SETUID
;
1595 * Description: Internal implementation for both the setgroups and initgroups
1598 * Parameters: gidsetsize Number of groups in set
1599 * gidset Pointer to group list
1600 * gmuid Base gid (initgroups only!)
1602 * Returns: 0 Success
1603 * suser:EPERM Permision denied
1604 * EINVAL Invalid gidsetsize value
1605 * copyin:EFAULT Bad gidset or gidsetsize is
1608 * Notes: When called from a thread running under an assumed per-thread
1609 * identity, this function will operate against the per-thread
1610 * credential, rather than against the process credential. In
1611 * this specific case, the process credential is verified to
1612 * still be privileged at the time of the call, rather than the
1613 * per-thread credential for this operation to be permitted.
1615 * This effectively means that setgroups/initigroups calls in
1616 * a thread running a per-thread credential should occur *after*
1617 * the settid call that created it, not before (unlike setuid,
1618 * which must be called after, since it will result in privilege
1621 * When called normally (i.e. no per-thread assumed identity),
1622 * the per process credential is updated per POSIX.
1624 * If the credential is changed as a result of this call, then we
1625 * flag the process as having set privilege since the last exec.
1628 setgroups1(proc_t p
, u_int gidsetsize
, user_addr_t gidset
, uid_t gmuid
, __unused
int32_t *retval
)
1631 gid_t newgroups
[NGROUPS
] = { 0 };
1633 kauth_cred_t my_cred
, my_new_cred
;
1634 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1636 DEBUG_CRED_ENTER("setgroups1 (%d/%d): %d 0x%016x %d\n", p
->p_pid
, (p
->p_pptr
? p
->p_pptr
->p_pid
: 0), gidsetsize
, gidset
, gmuid
);
1645 error
= copyin(gidset
,
1646 (caddr_t
)newgroups
, ngrp
* sizeof(gid_t
));
1652 my_cred
= kauth_cred_proc_ref(p
);
1653 if ((error
= suser(my_cred
, &p
->p_acflag
))) {
1654 kauth_cred_unref(&my_cred
);
1658 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1660 int my_cred_flags
= uthread
->uu_ucred
->cr_flags
;
1661 #endif /* DEBUG_CRED */
1662 kauth_cred_unref(&my_cred
);
1665 * If this thread is under an assumed identity, set the
1666 * supplementary grouplist on the thread credential instead
1667 * of the process one. If we were the only reference holder,
1668 * the credential is updated in place, otherwise, our reference
1669 * is dropped and we get back a different cred with a reference
1670 * already held on it. Because this is per-thread, we don't
1671 * need the referencing/locking/retry required for per-process.
1673 my_cred
= uthread
->uu_ucred
;
1674 uthread
->uu_ucred
= kauth_cred_setgroups(my_cred
, &newgroups
[0], ngrp
, gmuid
);
1676 if (my_cred
!= uthread
->uu_ucred
) {
1677 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
);
1679 #endif /* DEBUG_CRED */
1683 * get current credential and take a reference while we muck
1688 * Set the credential with new info. If there is no
1689 * change, we get back the same credential we passed
1690 * in; if there is a change, we drop the reference on
1691 * the credential we passed in. The subsequent
1692 * compare is safe, because it is a pointer compare
1693 * rather than a contents compare.
1695 my_new_cred
= kauth_cred_setgroups(my_cred
, &newgroups
[0], ngrp
, gmuid
);
1696 if (my_cred
!= my_new_cred
) {
1698 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
);
1702 * We need to protect for a race where another
1703 * thread also changed the credential after we
1704 * took our reference. If p_ucred has
1705 * changed then we should restart this again
1706 * with the new cred.
1708 if (p
->p_ucred
!= my_cred
) {
1709 proc_ucred_unlock(p
);
1710 kauth_cred_unref(&my_new_cred
);
1711 my_cred
= kauth_cred_proc_ref(p
);
1715 p
->p_ucred
= my_new_cred
;
1716 /* update cred on proc */
1717 PROC_UPDATE_CREDS_ONPROC(p
);
1718 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1719 proc_ucred_unlock(p
);
1723 /* Drop old proc reference or our extra reference */
1724 AUDIT_ARG(groupset
, posix_cred_get(my_cred
)->cr_groups
, ngrp
);
1725 kauth_cred_unref(&my_cred
);
1728 set_security_token(p
);
1738 * Description: Initialize the default supplementary groups list and set the
1739 * gmuid for use by the external group resolver (if any)
1741 * Parameters: uap->gidsetsize Number of groups in set
1742 * uap->gidset Pointer to group list
1743 * uap->gmuid Base gid
1745 * Returns: 0 Success
1746 * setgroups1:EPERM Permision denied
1747 * setgroups1:EINVAL Invalid gidsetsize value
1748 * setgroups1:EFAULT Bad gidset or gidsetsize is
1750 * Notes: This function opts *IN* to memberd participation
1752 * The normal purpose of this function is for a privileged
1753 * process to indicate supplementary groups and identity for
1754 * participation in extended group membership resolution prior
1755 * to dropping privilege by assuming a specific user identity.
1757 * It is the first half of the primary mechanism whereby user
1758 * identity is established to the system by programs such as
1759 * /usr/bin/login. The second half is the drop of uid privilege
1760 * for a specific uid corresponding to the user.
1762 * See also: setgroups1()
1765 initgroups(proc_t p
, struct initgroups_args
*uap
, __unused
int32_t *retval
)
1767 DEBUG_CRED_ENTER("initgroups\n");
1769 return(setgroups1(p
, uap
->gidsetsize
, uap
->gidset
, uap
->gmuid
, retval
));
1776 * Description: Initialize the default supplementary groups list
1778 * Parameters: gidsetsize Number of groups in set
1779 * gidset Pointer to group list
1781 * Returns: 0 Success
1782 * setgroups1:EPERM Permision denied
1783 * setgroups1:EINVAL Invalid gidsetsize value
1784 * setgroups1:EFAULT Bad gidset or gidsetsize is
1786 * Notes: This functions opts *OUT* of memberd participation.
1788 * This function exists for compatibility with POSIX. Most user
1789 * programs should use initgroups() instead to ensure correct
1790 * participation in group membership resolution when utilizing
1791 * a directory service for authentication.
1793 * It is identical to an initgroups() call with a gmuid argument
1794 * of KAUTH_UID_NONE.
1796 * See also: setgroups1()
1799 setgroups(proc_t p
, struct setgroups_args
*uap
, __unused
int32_t *retval
)
1801 DEBUG_CRED_ENTER("setgroups\n");
1803 return(setgroups1(p
, uap
->gidsetsize
, uap
->gidset
, KAUTH_UID_NONE
, retval
));
1808 * Set the per-thread/per-process supplementary groups list.
1810 * XXX implement setsgroups
1815 setsgroups(__unused proc_t p
, __unused
struct setsgroups_args
*uap
, __unused
int32_t *retval
)
1821 * Set the per-thread/per-process whiteout groups list.
1823 * XXX implement setwgroups
1828 setwgroups(__unused proc_t p
, __unused
struct setwgroups_args
*uap
, __unused
int32_t *retval
)
1835 * Check if gid is a member of the group set.
1837 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1841 groupmember(gid_t gid
, kauth_cred_t cred
)
1845 if (kauth_cred_ismember_gid(cred
, gid
, &is_member
) == 0 && is_member
)
1852 * Test whether the specified credentials imply "super-user"
1853 * privilege; if so, and we have accounting info, set the flag
1854 * indicating use of super-powers.
1855 * Returns 0 or error.
1857 * XXX This interface is going away; use kauth_cred_issuser() directly
1860 * Note: This interface exists to implement the "has used privilege"
1861 * bit (ASU) in the p_acflags field of the process, which is
1862 * only externalized via private sysctl and in process accounting
1863 * records. The flag is technically not required in either case.
1866 suser(kauth_cred_t cred
, u_short
*acflag
)
1869 if (!IS_VALID_CRED(cred
))
1872 if (kauth_cred_getuid(cred
) == 0) {
1884 * Description: Get login name, if available.
1886 * Parameters: uap->namebuf User buffer for return
1887 * uap->namelen User buffer length
1889 * Returns: 0 Success
1892 * Notes: Intended to obtain a string containing the user name of the
1893 * user associated with the controlling terminal for the calling
1896 * Not very useful on modern systems, due to inherent length
1897 * limitations for the static array in the session structure
1898 * which is used to store the login name.
1900 * Permitted to return NULL
1902 * XXX: Belongs in kern_proc.c
1905 getlogin(proc_t p
, struct getlogin_args
*uap
, __unused
int32_t *retval
)
1907 char buffer
[MAXLOGNAME
+1];
1908 struct session
* sessp
;
1910 bzero(buffer
, MAXLOGNAME
+1);
1912 sessp
= proc_session(p
);
1914 if (uap
->namelen
> MAXLOGNAME
)
1915 uap
->namelen
= MAXLOGNAME
;
1917 if(sessp
!= SESSION_NULL
) {
1918 session_lock(sessp
);
1919 bcopy( sessp
->s_login
, buffer
, uap
->namelen
);
1920 session_unlock(sessp
);
1922 session_rele(sessp
);
1924 return (copyout((caddr_t
)buffer
, uap
->namebuf
, uap
->namelen
));
1931 * Description: Set login name.
1933 * Parameters: uap->namebuf User buffer containing name
1935 * Returns: 0 Success
1936 * suser:EPERM Permission denied
1937 * copyinstr:EFAULT User buffer invalid
1938 * copyinstr:EINVAL Supplied name was too long
1940 * Notes: This is a utility system call to support getlogin().
1942 * XXX: Belongs in kern_proc.c
1945 setlogin(proc_t p
, struct setlogin_args
*uap
, __unused
int32_t *retval
)
1949 char buffer
[MAXLOGNAME
+1];
1950 struct session
* sessp
;
1952 if ((error
= proc_suser(p
)))
1955 bzero(&buffer
[0], MAXLOGNAME
+1);
1958 error
= copyinstr(uap
->namebuf
,
1959 (caddr_t
) &buffer
[0],
1960 MAXLOGNAME
- 1, (size_t *)&dummy
);
1962 sessp
= proc_session(p
);
1964 if (sessp
!= SESSION_NULL
) {
1965 session_lock(sessp
);
1966 bcopy(buffer
, sessp
->s_login
, MAXLOGNAME
);
1967 session_unlock(sessp
);
1968 session_rele(sessp
);
1973 AUDIT_ARG(text
, buffer
);
1974 } else if (error
== ENAMETOOLONG
)
1980 /* Set the secrity token of the task with current euid and eguid */
1982 * XXX This needs to change to give the task a reference and/or an opaque
1986 set_security_token(proc_t p
)
1988 return set_security_token_task_internal(p
, p
->task
);
1992 * Set the secrity token of the task with current euid and eguid
1993 * The function takes a proc and a task, where proc->task might point to a
1994 * different task if called from exec.
1998 set_security_token_task_internal(proc_t p
, void *t
)
2000 security_token_t sec_token
;
2001 audit_token_t audit_token
;
2002 kauth_cred_t my_cred
;
2003 posix_cred_t my_pcred
;
2004 host_priv_t host_priv
;
2008 * Don't allow a vfork child to override the parent's token settings
2009 * (since they share a task). Instead, the child will just have to
2010 * suffer along using the parent's token until the exec(). It's all
2011 * undefined behavior anyway, right?
2013 if (task
== current_task()) {
2015 uthread
= (uthread_t
)get_bsdthread_info(current_thread());
2016 if (uthread
->uu_flag
& UT_VFORK
)
2020 my_cred
= kauth_cred_proc_ref(p
);
2021 my_pcred
= posix_cred_get(my_cred
);
2023 /* XXX mach_init doesn't have a p_ucred when it calls this function */
2024 if (IS_VALID_CRED(my_cred
)) {
2025 sec_token
.val
[0] = kauth_cred_getuid(my_cred
);
2026 sec_token
.val
[1] = kauth_cred_getgid(my_cred
);
2028 sec_token
.val
[0] = 0;
2029 sec_token
.val
[1] = 0;
2033 * The current layout of the Mach audit token explicitly
2034 * adds these fields. But nobody should rely on such
2035 * a literal representation. Instead, the BSM library
2036 * provides a function to convert an audit token into
2037 * a BSM subject. Use of that mechanism will isolate
2038 * the user of the trailer from future representation
2041 audit_token
.val
[0] = my_cred
->cr_audit
.as_aia_p
->ai_auid
;
2042 audit_token
.val
[1] = my_pcred
->cr_uid
;
2043 audit_token
.val
[2] = my_pcred
->cr_gid
;
2044 audit_token
.val
[3] = my_pcred
->cr_ruid
;
2045 audit_token
.val
[4] = my_pcred
->cr_rgid
;
2046 audit_token
.val
[5] = p
->p_pid
;
2047 audit_token
.val
[6] = my_cred
->cr_audit
.as_aia_p
->ai_asid
;
2048 audit_token
.val
[7] = p
->p_idversion
;
2050 host_priv
= (sec_token
.val
[0]) ? HOST_PRIV_NULL
: host_priv_self();
2052 if (host_priv
!= HOST_PRIV_NULL
&& mac_system_check_host_priv(my_cred
))
2053 host_priv
= HOST_PRIV_NULL
;
2055 kauth_cred_unref(&my_cred
);
2057 #if DEVELOPMENT || DEBUG
2059 * Update the pid an proc name for importance base if any
2061 task_importance_update_owner_info(task
);
2064 return (host_security_set_task_token(host_security_self(),
2068 host_priv
) != KERN_SUCCESS
);
2072 int get_audit_token_pid(audit_token_t
*audit_token
);
2075 get_audit_token_pid(audit_token_t
*audit_token
)
2077 /* keep in-sync with set_security_token (above) */
2079 return (int)audit_token
->val
[5];
2085 * Fill in a struct xucred based on a kauth_cred_t.
2089 cru2x(kauth_cred_t cr
, struct xucred
*xcr
)
2091 posix_cred_t pcr
= posix_cred_get(cr
);
2093 bzero(xcr
, sizeof(*xcr
));
2094 xcr
->cr_version
= XUCRED_VERSION
;
2095 xcr
->cr_uid
= kauth_cred_getuid(cr
);
2096 xcr
->cr_ngroups
= pcr
->cr_ngroups
;
2097 bcopy(pcr
->cr_groups
, xcr
->cr_groups
, sizeof(xcr
->cr_groups
));