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
)
184 * Description: get the parent process ID
188 * Returns: pid_t Parent process ID
190 * XXX: Belongs in kern_proc.c
193 getppid(proc_t p
, __unused
struct getppid_args
*uap
, int32_t *retval
)
203 * Description: get the process group ID of the calling process
207 * Returns: pid_t Process group ID
209 * XXX: Belongs in kern_proc.c
212 getpgrp(proc_t p
, __unused
struct getpgrp_args
*uap
, int32_t *retval
)
214 *retval
= p
->p_pgrpid
;
222 * Description: Get an arbitary pid's process group id
224 * Parameters: uap->pid The target pid
227 * ESRCH No such process
229 * Notes: We are permitted to return EPERM in the case that the target
230 * process is not in the same session as the calling process,
231 * which could be a security consideration
233 * XXX: Belongs in kern_proc.c
236 getpgid(proc_t p
, struct getpgid_args
*uap
, int32_t *retval
)
246 if ((pt
= proc_find(uap
->pid
)) == 0) {
251 *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
;
287 if ((pt
= proc_find(uap
->pid
)) == 0) {
292 sessp
= proc_session(pt
);
293 *retval
= sessp
->s_sid
;
306 * Description: get real user ID for caller
310 * Returns: uid_t The real uid of the caller
313 getuid(__unused proc_t p
, __unused
struct getuid_args
*uap
, int32_t *retval
)
315 *retval
= kauth_getruid();
323 * Description: get effective user ID for caller
327 * Returns: uid_t The effective uid of the caller
330 geteuid(__unused proc_t p
, __unused
struct geteuid_args
*uap
, int32_t *retval
)
332 *retval
= kauth_getuid();
340 * Description: Return the per-thread override identity.
342 * Parameters: uap->uidp Address of uid_t to get uid
343 * uap->gidp Address of gid_t to get gid
346 * ESRCH No per thread identity active
349 gettid(__unused proc_t p
, struct gettid_args
*uap
, int32_t *retval
)
351 struct uthread
*uthread
= get_bsdthread_info(current_thread());
355 * If this thread is not running with an override identity, we can't
356 * return one to the caller, so return an error instead.
358 if (!(uthread
->uu_flag
& UT_SETUID
)) {
362 if ((error
= suword(uap
->uidp
, kauth_cred_getruid(uthread
->uu_ucred
)))) {
365 if ((error
= suword(uap
->gidp
, kauth_cred_getrgid(uthread
->uu_ucred
)))) {
377 * Description: get the real group ID for the calling process
381 * Returns: gid_t The real gid of the caller
384 getgid(__unused proc_t p
, __unused
struct getgid_args
*uap
, int32_t *retval
)
386 *retval
= kauth_getrgid();
394 * Description: get the effective group ID for the calling process
398 * Returns: gid_t The effective gid of the caller
400 * Notes: As an implementation detail, the effective gid is stored as
401 * the first element of the supplementary group list.
403 * This could be implemented in Libc instead because of the above
407 getegid(__unused proc_t p
, __unused
struct getegid_args
*uap
, int32_t *retval
)
409 *retval
= kauth_getgid();
417 * Description: get the list of supplementary groups for the calling process
419 * Parameters: uap->gidsetsize # of gid_t's in user buffer
420 * uap->gidset Pointer to user buffer
423 * EINVAL User buffer too small
424 * copyout:EFAULT User buffer invalid
429 * Notes: The caller may specify a 0 value for gidsetsize, and we will
430 * then return how large a buffer is required (in gid_t's) to
431 * contain the answer at the time of the call. Otherwise, we
432 * return the number of gid_t's catually copied to user space.
434 * When called with a 0 gidsetsize from a multithreaded program,
435 * there is no guarantee that another thread may not change the
436 * number of supplementary groups, and therefore a subsequent
437 * call could still fail, unless the maximum possible buffer
438 * size is supplied by the user.
440 * As an implementation detail, the effective gid is stored as
441 * the first element of the supplementary group list, and will
442 * be returned by this call.
445 getgroups(__unused proc_t p
, struct getgroups_args
*uap
, int32_t *retval
)
452 /* grab reference while we muck around with the credential */
453 cred
= kauth_cred_get_with_ref();
454 pcred
= posix_cred_get(cred
);
456 if ((ngrp
= uap
->gidsetsize
) == 0) {
457 *retval
= pcred
->cr_ngroups
;
458 kauth_cred_unref(&cred
);
461 if (ngrp
< pcred
->cr_ngroups
) {
462 kauth_cred_unref(&cred
);
465 ngrp
= pcred
->cr_ngroups
;
466 if ((error
= copyout((caddr_t
)pcred
->cr_groups
,
468 ngrp
* sizeof(gid_t
)))) {
469 kauth_cred_unref(&cred
);
472 kauth_cred_unref(&cred
);
479 * Return the per-thread/per-process supplementary groups list.
481 * XXX implement getsgroups
486 getsgroups(__unused proc_t p
, __unused
struct getsgroups_args
*uap
, __unused
int32_t *retval
)
492 * Return the per-thread/per-process whiteout groups list.
494 * XXX implement getwgroups
499 getwgroups(__unused proc_t p
, __unused
struct getwgroups_args
*uap
, __unused
int32_t *retval
)
508 * Description: Create a new session and set the process group ID to the
514 * EPERM Permission denied
516 * Notes: If the calling process is not the process group leader; there
517 * is no existing process group with its ID, and we are not
518 * currently in vfork, then this function will create a new
519 * session, a new process group, and put the caller in the
520 * process group (as the sole member) and make it the session
521 * leader (as the sole process in the session).
523 * The existing controlling tty (if any) will be dissociated
524 * from the process, and the next non-O_NOCTTY open of a tty
525 * will establish a new controlling tty.
527 * XXX: Belongs in kern_proc.c
530 setsid(proc_t p
, __unused
struct setsid_args
*uap
, int32_t *retval
)
532 struct pgrp
* pg
= PGRP_NULL
;
534 if (p
->p_pgrpid
== p
->p_pid
|| (pg
= pgfind(p
->p_pid
)) || p
->p_lflag
& P_LINVFORK
) {
535 if (pg
!= PGRP_NULL
) {
540 /* enter pgrp works with its own pgrp refcount */
541 (void)enterpgrp(p
, p
->p_pid
, 1);
551 * Description: set process group ID for job control
553 * Parameters: uap->pid Process to change
554 * uap->pgid Process group to join or create
557 * ESRCH pid is not the caller or a child of
559 * enterpgrp:ESRCH No such process
560 * EACCES Permission denied due to exec
561 * EINVAL Invalid argument
562 * EPERM The target process is not in the same
563 * session as the calling process
564 * EPERM The target process is a session leader
565 * EPERM pid and pgid are not the same, and
566 * there is no process in the calling
567 * process whose process group ID matches
570 * Notes: This function will cause the target process to either join
571 * an existing process process group, or create a new process
572 * group in the session of the calling process. It cannot be
573 * used to change the process group ID of a process which is
574 * already a session leader.
576 * If the target pid is 0, the pid of the calling process is
577 * substituted as the new target; if pgid is 0, the target pid
578 * is used as the target process group ID.
580 * Legacy: This system call entry point is also used to implement the
581 * legacy library routine setpgrp(), which under POSIX
583 * XXX: Belongs in kern_proc.c
586 setpgid(proc_t curp
, struct setpgid_args
*uap
, __unused
int32_t *retval
)
588 proc_t targp
= PROC_NULL
; /* target process */
589 struct pgrp
*pg
= PGRP_NULL
; /* target pgrp */
593 struct session
* curp_sessp
= SESSION_NULL
;
594 struct session
* targp_sessp
= SESSION_NULL
;
596 curp_sessp
= proc_session(curp
);
598 if (uap
->pid
!= 0 && uap
->pid
!= curp
->p_pid
) {
599 if ((targp
= proc_find(uap
->pid
)) == 0 || !inferior(targp
)) {
600 if (targp
!= PROC_NULL
) {
607 targp_sessp
= proc_session(targp
);
608 if (targp_sessp
!= curp_sessp
) {
612 if (targp
->p_flag
& P_EXEC
) {
618 targp_sessp
= proc_session(targp
);
621 if (SESS_LEADER(targp
, targp_sessp
)) {
625 if (targp_sessp
!= SESSION_NULL
) {
626 session_rele(targp_sessp
);
627 targp_sessp
= SESSION_NULL
;
634 if (uap
->pgid
== 0) {
635 uap
->pgid
= targp
->p_pid
;
636 } else if (uap
->pgid
!= targp
->p_pid
) {
637 if ((pg
= pgfind(uap
->pgid
)) == 0) {
641 samesess
= (pg
->pg_session
!= curp_sessp
);
648 error
= enterpgrp(targp
, uap
->pgid
, 0);
650 if (targp_sessp
!= SESSION_NULL
) {
651 session_rele(targp_sessp
);
653 if (curp_sessp
!= SESSION_NULL
) {
654 session_rele(curp_sessp
);
666 * Description: Is current process tainted by uid or gid changes system call
670 * Returns: 0 Not tainted
673 * Notes: A process is considered tainted if it was created as a retult
674 * of an execve call from an imnage that had either the SUID or
675 * SGID bit set on the executable, or if it has changed any of its
676 * real, effective, or saved user or group IDs since beginning
680 proc_issetugid(proc_t p
)
682 return (p
->p_flag
& P_SUGID
) ? 1 : 0;
686 issetugid(proc_t p
, __unused
struct issetugid_args
*uap
, int32_t *retval
)
689 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
690 * we use P_SUGID because we consider changing the owners as
691 * "tainting" as well.
692 * This is significant for procs that start as root and "become"
693 * a user without an exec - programs cannot know *everything*
694 * that libc *might* have put in their data segment.
697 *retval
= proc_issetugid(p
);
705 * Description: Set user ID system call
707 * Parameters: uap->uid uid to set
710 * suser:EPERM Permission denied
712 * Notes: If called by a privileged process, this function will set the
713 * real, effective, and saved uid to the requested value.
715 * If called from an unprivileged process, but uid is equal to the
716 * real or saved uid, then the effective uid will be set to the
717 * requested value, but the real and saved uid will not change.
719 * If the credential is changed as a result of this call, then we
720 * flag the process as having set privilege since the last exec.
723 setuid(proc_t p
, struct setuid_args
*uap
, __unused
int32_t *retval
)
726 uid_t svuid
= KAUTH_UID_NONE
;
727 uid_t ruid
= KAUTH_UID_NONE
;
728 uid_t gmuid
= KAUTH_UID_NONE
;
730 kauth_cred_t my_cred
, my_new_cred
;
731 posix_cred_t my_pcred
;
735 /* get current credential and take a reference while we muck with it */
736 my_cred
= kauth_cred_proc_ref(p
);
737 my_pcred
= posix_cred_get(my_cred
);
739 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
);
743 if (uid
!= my_pcred
->cr_ruid
&& /* allow setuid(getuid()) */
744 uid
!= my_pcred
->cr_svuid
&& /* allow setuid(saved uid) */
745 (error
= suser(my_cred
, &p
->p_acflag
))) {
746 kauth_cred_unref(&my_cred
);
751 * If we are privileged, then set the saved and real UID too;
752 * otherwise, just set the effective UID
754 if (suser(my_cred
, &p
->p_acflag
) == 0) {
758 svuid
= KAUTH_UID_NONE
;
759 ruid
= KAUTH_UID_NONE
;
762 * Only set the gmuid if the current cred has not opt'ed out;
763 * this normally only happens when calling setgroups() instead
764 * of initgroups() to set an explicit group list, or one of the
765 * other group manipulation functions is invoked and results in
766 * a dislocation (i.e. the credential group membership changes
767 * to something other than the default list for the user, as
768 * in entering a group or leaving an exclusion group).
770 if (!(my_pcred
->cr_flags
& CRF_NOMEMBERD
)) {
775 * Set the credential with new info. If there is no change,
776 * we get back the same credential we passed in; if there is
777 * a change, we drop the reference on the credential we
778 * passed in. The subsequent compare is safe, because it is
779 * a pointer compare rather than a contents compare.
781 my_new_cred
= kauth_cred_setresuid(my_cred
, ruid
, uid
, svuid
, gmuid
);
782 if (my_cred
!= my_new_cred
) {
783 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
);
786 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
787 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
788 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
789 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
790 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
791 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
793 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
794 (void)chgproccnt(ruid
, 1);
799 * We need to protect for a race where another thread
800 * also changed the credential after we took our
801 * reference. If p_ucred has changed then we should
802 * restart this again with the new cred.
804 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
806 if (p
->p_ucred
!= my_cred
) {
807 proc_ucred_unlock(p
);
809 * We didn't successfully switch to the new ruid, so decrement
810 * the procs/uid count that we incremented above.
812 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
813 (void)chgproccnt(ruid
, -1);
815 kauth_cred_unref(&my_new_cred
);
816 my_cred
= kauth_cred_proc_ref(p
);
817 my_pcred
= posix_cred_get(my_cred
);
821 p
->p_ucred
= my_new_cred
;
822 /* update cred on proc */
823 PROC_UPDATE_CREDS_ONPROC(p
);
825 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
826 proc_ucred_unlock(p
);
828 * If we've updated the ruid, decrement the count of procs running
829 * under the previous ruid
831 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
832 (void)chgproccnt(my_pcred
->cr_ruid
, -1);
837 /* Drop old proc reference or our extra reference */
838 kauth_cred_unref(&my_cred
);
840 set_security_token(p
);
848 * Description: Set effective user ID system call
850 * Parameters: uap->euid effective uid to set
853 * suser:EPERM Permission denied
855 * Notes: If called by a privileged process, or called from an
856 * unprivileged process but euid is equal to the real or saved
857 * uid, then the effective uid will be set to the requested
858 * value, but the real and saved uid will not change.
860 * If the credential is changed as a result of this call, then we
861 * flag the process as having set privilege since the last exec.
864 seteuid(proc_t p
, struct seteuid_args
*uap
, __unused
int32_t *retval
)
868 kauth_cred_t my_cred
, my_new_cred
;
869 posix_cred_t my_pcred
;
871 DEBUG_CRED_ENTER("seteuid: %d\n", uap
->euid
);
874 AUDIT_ARG(euid
, euid
);
876 my_cred
= kauth_cred_proc_ref(p
);
877 my_pcred
= posix_cred_get(my_cred
);
880 if (euid
!= my_pcred
->cr_ruid
&& euid
!= my_pcred
->cr_svuid
&&
881 (error
= suser(my_cred
, &p
->p_acflag
))) {
882 kauth_cred_unref(&my_cred
);
887 * Set the credential with new info. If there is no change,
888 * we get back the same credential we passed in; if there is
889 * a change, we drop the reference on the credential we
890 * passed in. The subsequent compare is safe, because it is
891 * a pointer compare rather than a contents compare.
893 my_new_cred
= kauth_cred_setresuid(my_cred
, KAUTH_UID_NONE
, euid
, KAUTH_UID_NONE
, my_pcred
->cr_gmuid
);
895 if (my_cred
!= my_new_cred
) {
896 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
);
900 * We need to protect for a race where another thread
901 * also changed the credential after we took our
902 * reference. If p_ucred has changed then we
903 * should restart this again with the new cred.
905 if (p
->p_ucred
!= my_cred
) {
906 proc_ucred_unlock(p
);
907 kauth_cred_unref(&my_new_cred
);
908 my_cred
= kauth_cred_proc_ref(p
);
909 my_pcred
= posix_cred_get(my_cred
);
913 p
->p_ucred
= my_new_cred
;
914 /* update cred on proc */
915 PROC_UPDATE_CREDS_ONPROC(p
);
916 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
917 proc_ucred_unlock(p
);
921 /* drop old proc reference or our extra reference */
922 kauth_cred_unref(&my_cred
);
924 set_security_token(p
);
932 * Description: Set real and effective user ID system call
934 * Parameters: uap->ruid real uid to set
935 * uap->euid effective uid to set
938 * suser:EPERM Permission denied
940 * Notes: A value of -1 is a special case indicating that the uid for
941 * which that value is specified not be changed. If both values
942 * are specified as -1, no action is taken.
944 * If called by a privileged process, the real and effective uid
945 * will be set to the new value(s) specified.
947 * If called from an unprivileged process, the real uid may be
948 * set to the current value of the real uid, or to the current
949 * value of the saved uid. The effective uid may be set to the
950 * current value of any of the effective, real, or saved uid.
952 * If the newly requested real uid or effective uid does not
953 * match the saved uid, then set the saved uid to the new
954 * effective uid (potentially unrecoverably dropping saved
957 * If the credential is changed as a result of this call, then we
958 * flag the process as having set privilege since the last exec.
961 setreuid(proc_t p
, struct setreuid_args
*uap
, __unused
int32_t *retval
)
965 kauth_cred_t my_cred
, my_new_cred
;
966 posix_cred_t my_pcred
;
968 DEBUG_CRED_ENTER("setreuid %d %d\n", uap
->ruid
, uap
->euid
);
972 if (ruid
== (uid_t
)-1) {
973 ruid
= KAUTH_UID_NONE
;
975 if (euid
== (uid_t
)-1) {
976 euid
= KAUTH_UID_NONE
;
978 AUDIT_ARG(euid
, euid
);
979 AUDIT_ARG(ruid
, ruid
);
981 my_cred
= kauth_cred_proc_ref(p
);
982 my_pcred
= posix_cred_get(my_cred
);
985 if (((ruid
!= KAUTH_UID_NONE
&& /* allow no change of ruid */
986 ruid
!= my_pcred
->cr_ruid
&& /* allow ruid = ruid */
987 ruid
!= my_pcred
->cr_uid
&& /* allow ruid = euid */
988 ruid
!= my_pcred
->cr_svuid
) || /* allow ruid = svuid */
989 (euid
!= KAUTH_UID_NONE
&& /* allow no change of euid */
990 euid
!= my_pcred
->cr_uid
&& /* allow euid = euid */
991 euid
!= my_pcred
->cr_ruid
&& /* allow euid = ruid */
992 euid
!= my_pcred
->cr_svuid
)) && /* allow euid = svuid */
993 (error
= suser(my_cred
, &p
->p_acflag
))) { /* allow root user any */
994 kauth_cred_unref(&my_cred
);
999 uid_t svuid
= KAUTH_UID_NONE
;
1001 new_euid
= my_pcred
->cr_uid
;
1003 * Set the credential with new info. If there is no change,
1004 * we get back the same credential we passed in; if there is
1005 * a change, we drop the reference on the credential we
1006 * passed in. The subsequent compare is safe, because it is
1007 * a pointer compare rather than a contents compare.
1009 if (euid
!= KAUTH_UID_NONE
&& my_pcred
->cr_uid
!= euid
) {
1010 /* changing the effective UID */
1012 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1015 * If the newly requested real uid or effective uid does
1016 * not match the saved uid, then set the saved uid to the
1017 * new effective uid. We are protected from escalation
1018 * by the prechecking.
1020 if (my_pcred
->cr_svuid
!= uap
->ruid
&&
1021 my_pcred
->cr_svuid
!= uap
->euid
) {
1023 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1026 my_new_cred
= kauth_cred_setresuid(my_cred
, ruid
, euid
, svuid
, my_pcred
->cr_gmuid
);
1028 if (my_cred
!= my_new_cred
) {
1029 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
);
1032 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
1033 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
1034 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
1035 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
1036 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
1037 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
1039 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1040 (void)chgproccnt(ruid
, 1);
1045 * We need to protect for a race where another thread
1046 * also changed the credential after we took our
1047 * reference. If p_ucred has changed then we should
1048 * restart this again with the new cred.
1050 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
1052 if (p
->p_ucred
!= my_cred
) {
1053 proc_ucred_unlock(p
);
1054 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1056 * We didn't successfully switch to the new ruid, so decrement
1057 * the procs/uid count that we incremented above.
1059 (void)chgproccnt(ruid
, -1);
1061 kauth_cred_unref(&my_new_cred
);
1062 my_cred
= kauth_cred_proc_ref(p
);
1063 my_pcred
= posix_cred_get(my_cred
);
1068 p
->p_ucred
= my_new_cred
;
1069 /* update cred on proc */
1070 PROC_UPDATE_CREDS_ONPROC(p
);
1071 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1072 proc_ucred_unlock(p
);
1074 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1076 * We switched to a new ruid, so decrement the count of procs running
1077 * under the previous ruid
1079 (void)chgproccnt(my_pcred
->cr_ruid
, -1);
1084 /* drop old proc reference or our extra reference */
1085 kauth_cred_unref(&my_cred
);
1087 set_security_token(p
);
1095 * Description: Set group ID system call
1097 * Parameters: uap->gid gid to set
1099 * Returns: 0 Success
1100 * suser:EPERM Permission denied
1102 * Notes: If called by a privileged process, this function will set the
1103 * real, effective, and saved gid to the requested value.
1105 * If called from an unprivileged process, but gid is equal to the
1106 * real or saved gid, then the effective gid will be set to the
1107 * requested value, but the real and saved gid will not change.
1109 * If the credential is changed as a result of this call, then we
1110 * flag the process as having set privilege since the last exec.
1112 * As an implementation detail, the effective gid is stored as
1113 * the first element of the supplementary group list, and
1114 * therefore the effective group list may be reordered to keep
1115 * the supplementary group list unchanged.
1118 setgid(proc_t p
, struct setgid_args
*uap
, __unused
int32_t *retval
)
1121 gid_t rgid
= KAUTH_GID_NONE
;
1122 gid_t svgid
= KAUTH_GID_NONE
;
1124 kauth_cred_t my_cred
, my_new_cred
;
1125 posix_cred_t my_pcred
;
1127 DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p
->p_pid
, (p
->p_pptr
? p
->p_pptr
->p_pid
: 0), uap
->gid
);
1130 AUDIT_ARG(gid
, gid
);
1132 /* get current credential and take a reference while we muck with it */
1133 my_cred
= kauth_cred_proc_ref(p
);
1134 my_pcred
= posix_cred_get(my_cred
);
1137 if (gid
!= my_pcred
->cr_rgid
&& /* allow setgid(getgid()) */
1138 gid
!= my_pcred
->cr_svgid
&& /* allow setgid(saved gid) */
1139 (error
= suser(my_cred
, &p
->p_acflag
))) {
1140 kauth_cred_unref(&my_cred
);
1145 * If we are privileged, then set the saved and real GID too;
1146 * otherwise, just set the effective GID
1148 if (suser(my_cred
, &p
->p_acflag
) == 0) {
1152 svgid
= KAUTH_GID_NONE
;
1153 rgid
= KAUTH_GID_NONE
;
1157 * Set the credential with new info. If there is no change,
1158 * we get back the same credential we passed in; if there is
1159 * a change, we drop the reference on the credential we
1160 * passed in. The subsequent compare is safe, because it is
1161 * a pointer compare rather than a contents compare.
1163 my_new_cred
= kauth_cred_setresgid(my_cred
, rgid
, gid
, svgid
);
1164 if (my_cred
!= my_new_cred
) {
1165 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
);
1169 * We need to protect for a race where another thread
1170 * also changed the credential after we took our
1171 * reference. If p_ucred has changed then we
1172 * should restart this again with the new cred.
1174 if (p
->p_ucred
!= my_cred
) {
1175 proc_ucred_unlock(p
);
1176 kauth_cred_unref(&my_new_cred
);
1178 my_cred
= kauth_cred_proc_ref(p
);
1179 my_pcred
= posix_cred_get(my_cred
);
1182 p
->p_ucred
= my_new_cred
;
1183 /* update cred on proc */
1184 PROC_UPDATE_CREDS_ONPROC(p
);
1185 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1186 proc_ucred_unlock(p
);
1190 /* Drop old proc reference or our extra reference */
1191 kauth_cred_unref(&my_cred
);
1193 set_security_token(p
);
1201 * Description: Set effective group ID system call
1203 * Parameters: uap->egid effective gid to set
1205 * Returns: 0 Success
1208 * Notes: If called by a privileged process, or called from an
1209 * unprivileged process but egid is equal to the real or saved
1210 * gid, then the effective gid will be set to the requested
1211 * value, but the real and saved gid will not change.
1213 * If the credential is changed as a result of this call, then we
1214 * flag the process as having set privilege since the last exec.
1216 * As an implementation detail, the effective gid is stored as
1217 * the first element of the supplementary group list, and
1218 * therefore the effective group list may be reordered to keep
1219 * the supplementary group list unchanged.
1222 setegid(proc_t p
, struct setegid_args
*uap
, __unused
int32_t *retval
)
1226 kauth_cred_t my_cred
, my_new_cred
;
1227 posix_cred_t my_pcred
;
1229 DEBUG_CRED_ENTER("setegid %d\n", uap
->egid
);
1232 AUDIT_ARG(egid
, egid
);
1234 /* get current credential and take a reference while we muck with it */
1235 my_cred
= kauth_cred_proc_ref(p
);
1236 my_pcred
= posix_cred_get(my_cred
);
1240 if (egid
!= my_pcred
->cr_rgid
&&
1241 egid
!= my_pcred
->cr_svgid
&&
1242 (error
= suser(my_cred
, &p
->p_acflag
))) {
1243 kauth_cred_unref(&my_cred
);
1247 * Set the credential with new info. If there is no change,
1248 * we get back the same credential we passed in; if there is
1249 * a change, we drop the reference on the credential we
1250 * passed in. The subsequent compare is safe, because it is
1251 * a pointer compare rather than a contents compare.
1253 my_new_cred
= kauth_cred_setresgid(my_cred
, KAUTH_GID_NONE
, egid
, KAUTH_GID_NONE
);
1254 if (my_cred
!= my_new_cred
) {
1255 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
);
1259 * We need to protect for a race where another thread
1260 * also changed the credential after we took our
1261 * reference. If p_ucred has changed then we
1262 * should restart this again with the new cred.
1264 if (p
->p_ucred
!= my_cred
) {
1265 proc_ucred_unlock(p
);
1266 kauth_cred_unref(&my_new_cred
);
1268 my_cred
= kauth_cred_proc_ref(p
);
1269 my_pcred
= posix_cred_get(my_cred
);
1272 p
->p_ucred
= my_new_cred
;
1273 /* update cred on proc */
1274 PROC_UPDATE_CREDS_ONPROC(p
);
1275 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1276 proc_ucred_unlock(p
);
1281 /* Drop old proc reference or our extra reference */
1282 kauth_cred_unref(&my_cred
);
1284 set_security_token(p
);
1291 * Description: Set real and effective group ID system call
1293 * Parameters: uap->rgid real gid to set
1294 * uap->egid effective gid to set
1296 * Returns: 0 Success
1297 * suser:EPERM Permission denied
1299 * Notes: A value of -1 is a special case indicating that the gid for
1300 * which that value is specified not be changed. If both values
1301 * are specified as -1, no action is taken.
1303 * If called by a privileged process, the real and effective gid
1304 * will be set to the new value(s) specified.
1306 * If called from an unprivileged process, the real gid may be
1307 * set to the current value of the real gid, or to the current
1308 * value of the saved gid. The effective gid may be set to the
1309 * current value of any of the effective, real, or saved gid.
1311 * If the new real and effective gid will not be equal, or the
1312 * new real or effective gid is not the same as the saved gid,
1313 * then the saved gid will be updated to reflect the new
1314 * effective gid (potentially unrecoverably dropping saved
1317 * If the credential is changed as a result of this call, then we
1318 * flag the process as having set privilege since the last exec.
1320 * As an implementation detail, the effective gid is stored as
1321 * the first element of the supplementary group list, and
1322 * therefore the effective group list may be reordered to keep
1323 * the supplementary group list unchanged.
1326 setregid(proc_t p
, struct setregid_args
*uap
, __unused
int32_t *retval
)
1330 kauth_cred_t my_cred
, my_new_cred
;
1331 posix_cred_t my_pcred
;
1333 DEBUG_CRED_ENTER("setregid %d %d\n", uap
->rgid
, uap
->egid
);
1338 if (rgid
== (uid_t
)-1) {
1339 rgid
= KAUTH_GID_NONE
;
1341 if (egid
== (uid_t
)-1) {
1342 egid
= KAUTH_GID_NONE
;
1344 AUDIT_ARG(egid
, egid
);
1345 AUDIT_ARG(rgid
, rgid
);
1347 /* get current credential and take a reference while we muck with it */
1348 my_cred
= kauth_cred_proc_ref(p
);
1349 my_pcred
= posix_cred_get(my_cred
);
1352 if (((rgid
!= KAUTH_UID_NONE
&& /* allow no change of rgid */
1353 rgid
!= my_pcred
->cr_rgid
&& /* allow rgid = rgid */
1354 rgid
!= my_pcred
->cr_gid
&& /* allow rgid = egid */
1355 rgid
!= my_pcred
->cr_svgid
) || /* allow rgid = svgid */
1356 (egid
!= KAUTH_UID_NONE
&& /* allow no change of egid */
1357 egid
!= my_pcred
->cr_groups
[0] && /* allow no change of egid */
1358 egid
!= my_pcred
->cr_gid
&& /* allow egid = egid */
1359 egid
!= my_pcred
->cr_rgid
&& /* allow egid = rgid */
1360 egid
!= my_pcred
->cr_svgid
)) && /* allow egid = svgid */
1361 (error
= suser(my_cred
, &p
->p_acflag
))) { /* allow root user any */
1362 kauth_cred_unref(&my_cred
);
1366 uid_t new_egid
= my_pcred
->cr_gid
;
1367 uid_t new_rgid
= my_pcred
->cr_rgid
;
1368 uid_t svgid
= KAUTH_UID_NONE
;
1372 * Set the credential with new info. If there is no change,
1373 * we get back the same credential we passed in; if there is
1374 * a change, we drop the reference on the credential we
1375 * passed in. The subsequent compare is safe, because it is
1376 * a pointer compare rather than a contents compare.
1378 if (egid
!= KAUTH_UID_NONE
&& my_pcred
->cr_gid
!= egid
) {
1379 /* changing the effective GID */
1381 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1383 if (rgid
!= KAUTH_UID_NONE
&& my_pcred
->cr_rgid
!= rgid
) {
1384 /* changing the real GID */
1386 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1389 * If the newly requested real gid or effective gid does
1390 * not match the saved gid, then set the saved gid to the
1391 * new effective gid. We are protected from escalation
1392 * by the prechecking.
1394 if (my_pcred
->cr_svgid
!= uap
->rgid
&&
1395 my_pcred
->cr_svgid
!= uap
->egid
) {
1397 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1400 my_new_cred
= kauth_cred_setresgid(my_cred
, rgid
, egid
, svgid
);
1401 if (my_cred
!= my_new_cred
) {
1402 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
);
1405 /* need to protect for a race where another thread
1406 * also changed the credential after we took our
1407 * reference. If p_ucred has changed then we
1408 * should restart this again with the new cred.
1410 if (p
->p_ucred
!= my_cred
) {
1411 proc_ucred_unlock(p
);
1412 kauth_cred_unref(&my_new_cred
);
1414 my_cred
= kauth_cred_proc_ref(p
);
1415 my_pcred
= posix_cred_get(my_cred
);
1418 p
->p_ucred
= my_new_cred
;
1419 /* update cred on proc */
1420 PROC_UPDATE_CREDS_ONPROC(p
);
1421 OSBitOrAtomic(P_SUGID
, &p
->p_flag
); /* XXX redundant? */
1422 proc_ucred_unlock(p
);
1426 /* Drop old proc reference or our extra reference */
1427 kauth_cred_unref(&my_cred
);
1429 set_security_token(p
);
1435 * Set the per-thread override identity. The first parameter can be the
1436 * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
1437 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1438 * means "revert to the per process credential"; otherwise, if permitted,
1439 * it changes the effective, real, and saved UIDs and GIDs for the current
1440 * thread to the requested UID and single GID, and clears all other GIDs.
1443 settid(proc_t p
, struct settid_args
*uap
, __unused
int32_t *retval
)
1446 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1452 AUDIT_ARG(uid
, uid
);
1453 AUDIT_ARG(gid
, gid
);
1455 if (proc_suser(p
) != 0) {
1459 if (uid
== KAUTH_UID_NONE
) {
1460 /* must already be assuming another identity in order to revert back */
1461 if ((uthread
->uu_flag
& UT_SETUID
) == 0) {
1465 /* revert to delayed binding of process credential */
1466 uc
= kauth_cred_proc_ref(p
);
1467 kauth_cred_unref(&uthread
->uu_ucred
);
1468 uthread
->uu_ucred
= uc
;
1469 uthread
->uu_flag
&= ~UT_SETUID
;
1471 kauth_cred_t my_cred
, my_new_cred
;
1473 /* cannot already be assuming another identity */
1474 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1479 * Get a new credential instance from the old if this one
1480 * changes; otherwise kauth_cred_setuidgid() returns the
1481 * same credential. We take an extra reference on the
1482 * current credential while we muck with it, so we can do
1483 * the post-compare for changes by pointer.
1485 kauth_cred_ref(uthread
->uu_ucred
);
1486 my_cred
= uthread
->uu_ucred
;
1487 my_new_cred
= kauth_cred_setuidgid(my_cred
, uid
, gid
);
1488 if (my_cred
!= my_new_cred
) {
1489 uthread
->uu_ucred
= my_new_cred
;
1491 uthread
->uu_flag
|= UT_SETUID
;
1493 /* Drop old uthread reference or our extra reference */
1494 kauth_cred_unref(&my_cred
);
1497 * XXX should potentially set per thread security token (there is
1499 * XXX it is unclear whether P_SUGID should be st at this point;
1500 * XXX in theory, it is being deprecated.
1507 * Set the per-thread override identity. Use this system call for a thread to
1508 * assume the identity of another process or to revert back to normal identity
1509 * of the current process.
1511 * When the "assume" argument is non zero the current thread will assume the
1512 * identity of the process represented by the pid argument.
1514 * When the assume argument is zero we revert back to our normal identity.
1517 settid_with_pid(proc_t p
, struct settid_with_pid_args
*uap
, __unused
int32_t *retval
)
1520 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1521 kauth_cred_t my_cred
, my_target_cred
, my_new_cred
;
1522 posix_cred_t my_target_pcred
;
1524 AUDIT_ARG(pid
, uap
->pid
);
1525 AUDIT_ARG(value32
, uap
->assume
);
1527 if (proc_suser(p
) != 0) {
1532 * XXX should potentially set per thread security token (there is
1534 * XXX it is unclear whether P_SUGID should be st at this point;
1535 * XXX in theory, it is being deprecated.
1539 * assume argument tells us to assume the identity of the process with the
1540 * id passed in the pid argument.
1542 if (uap
->assume
!= 0) {
1543 /* can't do this if we have already assumed an identity */
1544 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1548 target_proc
= proc_find(uap
->pid
);
1549 /* can't assume the identity of the kernel process */
1550 if (target_proc
== NULL
|| target_proc
== kernproc
) {
1551 if (target_proc
!= NULL
) {
1552 proc_rele(target_proc
);
1558 * Take a reference on the credential used in our target
1559 * process then use it as the identity for our current
1560 * thread. We take an extra reference on the current
1561 * credential while we muck with it, so we can do the
1562 * post-compare for changes by pointer.
1564 * The post-compare is needed for the case that our process
1565 * credential has been changed to be identical to our thread
1566 * credential following our assumption of a per-thread one,
1567 * since the credential cache will maintain a unique instance.
1569 kauth_cred_ref(uthread
->uu_ucred
);
1570 my_cred
= uthread
->uu_ucred
;
1571 my_target_cred
= kauth_cred_proc_ref(target_proc
);
1572 my_target_pcred
= posix_cred_get(my_target_cred
);
1573 my_new_cred
= kauth_cred_setuidgid(my_cred
, my_target_pcred
->cr_uid
, my_target_pcred
->cr_gid
);
1574 if (my_cred
!= my_new_cred
) {
1575 uthread
->uu_ucred
= my_new_cred
;
1578 uthread
->uu_flag
|= UT_SETUID
;
1580 /* Drop old uthread reference or our extra reference */
1581 proc_rele(target_proc
);
1582 kauth_cred_unref(&my_cred
);
1583 kauth_cred_unref(&my_target_cred
);
1589 * Otherwise, we are reverting back to normal mode of operation where
1590 * delayed binding of the process credential sets the credential in
1591 * the thread (uu_ucred)
1593 if ((uthread
->uu_flag
& UT_SETUID
) == 0) {
1597 /* revert to delayed binding of process credential */
1598 my_new_cred
= kauth_cred_proc_ref(p
);
1599 kauth_cred_unref(&uthread
->uu_ucred
);
1600 uthread
->uu_ucred
= my_new_cred
;
1601 uthread
->uu_flag
&= ~UT_SETUID
;
1610 * Description: Internal implementation for both the setgroups and initgroups
1613 * Parameters: gidsetsize Number of groups in set
1614 * gidset Pointer to group list
1615 * gmuid Base gid (initgroups only!)
1617 * Returns: 0 Success
1618 * suser:EPERM Permision denied
1619 * EINVAL Invalid gidsetsize value
1620 * copyin:EFAULT Bad gidset or gidsetsize is
1623 * Notes: When called from a thread running under an assumed per-thread
1624 * identity, this function will operate against the per-thread
1625 * credential, rather than against the process credential. In
1626 * this specific case, the process credential is verified to
1627 * still be privileged at the time of the call, rather than the
1628 * per-thread credential for this operation to be permitted.
1630 * This effectively means that setgroups/initigroups calls in
1631 * a thread running a per-thread credential should occur *after*
1632 * the settid call that created it, not before (unlike setuid,
1633 * which must be called after, since it will result in privilege
1636 * When called normally (i.e. no per-thread assumed identity),
1637 * the per process credential is updated per POSIX.
1639 * If the credential is changed as a result of this call, then we
1640 * flag the process as having set privilege since the last exec.
1643 setgroups1(proc_t p
, u_int gidsetsize
, user_addr_t gidset
, uid_t gmuid
, __unused
int32_t *retval
)
1646 gid_t newgroups
[NGROUPS
] = { 0 };
1648 kauth_cred_t my_cred
, my_new_cred
;
1649 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1651 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
);
1654 if (ngrp
> NGROUPS
) {
1661 error
= copyin(gidset
,
1662 (caddr_t
)newgroups
, ngrp
* sizeof(gid_t
));
1668 my_cred
= kauth_cred_proc_ref(p
);
1669 if ((error
= suser(my_cred
, &p
->p_acflag
))) {
1670 kauth_cred_unref(&my_cred
);
1674 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1676 int my_cred_flags
= uthread
->uu_ucred
->cr_flags
;
1677 #endif /* DEBUG_CRED */
1678 kauth_cred_unref(&my_cred
);
1681 * If this thread is under an assumed identity, set the
1682 * supplementary grouplist on the thread credential instead
1683 * of the process one. If we were the only reference holder,
1684 * the credential is updated in place, otherwise, our reference
1685 * is dropped and we get back a different cred with a reference
1686 * already held on it. Because this is per-thread, we don't
1687 * need the referencing/locking/retry required for per-process.
1689 my_cred
= uthread
->uu_ucred
;
1690 uthread
->uu_ucred
= kauth_cred_setgroups(my_cred
, &newgroups
[0], ngrp
, gmuid
);
1692 if (my_cred
!= uthread
->uu_ucred
) {
1693 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
);
1695 #endif /* DEBUG_CRED */
1698 * get current credential and take a reference while we muck
1703 * Set the credential with new info. If there is no
1704 * change, we get back the same credential we passed
1705 * in; if there is a change, we drop the reference on
1706 * the credential we passed in. The subsequent
1707 * compare is safe, because it is a pointer compare
1708 * rather than a contents compare.
1710 my_new_cred
= kauth_cred_setgroups(my_cred
, &newgroups
[0], ngrp
, gmuid
);
1711 if (my_cred
!= my_new_cred
) {
1712 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
);
1716 * We need to protect for a race where another
1717 * thread also changed the credential after we
1718 * took our reference. If p_ucred has
1719 * changed then we should restart this again
1720 * with the new cred.
1722 if (p
->p_ucred
!= my_cred
) {
1723 proc_ucred_unlock(p
);
1724 kauth_cred_unref(&my_new_cred
);
1725 my_cred
= kauth_cred_proc_ref(p
);
1729 p
->p_ucred
= my_new_cred
;
1730 /* update cred on proc */
1731 PROC_UPDATE_CREDS_ONPROC(p
);
1732 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1733 proc_ucred_unlock(p
);
1737 /* Drop old proc reference or our extra reference */
1738 AUDIT_ARG(groupset
, posix_cred_get(my_cred
)->cr_groups
, ngrp
);
1739 kauth_cred_unref(&my_cred
);
1742 set_security_token(p
);
1752 * Description: Initialize the default supplementary groups list and set the
1753 * gmuid for use by the external group resolver (if any)
1755 * Parameters: uap->gidsetsize Number of groups in set
1756 * uap->gidset Pointer to group list
1757 * uap->gmuid Base gid
1759 * Returns: 0 Success
1760 * setgroups1:EPERM Permision denied
1761 * setgroups1:EINVAL Invalid gidsetsize value
1762 * setgroups1:EFAULT Bad gidset or gidsetsize is
1764 * Notes: This function opts *IN* to memberd participation
1766 * The normal purpose of this function is for a privileged
1767 * process to indicate supplementary groups and identity for
1768 * participation in extended group membership resolution prior
1769 * to dropping privilege by assuming a specific user identity.
1771 * It is the first half of the primary mechanism whereby user
1772 * identity is established to the system by programs such as
1773 * /usr/bin/login. The second half is the drop of uid privilege
1774 * for a specific uid corresponding to the user.
1776 * See also: setgroups1()
1779 initgroups(proc_t p
, struct initgroups_args
*uap
, __unused
int32_t *retval
)
1781 DEBUG_CRED_ENTER("initgroups\n");
1783 return setgroups1(p
, uap
->gidsetsize
, uap
->gidset
, uap
->gmuid
, retval
);
1790 * Description: Initialize the default supplementary groups list
1792 * Parameters: gidsetsize Number of groups in set
1793 * gidset Pointer to group list
1795 * Returns: 0 Success
1796 * setgroups1:EPERM Permision denied
1797 * setgroups1:EINVAL Invalid gidsetsize value
1798 * setgroups1:EFAULT Bad gidset or gidsetsize is
1800 * Notes: This functions opts *OUT* of memberd participation.
1802 * This function exists for compatibility with POSIX. Most user
1803 * programs should use initgroups() instead to ensure correct
1804 * participation in group membership resolution when utilizing
1805 * a directory service for authentication.
1807 * It is identical to an initgroups() call with a gmuid argument
1808 * of KAUTH_UID_NONE.
1810 * See also: setgroups1()
1813 setgroups(proc_t p
, struct setgroups_args
*uap
, __unused
int32_t *retval
)
1815 DEBUG_CRED_ENTER("setgroups\n");
1817 return setgroups1(p
, uap
->gidsetsize
, uap
->gidset
, KAUTH_UID_NONE
, retval
);
1822 * Set the per-thread/per-process supplementary groups list.
1824 * XXX implement setsgroups
1829 setsgroups(__unused proc_t p
, __unused
struct setsgroups_args
*uap
, __unused
int32_t *retval
)
1835 * Set the per-thread/per-process whiteout groups list.
1837 * XXX implement setwgroups
1842 setwgroups(__unused proc_t p
, __unused
struct setwgroups_args
*uap
, __unused
int32_t *retval
)
1849 * Check if gid is a member of the group set.
1851 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1855 groupmember(gid_t gid
, kauth_cred_t cred
)
1859 if (kauth_cred_ismember_gid(cred
, gid
, &is_member
) == 0 && is_member
) {
1867 * Test whether the specified credentials imply "super-user"
1868 * privilege; if so, and we have accounting info, set the flag
1869 * indicating use of super-powers.
1870 * Returns 0 or error.
1872 * XXX This interface is going away; use kauth_cred_issuser() directly
1875 * Note: This interface exists to implement the "has used privilege"
1876 * bit (ASU) in the p_acflags field of the process, which is
1877 * only externalized via private sysctl and in process accounting
1878 * records. The flag is technically not required in either case.
1881 suser(kauth_cred_t cred
, u_short
*acflag
)
1884 if (!IS_VALID_CRED(cred
)) {
1888 if (kauth_cred_getuid(cred
) == 0) {
1901 * Description: Get login name, if available.
1903 * Parameters: uap->namebuf User buffer for return
1904 * uap->namelen User buffer length
1906 * Returns: 0 Success
1909 * Notes: Intended to obtain a string containing the user name of the
1910 * user associated with the controlling terminal for the calling
1913 * Not very useful on modern systems, due to inherent length
1914 * limitations for the static array in the session structure
1915 * which is used to store the login name.
1917 * Permitted to return NULL
1919 * XXX: Belongs in kern_proc.c
1922 getlogin(proc_t p
, struct getlogin_args
*uap
, __unused
int32_t *retval
)
1924 char buffer
[MAXLOGNAME
+ 1];
1925 struct session
* sessp
;
1927 bzero(buffer
, MAXLOGNAME
+ 1);
1929 sessp
= proc_session(p
);
1931 if (uap
->namelen
> MAXLOGNAME
) {
1932 uap
->namelen
= MAXLOGNAME
;
1935 if (sessp
!= SESSION_NULL
) {
1936 session_lock(sessp
);
1937 bcopy( sessp
->s_login
, buffer
, uap
->namelen
);
1938 session_unlock(sessp
);
1940 session_rele(sessp
);
1942 return copyout((caddr_t
)buffer
, uap
->namebuf
, uap
->namelen
);
1949 * Description: Set login name.
1951 * Parameters: uap->namebuf User buffer containing name
1953 * Returns: 0 Success
1954 * suser:EPERM Permission denied
1955 * copyinstr:EFAULT User buffer invalid
1956 * copyinstr:EINVAL Supplied name was too long
1958 * Notes: This is a utility system call to support getlogin().
1960 * XXX: Belongs in kern_proc.c
1963 setlogin(proc_t p
, struct setlogin_args
*uap
, __unused
int32_t *retval
)
1967 char buffer
[MAXLOGNAME
+ 1];
1968 struct session
* sessp
;
1970 if ((error
= proc_suser(p
))) {
1974 bzero(&buffer
[0], MAXLOGNAME
+ 1);
1977 error
= copyinstr(uap
->namebuf
,
1978 (caddr_t
) &buffer
[0],
1979 MAXLOGNAME
- 1, (size_t *)&dummy
);
1981 sessp
= proc_session(p
);
1983 if (sessp
!= SESSION_NULL
) {
1984 session_lock(sessp
);
1985 bcopy(buffer
, sessp
->s_login
, MAXLOGNAME
);
1986 session_unlock(sessp
);
1987 session_rele(sessp
);
1992 AUDIT_ARG(text
, buffer
);
1993 } else if (error
== ENAMETOOLONG
) {
2000 /* Set the secrity token of the task with current euid and eguid */
2002 * XXX This needs to change to give the task a reference and/or an opaque
2006 set_security_token(proc_t p
)
2008 return set_security_token_task_internal(p
, p
->task
);
2012 * Set the secrity token of the task with current euid and eguid
2013 * The function takes a proc and a task, where proc->task might point to a
2014 * different task if called from exec.
2018 set_security_token_task_internal(proc_t p
, void *t
)
2020 security_token_t sec_token
;
2021 audit_token_t audit_token
;
2022 kauth_cred_t my_cred
;
2023 posix_cred_t my_pcred
;
2024 host_priv_t host_priv
;
2028 * Don't allow a vfork child to override the parent's token settings
2029 * (since they share a task). Instead, the child will just have to
2030 * suffer along using the parent's token until the exec(). It's all
2031 * undefined behavior anyway, right?
2033 if (task
== current_task()) {
2035 uthread
= (uthread_t
)get_bsdthread_info(current_thread());
2036 if (uthread
->uu_flag
& UT_VFORK
) {
2041 my_cred
= kauth_cred_proc_ref(p
);
2042 my_pcred
= posix_cred_get(my_cred
);
2044 /* XXX mach_init doesn't have a p_ucred when it calls this function */
2045 if (IS_VALID_CRED(my_cred
)) {
2046 sec_token
.val
[0] = kauth_cred_getuid(my_cred
);
2047 sec_token
.val
[1] = kauth_cred_getgid(my_cred
);
2049 sec_token
.val
[0] = 0;
2050 sec_token
.val
[1] = 0;
2054 * The current layout of the Mach audit token explicitly
2055 * adds these fields. But nobody should rely on such
2056 * a literal representation. Instead, the BSM library
2057 * provides a function to convert an audit token into
2058 * a BSM subject. Use of that mechanism will isolate
2059 * the user of the trailer from future representation
2062 audit_token
.val
[0] = my_cred
->cr_audit
.as_aia_p
->ai_auid
;
2063 audit_token
.val
[1] = my_pcred
->cr_uid
;
2064 audit_token
.val
[2] = my_pcred
->cr_gid
;
2065 audit_token
.val
[3] = my_pcred
->cr_ruid
;
2066 audit_token
.val
[4] = my_pcred
->cr_rgid
;
2067 audit_token
.val
[5] = p
->p_pid
;
2068 audit_token
.val
[6] = my_cred
->cr_audit
.as_aia_p
->ai_asid
;
2069 audit_token
.val
[7] = p
->p_idversion
;
2071 host_priv
= (sec_token
.val
[0]) ? HOST_PRIV_NULL
: host_priv_self();
2073 if (host_priv
!= HOST_PRIV_NULL
&& mac_system_check_host_priv(my_cred
)) {
2074 host_priv
= HOST_PRIV_NULL
;
2077 kauth_cred_unref(&my_cred
);
2079 #if DEVELOPMENT || DEBUG
2081 * Update the pid an proc name for importance base if any
2083 task_importance_update_owner_info(task
);
2086 return host_security_set_task_token(host_security_self(),
2090 host_priv
) != KERN_SUCCESS
;
2094 int get_audit_token_pid(audit_token_t
*audit_token
);
2097 get_audit_token_pid(audit_token_t
*audit_token
)
2099 /* keep in-sync with set_security_token (above) */
2101 return (int)audit_token
->val
[5];
2108 * Fill in a struct xucred based on a kauth_cred_t.
2112 cru2x(kauth_cred_t cr
, struct xucred
*xcr
)
2114 posix_cred_t pcr
= posix_cred_get(cr
);
2116 bzero(xcr
, sizeof(*xcr
));
2117 xcr
->cr_version
= XUCRED_VERSION
;
2118 xcr
->cr_uid
= kauth_cred_getuid(cr
);
2119 xcr
->cr_ngroups
= pcr
->cr_ngroups
;
2120 bcopy(pcr
->cr_groups
, xcr
->cr_groups
, sizeof(xcr
->cr_groups
));