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
)
507 * Description: Core implementation of setsid().
510 setsid_internal(proc_t p
)
512 struct pgrp
* pg
= PGRP_NULL
;
514 if (p
->p_pgrpid
== p
->p_pid
|| (pg
= pgfind(p
->p_pid
)) || p
->p_lflag
& P_LINVFORK
) {
515 if (pg
!= PGRP_NULL
) {
520 /* enter pgrp works with its own pgrp refcount */
521 (void)enterpgrp(p
, p
->p_pid
, 1);
529 * Description: Create a new session and set the process group ID to the
535 * EPERM Permission denied
537 * Notes: If the calling process is not the process group leader; there
538 * is no existing process group with its ID, and we are not
539 * currently in vfork, then this function will create a new
540 * session, a new process group, and put the caller in the
541 * process group (as the sole member) and make it the session
542 * leader (as the sole process in the session).
544 * The existing controlling tty (if any) will be dissociated
545 * from the process, and the next non-O_NOCTTY open of a tty
546 * will establish a new controlling tty.
548 * XXX: Belongs in kern_proc.c
551 setsid(proc_t p
, __unused
struct setsid_args
*uap
, int32_t *retval
)
553 int rc
= setsid_internal(p
);
564 * Description: set process group ID for job control
566 * Parameters: uap->pid Process to change
567 * uap->pgid Process group to join or create
570 * ESRCH pid is not the caller or a child of
572 * enterpgrp:ESRCH No such process
573 * EACCES Permission denied due to exec
574 * EINVAL Invalid argument
575 * EPERM The target process is not in the same
576 * session as the calling process
577 * EPERM The target process is a session leader
578 * EPERM pid and pgid are not the same, and
579 * there is no process in the calling
580 * process whose process group ID matches
583 * Notes: This function will cause the target process to either join
584 * an existing process process group, or create a new process
585 * group in the session of the calling process. It cannot be
586 * used to change the process group ID of a process which is
587 * already a session leader.
589 * If the target pid is 0, the pid of the calling process is
590 * substituted as the new target; if pgid is 0, the target pid
591 * is used as the target process group ID.
593 * Legacy: This system call entry point is also used to implement the
594 * legacy library routine setpgrp(), which under POSIX
596 * XXX: Belongs in kern_proc.c
599 setpgid(proc_t curp
, struct setpgid_args
*uap
, __unused
int32_t *retval
)
601 proc_t targp
= PROC_NULL
; /* target process */
602 struct pgrp
*pg
= PGRP_NULL
; /* target pgrp */
606 struct session
* curp_sessp
= SESSION_NULL
;
607 struct session
* targp_sessp
= SESSION_NULL
;
609 curp_sessp
= proc_session(curp
);
611 if (uap
->pid
!= 0 && uap
->pid
!= curp
->p_pid
) {
612 if ((targp
= proc_find(uap
->pid
)) == 0 || !inferior(targp
)) {
613 if (targp
!= PROC_NULL
) {
620 targp_sessp
= proc_session(targp
);
621 if (targp_sessp
!= curp_sessp
) {
625 if (targp
->p_flag
& P_EXEC
) {
631 targp_sessp
= proc_session(targp
);
634 if (SESS_LEADER(targp
, targp_sessp
)) {
638 if (targp_sessp
!= SESSION_NULL
) {
639 session_rele(targp_sessp
);
640 targp_sessp
= SESSION_NULL
;
647 if (uap
->pgid
== 0) {
648 uap
->pgid
= targp
->p_pid
;
649 } else if (uap
->pgid
!= targp
->p_pid
) {
650 if ((pg
= pgfind(uap
->pgid
)) == 0) {
654 samesess
= (pg
->pg_session
!= curp_sessp
);
661 error
= enterpgrp(targp
, uap
->pgid
, 0);
663 if (targp_sessp
!= SESSION_NULL
) {
664 session_rele(targp_sessp
);
666 if (curp_sessp
!= SESSION_NULL
) {
667 session_rele(curp_sessp
);
679 * Description: Is current process tainted by uid or gid changes system call
683 * Returns: 0 Not tainted
686 * Notes: A process is considered tainted if it was created as a retult
687 * of an execve call from an imnage that had either the SUID or
688 * SGID bit set on the executable, or if it has changed any of its
689 * real, effective, or saved user or group IDs since beginning
693 proc_issetugid(proc_t p
)
695 return (p
->p_flag
& P_SUGID
) ? 1 : 0;
699 issetugid(proc_t p
, __unused
struct issetugid_args
*uap
, int32_t *retval
)
702 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
703 * we use P_SUGID because we consider changing the owners as
704 * "tainting" as well.
705 * This is significant for procs that start as root and "become"
706 * a user without an exec - programs cannot know *everything*
707 * that libc *might* have put in their data segment.
710 *retval
= proc_issetugid(p
);
718 * Description: Set user ID system call
720 * Parameters: uap->uid uid to set
723 * suser:EPERM Permission denied
725 * Notes: If called by a privileged process, this function will set the
726 * real, effective, and saved uid to the requested value.
728 * If called from an unprivileged process, but uid is equal to the
729 * real or saved uid, then the effective uid will be set to the
730 * requested value, but the real and saved uid will not change.
732 * If the credential is changed as a result of this call, then we
733 * flag the process as having set privilege since the last exec.
736 setuid(proc_t p
, struct setuid_args
*uap
, __unused
int32_t *retval
)
739 uid_t svuid
= KAUTH_UID_NONE
;
740 uid_t ruid
= KAUTH_UID_NONE
;
741 uid_t gmuid
= KAUTH_UID_NONE
;
743 kauth_cred_t my_cred
, my_new_cred
;
744 posix_cred_t my_pcred
;
748 /* get current credential and take a reference while we muck with it */
749 my_cred
= kauth_cred_proc_ref(p
);
750 my_pcred
= posix_cred_get(my_cred
);
752 DEBUG_CRED_ENTER("setuid (%d/%d): %p %d\n", p
->p_pid
, (p
->p_pptr
? p
->p_pptr
->p_pid
: 0), my_cred
, uap
->uid
);
756 if (uid
!= my_pcred
->cr_ruid
&& /* allow setuid(getuid()) */
757 uid
!= my_pcred
->cr_svuid
&& /* allow setuid(saved uid) */
758 (error
= suser(my_cred
, &p
->p_acflag
))) {
759 kauth_cred_unref(&my_cred
);
764 * If we are privileged, then set the saved and real UID too;
765 * otherwise, just set the effective UID
767 if (suser(my_cred
, &p
->p_acflag
) == 0) {
771 svuid
= KAUTH_UID_NONE
;
772 ruid
= KAUTH_UID_NONE
;
775 * Only set the gmuid if the current cred has not opt'ed out;
776 * this normally only happens when calling setgroups() instead
777 * of initgroups() to set an explicit group list, or one of the
778 * other group manipulation functions is invoked and results in
779 * a dislocation (i.e. the credential group membership changes
780 * to something other than the default list for the user, as
781 * in entering a group or leaving an exclusion group).
783 if (!(my_pcred
->cr_flags
& CRF_NOMEMBERD
)) {
788 * Set the credential with new info. If there is no change,
789 * we get back the same credential we passed in; if there is
790 * a change, we drop the reference on the credential we
791 * passed in. The subsequent compare is safe, because it is
792 * a pointer compare rather than a contents compare.
794 my_new_cred
= kauth_cred_setresuid(my_cred
, ruid
, uid
, svuid
, gmuid
);
795 if (my_cred
!= my_new_cred
) {
796 DEBUG_CRED_CHANGE("setuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p
->p_pid
, my_cred
, my_pcred
->cr_flags
, my_new_cred
, posix_cred_get(my_new_cred
)->cr_flags
);
799 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
800 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
801 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
802 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
803 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
804 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
806 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
807 (void)chgproccnt(ruid
, 1);
812 * We need to protect for a race where another thread
813 * also changed the credential after we took our
814 * reference. If p_ucred has changed then we should
815 * restart this again with the new cred.
817 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
819 if (p
->p_ucred
!= my_cred
) {
820 proc_ucred_unlock(p
);
822 * We didn't successfully switch to the new ruid, so decrement
823 * the procs/uid count that we incremented above.
825 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
826 (void)chgproccnt(ruid
, -1);
828 kauth_cred_unref(&my_new_cred
);
829 my_cred
= kauth_cred_proc_ref(p
);
830 my_pcred
= posix_cred_get(my_cred
);
834 p
->p_ucred
= my_new_cred
;
835 /* update cred on proc */
836 PROC_UPDATE_CREDS_ONPROC(p
);
838 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
839 proc_ucred_unlock(p
);
841 * If we've updated the ruid, decrement the count of procs running
842 * under the previous ruid
844 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
845 (void)chgproccnt(my_pcred
->cr_ruid
, -1);
850 /* Drop old proc reference or our extra reference */
851 kauth_cred_unref(&my_cred
);
853 set_security_token(p
);
861 * Description: Set effective user ID system call
863 * Parameters: uap->euid effective uid to set
866 * suser:EPERM Permission denied
868 * Notes: If called by a privileged process, or called from an
869 * unprivileged process but euid is equal to the real or saved
870 * uid, then the effective uid will be set to the requested
871 * value, but the real and saved uid will not change.
873 * If the credential is changed as a result of this call, then we
874 * flag the process as having set privilege since the last exec.
877 seteuid(proc_t p
, struct seteuid_args
*uap
, __unused
int32_t *retval
)
881 kauth_cred_t my_cred
, my_new_cred
;
882 posix_cred_t my_pcred
;
884 DEBUG_CRED_ENTER("seteuid: %d\n", uap
->euid
);
887 AUDIT_ARG(euid
, euid
);
889 my_cred
= kauth_cred_proc_ref(p
);
890 my_pcred
= posix_cred_get(my_cred
);
893 if (euid
!= my_pcred
->cr_ruid
&& euid
!= my_pcred
->cr_svuid
&&
894 (error
= suser(my_cred
, &p
->p_acflag
))) {
895 kauth_cred_unref(&my_cred
);
900 * Set the credential with new info. If there is no change,
901 * we get back the same credential we passed in; if there is
902 * a change, we drop the reference on the credential we
903 * passed in. The subsequent compare is safe, because it is
904 * a pointer compare rather than a contents compare.
906 my_new_cred
= kauth_cred_setresuid(my_cred
, KAUTH_UID_NONE
, euid
, KAUTH_UID_NONE
, my_pcred
->cr_gmuid
);
908 if (my_cred
!= my_new_cred
) {
909 DEBUG_CRED_CHANGE("seteuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p
->p_pid
, my_cred
, my_pcred
->cr_flags
, my_new_cred
, posix_cred_get(my_new_cred
)->cr_flags
);
913 * We need to protect for a race where another thread
914 * also changed the credential after we took our
915 * reference. If p_ucred has changed then we
916 * should restart this again with the new cred.
918 if (p
->p_ucred
!= my_cred
) {
919 proc_ucred_unlock(p
);
920 kauth_cred_unref(&my_new_cred
);
921 my_cred
= kauth_cred_proc_ref(p
);
922 my_pcred
= posix_cred_get(my_cred
);
926 p
->p_ucred
= my_new_cred
;
927 /* update cred on proc */
928 PROC_UPDATE_CREDS_ONPROC(p
);
929 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
930 proc_ucred_unlock(p
);
934 /* drop old proc reference or our extra reference */
935 kauth_cred_unref(&my_cred
);
937 set_security_token(p
);
945 * Description: Set real and effective user ID system call
947 * Parameters: uap->ruid real uid to set
948 * uap->euid effective uid to set
951 * suser:EPERM Permission denied
953 * Notes: A value of -1 is a special case indicating that the uid for
954 * which that value is specified not be changed. If both values
955 * are specified as -1, no action is taken.
957 * If called by a privileged process, the real and effective uid
958 * will be set to the new value(s) specified.
960 * If called from an unprivileged process, the real uid may be
961 * set to the current value of the real uid, or to the current
962 * value of the saved uid. The effective uid may be set to the
963 * current value of any of the effective, real, or saved uid.
965 * If the newly requested real uid or effective uid does not
966 * match the saved uid, then set the saved uid to the new
967 * effective uid (potentially unrecoverably dropping saved
970 * If the credential is changed as a result of this call, then we
971 * flag the process as having set privilege since the last exec.
974 setreuid(proc_t p
, struct setreuid_args
*uap
, __unused
int32_t *retval
)
978 kauth_cred_t my_cred
, my_new_cred
;
979 posix_cred_t my_pcred
;
981 DEBUG_CRED_ENTER("setreuid %d %d\n", uap
->ruid
, uap
->euid
);
985 if (ruid
== (uid_t
)-1) {
986 ruid
= KAUTH_UID_NONE
;
988 if (euid
== (uid_t
)-1) {
989 euid
= KAUTH_UID_NONE
;
991 AUDIT_ARG(euid
, euid
);
992 AUDIT_ARG(ruid
, ruid
);
994 my_cred
= kauth_cred_proc_ref(p
);
995 my_pcred
= posix_cred_get(my_cred
);
998 if (((ruid
!= KAUTH_UID_NONE
&& /* allow no change of ruid */
999 ruid
!= my_pcred
->cr_ruid
&& /* allow ruid = ruid */
1000 ruid
!= my_pcred
->cr_uid
&& /* allow ruid = euid */
1001 ruid
!= my_pcred
->cr_svuid
) || /* allow ruid = svuid */
1002 (euid
!= KAUTH_UID_NONE
&& /* allow no change of euid */
1003 euid
!= my_pcred
->cr_uid
&& /* allow euid = euid */
1004 euid
!= my_pcred
->cr_ruid
&& /* allow euid = ruid */
1005 euid
!= my_pcred
->cr_svuid
)) && /* allow euid = svuid */
1006 (error
= suser(my_cred
, &p
->p_acflag
))) { /* allow root user any */
1007 kauth_cred_unref(&my_cred
);
1012 uid_t svuid
= KAUTH_UID_NONE
;
1014 new_euid
= my_pcred
->cr_uid
;
1016 * Set the credential with new info. If there is no change,
1017 * we get back the same credential we passed in; if there is
1018 * a change, we drop the reference on the credential we
1019 * passed in. The subsequent compare is safe, because it is
1020 * a pointer compare rather than a contents compare.
1022 if (euid
!= KAUTH_UID_NONE
&& my_pcred
->cr_uid
!= euid
) {
1023 /* changing the effective UID */
1025 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1028 * If the newly requested real uid or effective uid does
1029 * not match the saved uid, then set the saved uid to the
1030 * new effective uid. We are protected from escalation
1031 * by the prechecking.
1033 if (my_pcred
->cr_svuid
!= uap
->ruid
&&
1034 my_pcred
->cr_svuid
!= uap
->euid
) {
1036 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1039 my_new_cred
= kauth_cred_setresuid(my_cred
, ruid
, euid
, svuid
, my_pcred
->cr_gmuid
);
1041 if (my_cred
!= my_new_cred
) {
1042 DEBUG_CRED_CHANGE("setreuid CH(%d): %p/0x%08x -> %p/0x%08x\n", p
->p_pid
, my_cred
, my_pcred
->cr_flags
, my_new_cred
, posix_cred_get(my_new_cred
)->cr_flags
);
1045 * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
1046 * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
1047 * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
1048 * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
1049 * may be able to decrement the proc count of B before we can increment it. This results in a panic.
1050 * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
1052 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1053 (void)chgproccnt(ruid
, 1);
1058 * We need to protect for a race where another thread
1059 * also changed the credential after we took our
1060 * reference. If p_ucred has changed then we should
1061 * restart this again with the new cred.
1063 * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
1065 if (p
->p_ucred
!= my_cred
) {
1066 proc_ucred_unlock(p
);
1067 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1069 * We didn't successfully switch to the new ruid, so decrement
1070 * the procs/uid count that we incremented above.
1072 (void)chgproccnt(ruid
, -1);
1074 kauth_cred_unref(&my_new_cred
);
1075 my_cred
= kauth_cred_proc_ref(p
);
1076 my_pcred
= posix_cred_get(my_cred
);
1081 p
->p_ucred
= my_new_cred
;
1082 /* update cred on proc */
1083 PROC_UPDATE_CREDS_ONPROC(p
);
1084 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1085 proc_ucred_unlock(p
);
1087 if (ruid
!= KAUTH_UID_NONE
&& !proc_has_persona(p
)) {
1089 * We switched to a new ruid, so decrement the count of procs running
1090 * under the previous ruid
1092 (void)chgproccnt(my_pcred
->cr_ruid
, -1);
1097 /* drop old proc reference or our extra reference */
1098 kauth_cred_unref(&my_cred
);
1100 set_security_token(p
);
1108 * Description: Set group ID system call
1110 * Parameters: uap->gid gid to set
1112 * Returns: 0 Success
1113 * suser:EPERM Permission denied
1115 * Notes: If called by a privileged process, this function will set the
1116 * real, effective, and saved gid to the requested value.
1118 * If called from an unprivileged process, but gid is equal to the
1119 * real or saved gid, then the effective gid will be set to the
1120 * requested value, but the real and saved gid will not change.
1122 * If the credential is changed as a result of this call, then we
1123 * flag the process as having set privilege since the last exec.
1125 * As an implementation detail, the effective gid is stored as
1126 * the first element of the supplementary group list, and
1127 * therefore the effective group list may be reordered to keep
1128 * the supplementary group list unchanged.
1131 setgid(proc_t p
, struct setgid_args
*uap
, __unused
int32_t *retval
)
1134 gid_t rgid
= KAUTH_GID_NONE
;
1135 gid_t svgid
= KAUTH_GID_NONE
;
1137 kauth_cred_t my_cred
, my_new_cred
;
1138 posix_cred_t my_pcred
;
1140 DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p
->p_pid
, (p
->p_pptr
? p
->p_pptr
->p_pid
: 0), uap
->gid
);
1143 AUDIT_ARG(gid
, gid
);
1145 /* get current credential and take a reference while we muck with it */
1146 my_cred
= kauth_cred_proc_ref(p
);
1147 my_pcred
= posix_cred_get(my_cred
);
1150 if (gid
!= my_pcred
->cr_rgid
&& /* allow setgid(getgid()) */
1151 gid
!= my_pcred
->cr_svgid
&& /* allow setgid(saved gid) */
1152 (error
= suser(my_cred
, &p
->p_acflag
))) {
1153 kauth_cred_unref(&my_cred
);
1158 * If we are privileged, then set the saved and real GID too;
1159 * otherwise, just set the effective GID
1161 if (suser(my_cred
, &p
->p_acflag
) == 0) {
1165 svgid
= KAUTH_GID_NONE
;
1166 rgid
= KAUTH_GID_NONE
;
1170 * Set the credential with new info. If there is no change,
1171 * we get back the same credential we passed in; if there is
1172 * a change, we drop the reference on the credential we
1173 * passed in. The subsequent compare is safe, because it is
1174 * a pointer compare rather than a contents compare.
1176 my_new_cred
= kauth_cred_setresgid(my_cred
, rgid
, gid
, svgid
);
1177 if (my_cred
!= my_new_cred
) {
1178 DEBUG_CRED_CHANGE("setgid(CH)%d: %p/0x%08x->%p/0x%08x\n", p
->p_pid
, my_cred
, my_cred
->cr_flags
, my_new_cred
, my_new_cred
->cr_flags
);
1182 * We need to protect for a race where another thread
1183 * also changed the credential after we took our
1184 * reference. If p_ucred has changed then we
1185 * should restart this again with the new cred.
1187 if (p
->p_ucred
!= my_cred
) {
1188 proc_ucred_unlock(p
);
1189 kauth_cred_unref(&my_new_cred
);
1191 my_cred
= kauth_cred_proc_ref(p
);
1192 my_pcred
= posix_cred_get(my_cred
);
1195 p
->p_ucred
= my_new_cred
;
1196 /* update cred on proc */
1197 PROC_UPDATE_CREDS_ONPROC(p
);
1198 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1199 proc_ucred_unlock(p
);
1203 /* Drop old proc reference or our extra reference */
1204 kauth_cred_unref(&my_cred
);
1206 set_security_token(p
);
1214 * Description: Set effective group ID system call
1216 * Parameters: uap->egid effective gid to set
1218 * Returns: 0 Success
1221 * Notes: If called by a privileged process, or called from an
1222 * unprivileged process but egid is equal to the real or saved
1223 * gid, then the effective gid will be set to the requested
1224 * value, but the real and saved gid will not change.
1226 * If the credential is changed as a result of this call, then we
1227 * flag the process as having set privilege since the last exec.
1229 * As an implementation detail, the effective gid is stored as
1230 * the first element of the supplementary group list, and
1231 * therefore the effective group list may be reordered to keep
1232 * the supplementary group list unchanged.
1235 setegid(proc_t p
, struct setegid_args
*uap
, __unused
int32_t *retval
)
1239 kauth_cred_t my_cred
, my_new_cred
;
1240 posix_cred_t my_pcred
;
1242 DEBUG_CRED_ENTER("setegid %d\n", uap
->egid
);
1245 AUDIT_ARG(egid
, egid
);
1247 /* get current credential and take a reference while we muck with it */
1248 my_cred
= kauth_cred_proc_ref(p
);
1249 my_pcred
= posix_cred_get(my_cred
);
1253 if (egid
!= my_pcred
->cr_rgid
&&
1254 egid
!= my_pcred
->cr_svgid
&&
1255 (error
= suser(my_cred
, &p
->p_acflag
))) {
1256 kauth_cred_unref(&my_cred
);
1260 * Set the credential with new info. If there is no change,
1261 * we get back the same credential we passed in; if there is
1262 * a change, we drop the reference on the credential we
1263 * passed in. The subsequent compare is safe, because it is
1264 * a pointer compare rather than a contents compare.
1266 my_new_cred
= kauth_cred_setresgid(my_cred
, KAUTH_GID_NONE
, egid
, KAUTH_GID_NONE
);
1267 if (my_cred
!= my_new_cred
) {
1268 DEBUG_CRED_CHANGE("setegid(CH)%d: %p/0x%08x->%p/0x%08x\n", p
->p_pid
, my_cred
, my_pcred
->cr_flags
, my_new_cred
, posix_cred_get(my_new_cred
)->cr_flags
);
1272 * We need to protect for a race where another thread
1273 * also changed the credential after we took our
1274 * reference. If p_ucred has changed then we
1275 * should restart this again with the new cred.
1277 if (p
->p_ucred
!= my_cred
) {
1278 proc_ucred_unlock(p
);
1279 kauth_cred_unref(&my_new_cred
);
1281 my_cred
= kauth_cred_proc_ref(p
);
1282 my_pcred
= posix_cred_get(my_cred
);
1285 p
->p_ucred
= my_new_cred
;
1286 /* update cred on proc */
1287 PROC_UPDATE_CREDS_ONPROC(p
);
1288 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1289 proc_ucred_unlock(p
);
1294 /* Drop old proc reference or our extra reference */
1295 kauth_cred_unref(&my_cred
);
1297 set_security_token(p
);
1304 * Description: Set real and effective group ID system call
1306 * Parameters: uap->rgid real gid to set
1307 * uap->egid effective gid to set
1309 * Returns: 0 Success
1310 * suser:EPERM Permission denied
1312 * Notes: A value of -1 is a special case indicating that the gid for
1313 * which that value is specified not be changed. If both values
1314 * are specified as -1, no action is taken.
1316 * If called by a privileged process, the real and effective gid
1317 * will be set to the new value(s) specified.
1319 * If called from an unprivileged process, the real gid may be
1320 * set to the current value of the real gid, or to the current
1321 * value of the saved gid. The effective gid may be set to the
1322 * current value of any of the effective, real, or saved gid.
1324 * If the new real and effective gid will not be equal, or the
1325 * new real or effective gid is not the same as the saved gid,
1326 * then the saved gid will be updated to reflect the new
1327 * effective gid (potentially unrecoverably dropping saved
1330 * If the credential is changed as a result of this call, then we
1331 * flag the process as having set privilege since the last exec.
1333 * As an implementation detail, the effective gid is stored as
1334 * the first element of the supplementary group list, and
1335 * therefore the effective group list may be reordered to keep
1336 * the supplementary group list unchanged.
1339 setregid(proc_t p
, struct setregid_args
*uap
, __unused
int32_t *retval
)
1343 kauth_cred_t my_cred
, my_new_cred
;
1344 posix_cred_t my_pcred
;
1346 DEBUG_CRED_ENTER("setregid %d %d\n", uap
->rgid
, uap
->egid
);
1351 if (rgid
== (uid_t
)-1) {
1352 rgid
= KAUTH_GID_NONE
;
1354 if (egid
== (uid_t
)-1) {
1355 egid
= KAUTH_GID_NONE
;
1357 AUDIT_ARG(egid
, egid
);
1358 AUDIT_ARG(rgid
, rgid
);
1360 /* get current credential and take a reference while we muck with it */
1361 my_cred
= kauth_cred_proc_ref(p
);
1362 my_pcred
= posix_cred_get(my_cred
);
1365 if (((rgid
!= KAUTH_UID_NONE
&& /* allow no change of rgid */
1366 rgid
!= my_pcred
->cr_rgid
&& /* allow rgid = rgid */
1367 rgid
!= my_pcred
->cr_gid
&& /* allow rgid = egid */
1368 rgid
!= my_pcred
->cr_svgid
) || /* allow rgid = svgid */
1369 (egid
!= KAUTH_UID_NONE
&& /* allow no change of egid */
1370 egid
!= my_pcred
->cr_groups
[0] && /* allow no change of egid */
1371 egid
!= my_pcred
->cr_gid
&& /* allow egid = egid */
1372 egid
!= my_pcred
->cr_rgid
&& /* allow egid = rgid */
1373 egid
!= my_pcred
->cr_svgid
)) && /* allow egid = svgid */
1374 (error
= suser(my_cred
, &p
->p_acflag
))) { /* allow root user any */
1375 kauth_cred_unref(&my_cred
);
1379 uid_t new_egid
= my_pcred
->cr_gid
;
1380 uid_t new_rgid
= my_pcred
->cr_rgid
;
1381 uid_t svgid
= KAUTH_UID_NONE
;
1385 * Set the credential with new info. If there is no change,
1386 * we get back the same credential we passed in; if there is
1387 * a change, we drop the reference on the credential we
1388 * passed in. The subsequent compare is safe, because it is
1389 * a pointer compare rather than a contents compare.
1391 if (egid
!= KAUTH_UID_NONE
&& my_pcred
->cr_gid
!= egid
) {
1392 /* changing the effective GID */
1394 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1396 if (rgid
!= KAUTH_UID_NONE
&& my_pcred
->cr_rgid
!= rgid
) {
1397 /* changing the real GID */
1399 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1402 * If the newly requested real gid or effective gid does
1403 * not match the saved gid, then set the saved gid to the
1404 * new effective gid. We are protected from escalation
1405 * by the prechecking.
1407 if (my_pcred
->cr_svgid
!= uap
->rgid
&&
1408 my_pcred
->cr_svgid
!= uap
->egid
) {
1410 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1413 my_new_cred
= kauth_cred_setresgid(my_cred
, rgid
, egid
, svgid
);
1414 if (my_cred
!= my_new_cred
) {
1415 DEBUG_CRED_CHANGE("setregid(CH)%d: %p/0x%08x->%p/0x%08x\n", p
->p_pid
, my_cred
, my_pcred
->cr_flags
, my_new_cred
, posix_cred_get(my_new_cred
)->cr_flags
);
1418 /* need to protect for a race where another thread
1419 * also changed the credential after we took our
1420 * reference. If p_ucred has changed then we
1421 * should restart this again with the new cred.
1423 if (p
->p_ucred
!= my_cred
) {
1424 proc_ucred_unlock(p
);
1425 kauth_cred_unref(&my_new_cred
);
1427 my_cred
= kauth_cred_proc_ref(p
);
1428 my_pcred
= posix_cred_get(my_cred
);
1431 p
->p_ucred
= my_new_cred
;
1432 /* update cred on proc */
1433 PROC_UPDATE_CREDS_ONPROC(p
);
1434 OSBitOrAtomic(P_SUGID
, &p
->p_flag
); /* XXX redundant? */
1435 proc_ucred_unlock(p
);
1439 /* Drop old proc reference or our extra reference */
1440 kauth_cred_unref(&my_cred
);
1442 set_security_token(p
);
1448 * Set the per-thread override identity. The first parameter can be the
1449 * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
1450 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1451 * means "revert to the per process credential"; otherwise, if permitted,
1452 * it changes the effective, real, and saved UIDs and GIDs for the current
1453 * thread to the requested UID and single GID, and clears all other GIDs.
1456 settid(proc_t p
, struct settid_args
*uap
, __unused
int32_t *retval
)
1459 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1465 AUDIT_ARG(uid
, uid
);
1466 AUDIT_ARG(gid
, gid
);
1468 if (proc_suser(p
) != 0) {
1472 if (uid
== KAUTH_UID_NONE
) {
1473 /* must already be assuming another identity in order to revert back */
1474 if ((uthread
->uu_flag
& UT_SETUID
) == 0) {
1478 /* revert to delayed binding of process credential */
1479 uc
= kauth_cred_proc_ref(p
);
1480 kauth_cred_unref(&uthread
->uu_ucred
);
1481 uthread
->uu_ucred
= uc
;
1482 uthread
->uu_flag
&= ~UT_SETUID
;
1484 kauth_cred_t my_cred
, my_new_cred
;
1486 /* cannot already be assuming another identity */
1487 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1492 * Get a new credential instance from the old if this one
1493 * changes; otherwise kauth_cred_setuidgid() returns the
1494 * same credential. We take an extra reference on the
1495 * current credential while we muck with it, so we can do
1496 * the post-compare for changes by pointer.
1498 kauth_cred_ref(uthread
->uu_ucred
);
1499 my_cred
= uthread
->uu_ucred
;
1500 my_new_cred
= kauth_cred_setuidgid(my_cred
, uid
, gid
);
1501 if (my_cred
!= my_new_cred
) {
1502 uthread
->uu_ucred
= my_new_cred
;
1504 uthread
->uu_flag
|= UT_SETUID
;
1506 /* Drop old uthread reference or our extra reference */
1507 kauth_cred_unref(&my_cred
);
1510 * XXX should potentially set per thread security token (there is
1512 * XXX it is unclear whether P_SUGID should be st at this point;
1513 * XXX in theory, it is being deprecated.
1520 * Set the per-thread override identity. Use this system call for a thread to
1521 * assume the identity of another process or to revert back to normal identity
1522 * of the current process.
1524 * When the "assume" argument is non zero the current thread will assume the
1525 * identity of the process represented by the pid argument.
1527 * When the assume argument is zero we revert back to our normal identity.
1530 settid_with_pid(proc_t p
, struct settid_with_pid_args
*uap
, __unused
int32_t *retval
)
1533 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1534 kauth_cred_t my_cred
, my_target_cred
, my_new_cred
;
1535 posix_cred_t my_target_pcred
;
1537 AUDIT_ARG(pid
, uap
->pid
);
1538 AUDIT_ARG(value32
, uap
->assume
);
1540 if (proc_suser(p
) != 0) {
1545 * XXX should potentially set per thread security token (there is
1547 * XXX it is unclear whether P_SUGID should be st at this point;
1548 * XXX in theory, it is being deprecated.
1552 * assume argument tells us to assume the identity of the process with the
1553 * id passed in the pid argument.
1555 if (uap
->assume
!= 0) {
1556 /* can't do this if we have already assumed an identity */
1557 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1561 target_proc
= proc_find(uap
->pid
);
1562 /* can't assume the identity of the kernel process */
1563 if (target_proc
== NULL
|| target_proc
== kernproc
) {
1564 if (target_proc
!= NULL
) {
1565 proc_rele(target_proc
);
1571 * Take a reference on the credential used in our target
1572 * process then use it as the identity for our current
1573 * thread. We take an extra reference on the current
1574 * credential while we muck with it, so we can do the
1575 * post-compare for changes by pointer.
1577 * The post-compare is needed for the case that our process
1578 * credential has been changed to be identical to our thread
1579 * credential following our assumption of a per-thread one,
1580 * since the credential cache will maintain a unique instance.
1582 kauth_cred_ref(uthread
->uu_ucred
);
1583 my_cred
= uthread
->uu_ucred
;
1584 my_target_cred
= kauth_cred_proc_ref(target_proc
);
1585 my_target_pcred
= posix_cred_get(my_target_cred
);
1586 my_new_cred
= kauth_cred_setuidgid(my_cred
, my_target_pcred
->cr_uid
, my_target_pcred
->cr_gid
);
1587 if (my_cred
!= my_new_cred
) {
1588 uthread
->uu_ucred
= my_new_cred
;
1591 uthread
->uu_flag
|= UT_SETUID
;
1593 /* Drop old uthread reference or our extra reference */
1594 proc_rele(target_proc
);
1595 kauth_cred_unref(&my_cred
);
1596 kauth_cred_unref(&my_target_cred
);
1602 * Otherwise, we are reverting back to normal mode of operation where
1603 * delayed binding of the process credential sets the credential in
1604 * the thread (uu_ucred)
1606 if ((uthread
->uu_flag
& UT_SETUID
) == 0) {
1610 /* revert to delayed binding of process credential */
1611 my_new_cred
= kauth_cred_proc_ref(p
);
1612 kauth_cred_unref(&uthread
->uu_ucred
);
1613 uthread
->uu_ucred
= my_new_cred
;
1614 uthread
->uu_flag
&= ~UT_SETUID
;
1623 * Description: Internal implementation for both the setgroups and initgroups
1626 * Parameters: gidsetsize Number of groups in set
1627 * gidset Pointer to group list
1628 * gmuid Base gid (initgroups only!)
1630 * Returns: 0 Success
1631 * suser:EPERM Permision denied
1632 * EINVAL Invalid gidsetsize value
1633 * copyin:EFAULT Bad gidset or gidsetsize is
1636 * Notes: When called from a thread running under an assumed per-thread
1637 * identity, this function will operate against the per-thread
1638 * credential, rather than against the process credential. In
1639 * this specific case, the process credential is verified to
1640 * still be privileged at the time of the call, rather than the
1641 * per-thread credential for this operation to be permitted.
1643 * This effectively means that setgroups/initigroups calls in
1644 * a thread running a per-thread credential should occur *after*
1645 * the settid call that created it, not before (unlike setuid,
1646 * which must be called after, since it will result in privilege
1649 * When called normally (i.e. no per-thread assumed identity),
1650 * the per process credential is updated per POSIX.
1652 * If the credential is changed as a result of this call, then we
1653 * flag the process as having set privilege since the last exec.
1656 setgroups1(proc_t p
, u_int ngrp
, user_addr_t gidset
, uid_t gmuid
, __unused
int32_t *retval
)
1658 gid_t newgroups
[NGROUPS
] = { 0 };
1661 DEBUG_CRED_ENTER("setgroups1 (%d/%d): %d 0x%016x %d\n", p
->p_pid
,
1662 (p
->p_pptr
? p
->p_pptr
->p_pid
: 0), ngrp
, gidset
, gmuid
);
1664 if (ngrp
> NGROUPS
) {
1669 error
= copyin(gidset
,
1670 (caddr_t
)newgroups
, ngrp
* sizeof(gid_t
));
1675 return setgroups_internal(p
, ngrp
, newgroups
, gmuid
);
1679 setgroups_internal(proc_t p
, u_int ngrp
, gid_t
*newgroups
, uid_t gmuid
)
1681 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1682 kauth_cred_t my_cred
, my_new_cred
;
1685 my_cred
= kauth_cred_proc_ref(p
);
1686 if ((error
= suser(my_cred
, &p
->p_acflag
))) {
1687 kauth_cred_unref(&my_cred
);
1696 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1698 int my_cred_flags
= uthread
->uu_ucred
->cr_flags
;
1699 #endif /* DEBUG_CRED */
1700 kauth_cred_unref(&my_cred
);
1703 * If this thread is under an assumed identity, set the
1704 * supplementary grouplist on the thread credential instead
1705 * of the process one. If we were the only reference holder,
1706 * the credential is updated in place, otherwise, our reference
1707 * is dropped and we get back a different cred with a reference
1708 * already held on it. Because this is per-thread, we don't
1709 * need the referencing/locking/retry required for per-process.
1711 my_cred
= uthread
->uu_ucred
;
1712 uthread
->uu_ucred
= kauth_cred_setgroups(my_cred
, &newgroups
[0], ngrp
, gmuid
);
1714 if (my_cred
!= uthread
->uu_ucred
) {
1715 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p
->p_pid
, my_cred
, my_cred_flags
, uthread
->uu_ucred
, uthread
->uu_ucred
->cr_flags
);
1717 #endif /* DEBUG_CRED */
1720 * get current credential and take a reference while we muck
1725 * Set the credential with new info. If there is no
1726 * change, we get back the same credential we passed
1727 * in; if there is a change, we drop the reference on
1728 * the credential we passed in. The subsequent
1729 * compare is safe, because it is a pointer compare
1730 * rather than a contents compare.
1732 my_new_cred
= kauth_cred_setgroups(my_cred
, &newgroups
[0], ngrp
, gmuid
);
1733 if (my_cred
!= my_new_cred
) {
1734 DEBUG_CRED_CHANGE("setgroups1(CH)%d: %p/0x%08x->%p/0x%08x\n", p
->p_pid
, my_cred
, my_cred
->cr_flags
, my_new_cred
, my_new_cred
->cr_flags
);
1738 * We need to protect for a race where another
1739 * thread also changed the credential after we
1740 * took our reference. If p_ucred has
1741 * changed then we should restart this again
1742 * with the new cred.
1744 if (p
->p_ucred
!= my_cred
) {
1745 proc_ucred_unlock(p
);
1746 kauth_cred_unref(&my_new_cred
);
1747 my_cred
= kauth_cred_proc_ref(p
);
1751 p
->p_ucred
= my_new_cred
;
1752 /* update cred on proc */
1753 PROC_UPDATE_CREDS_ONPROC(p
);
1754 OSBitOrAtomic(P_SUGID
, &p
->p_flag
);
1755 proc_ucred_unlock(p
);
1759 /* Drop old proc reference or our extra reference */
1760 AUDIT_ARG(groupset
, posix_cred_get(my_cred
)->cr_groups
, ngrp
);
1761 kauth_cred_unref(&my_cred
);
1764 set_security_token(p
);
1774 * Description: Initialize the default supplementary groups list and set the
1775 * gmuid for use by the external group resolver (if any)
1777 * Parameters: uap->gidsetsize Number of groups in set
1778 * uap->gidset Pointer to group list
1779 * uap->gmuid Base gid
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 function opts *IN* to memberd participation
1788 * The normal purpose of this function is for a privileged
1789 * process to indicate supplementary groups and identity for
1790 * participation in extended group membership resolution prior
1791 * to dropping privilege by assuming a specific user identity.
1793 * It is the first half of the primary mechanism whereby user
1794 * identity is established to the system by programs such as
1795 * /usr/bin/login. The second half is the drop of uid privilege
1796 * for a specific uid corresponding to the user.
1798 * See also: setgroups1()
1801 initgroups(proc_t p
, struct initgroups_args
*uap
, __unused
int32_t *retval
)
1803 DEBUG_CRED_ENTER("initgroups\n");
1805 return setgroups1(p
, uap
->gidsetsize
, uap
->gidset
, uap
->gmuid
, retval
);
1812 * Description: Initialize the default supplementary groups list
1814 * Parameters: gidsetsize Number of groups in set
1815 * gidset Pointer to group list
1817 * Returns: 0 Success
1818 * setgroups1:EPERM Permision denied
1819 * setgroups1:EINVAL Invalid gidsetsize value
1820 * setgroups1:EFAULT Bad gidset or gidsetsize is
1822 * Notes: This functions opts *OUT* of memberd participation.
1824 * This function exists for compatibility with POSIX. Most user
1825 * programs should use initgroups() instead to ensure correct
1826 * participation in group membership resolution when utilizing
1827 * a directory service for authentication.
1829 * It is identical to an initgroups() call with a gmuid argument
1830 * of KAUTH_UID_NONE.
1832 * See also: setgroups1()
1835 setgroups(proc_t p
, struct setgroups_args
*uap
, __unused
int32_t *retval
)
1837 DEBUG_CRED_ENTER("setgroups\n");
1839 return setgroups1(p
, uap
->gidsetsize
, uap
->gidset
, KAUTH_UID_NONE
, retval
);
1844 * Set the per-thread/per-process supplementary groups list.
1846 * XXX implement setsgroups
1851 setsgroups(__unused proc_t p
, __unused
struct setsgroups_args
*uap
, __unused
int32_t *retval
)
1857 * Set the per-thread/per-process whiteout groups list.
1859 * XXX implement setwgroups
1864 setwgroups(__unused proc_t p
, __unused
struct setwgroups_args
*uap
, __unused
int32_t *retval
)
1871 * Check if gid is a member of the group set.
1873 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1877 groupmember(gid_t gid
, kauth_cred_t cred
)
1881 if (kauth_cred_ismember_gid(cred
, gid
, &is_member
) == 0 && is_member
) {
1889 * Test whether the specified credentials imply "super-user"
1890 * privilege; if so, and we have accounting info, set the flag
1891 * indicating use of super-powers.
1892 * Returns 0 or error.
1894 * XXX This interface is going away; use kauth_cred_issuser() directly
1897 * Note: This interface exists to implement the "has used privilege"
1898 * bit (ASU) in the p_acflags field of the process, which is
1899 * only externalized via private sysctl and in process accounting
1900 * records. The flag is technically not required in either case.
1903 suser(kauth_cred_t cred
, u_short
*acflag
)
1906 if (!IS_VALID_CRED(cred
)) {
1910 if (kauth_cred_getuid(cred
) == 0) {
1923 * Description: Get login name, if available.
1925 * Parameters: uap->namebuf User buffer for return
1926 * uap->namelen User buffer length
1928 * Returns: 0 Success
1931 * Notes: Intended to obtain a string containing the user name of the
1932 * user associated with the controlling terminal for the calling
1935 * Not very useful on modern systems, due to inherent length
1936 * limitations for the static array in the session structure
1937 * which is used to store the login name.
1939 * Permitted to return NULL
1941 * XXX: Belongs in kern_proc.c
1944 getlogin(proc_t p
, struct getlogin_args
*uap
, __unused
int32_t *retval
)
1946 char buffer
[MAXLOGNAME
+ 1];
1947 struct session
* sessp
;
1949 bzero(buffer
, MAXLOGNAME
+ 1);
1951 sessp
= proc_session(p
);
1953 if (uap
->namelen
> MAXLOGNAME
) {
1954 uap
->namelen
= MAXLOGNAME
;
1957 if (sessp
!= SESSION_NULL
) {
1958 session_lock(sessp
);
1959 bcopy( sessp
->s_login
, buffer
, uap
->namelen
);
1960 session_unlock(sessp
);
1962 session_rele(sessp
);
1964 return copyout((caddr_t
)buffer
, uap
->namebuf
, uap
->namelen
);
1968 setlogin_internal(proc_t p
, const char login
[static MAXLOGNAME
])
1970 struct session
*sessp
= proc_session(p
);
1972 if (sessp
!= SESSION_NULL
) {
1973 session_lock(sessp
);
1974 bcopy(login
, sessp
->s_login
, MAXLOGNAME
);
1975 session_unlock(sessp
);
1976 session_rele(sessp
);
1983 * Description: Set login name.
1985 * Parameters: uap->namebuf User buffer containing name
1987 * Returns: 0 Success
1988 * suser:EPERM Permission denied
1989 * copyinstr:EFAULT User buffer invalid
1990 * copyinstr:EINVAL Supplied name was too long
1992 * Notes: This is a utility system call to support getlogin().
1994 * XXX: Belongs in kern_proc.c
1997 setlogin(proc_t p
, struct setlogin_args
*uap
, __unused
int32_t *retval
)
2001 char buffer
[MAXLOGNAME
+ 1];
2003 if ((error
= proc_suser(p
))) {
2007 bzero(&buffer
[0], MAXLOGNAME
+ 1);
2010 error
= copyinstr(uap
->namebuf
,
2011 (caddr_t
) &buffer
[0],
2012 MAXLOGNAME
- 1, (size_t *)&dummy
);
2014 setlogin_internal(p
, buffer
);
2017 AUDIT_ARG(text
, buffer
);
2018 } else if (error
== ENAMETOOLONG
) {
2025 /* Set the secrity token of the task with current euid and eguid */
2027 * XXX This needs to change to give the task a reference and/or an opaque
2031 set_security_token(proc_t p
)
2033 return set_security_token_task_internal(p
, p
->task
);
2037 proc_calc_audit_token(proc_t p
, kauth_cred_t my_cred
, audit_token_t
*audit_token
)
2039 posix_cred_t my_pcred
= posix_cred_get(my_cred
);
2042 * The current layout of the Mach audit token explicitly
2043 * adds these fields. But nobody should rely on such
2044 * a literal representation. Instead, the BSM library
2045 * provides a function to convert an audit token into
2046 * a BSM subject. Use of that mechanism will isolate
2047 * the user of the trailer from future representation
2050 audit_token
->val
[0] = my_cred
->cr_audit
.as_aia_p
->ai_auid
;
2051 audit_token
->val
[1] = my_pcred
->cr_uid
;
2052 audit_token
->val
[2] = my_pcred
->cr_gid
;
2053 audit_token
->val
[3] = my_pcred
->cr_ruid
;
2054 audit_token
->val
[4] = my_pcred
->cr_rgid
;
2055 audit_token
->val
[5] = p
->p_pid
;
2056 audit_token
->val
[6] = my_cred
->cr_audit
.as_aia_p
->ai_asid
;
2057 audit_token
->val
[7] = p
->p_idversion
;
2061 * Set the secrity token of the task with current euid and eguid
2062 * The function takes a proc and a task, where proc->task might point to a
2063 * different task if called from exec.
2067 set_security_token_task_internal(proc_t p
, void *t
)
2069 kauth_cred_t my_cred
;
2070 security_token_t sec_token
;
2071 audit_token_t audit_token
;
2072 host_priv_t host_priv
;
2076 * Don't allow a vfork child to override the parent's token settings
2077 * (since they share a task). Instead, the child will just have to
2078 * suffer along using the parent's token until the exec(). It's all
2079 * undefined behavior anyway, right?
2081 if (task
== current_task()) {
2083 uthread
= (uthread_t
)get_bsdthread_info(current_thread());
2084 if (uthread
->uu_flag
& UT_VFORK
) {
2089 my_cred
= kauth_cred_proc_ref(p
);
2091 proc_calc_audit_token(p
, my_cred
, &audit_token
);
2093 /* XXX mach_init doesn't have a p_ucred when it calls this function */
2094 if (IS_VALID_CRED(my_cred
)) {
2095 sec_token
.val
[0] = kauth_cred_getuid(my_cred
);
2096 sec_token
.val
[1] = kauth_cred_getgid(my_cred
);
2098 sec_token
.val
[0] = 0;
2099 sec_token
.val
[1] = 0;
2102 host_priv
= (sec_token
.val
[0]) ? HOST_PRIV_NULL
: host_priv_self();
2104 if (host_priv
!= HOST_PRIV_NULL
&& mac_system_check_host_priv(my_cred
)) {
2105 host_priv
= HOST_PRIV_NULL
;
2108 kauth_cred_unref(&my_cred
);
2110 #if DEVELOPMENT || DEBUG
2112 * Update the pid an proc name for importance base if any
2114 task_importance_update_owner_info(task
);
2117 return host_security_set_task_token(host_security_self(),
2121 host_priv
) != KERN_SUCCESS
;
2125 proc_parent_audit_token(proc_t p
, audit_token_t
*token_out
)
2128 kauth_cred_t my_cred
;
2133 my_cred
= kauth_cred_proc_ref(parent
);
2134 proc_calc_audit_token(parent
, my_cred
, token_out
);
2135 kauth_cred_unref(&my_cred
);
2141 int get_audit_token_pid(audit_token_t
*audit_token
);
2144 get_audit_token_pid(audit_token_t
*audit_token
)
2146 /* keep in-sync with set_security_token (above) */
2148 return (int)audit_token
->val
[5];
2155 * Fill in a struct xucred based on a kauth_cred_t.
2159 cru2x(kauth_cred_t cr
, struct xucred
*xcr
)
2161 posix_cred_t pcr
= posix_cred_get(cr
);
2163 bzero(xcr
, sizeof(*xcr
));
2164 xcr
->cr_version
= XUCRED_VERSION
;
2165 xcr
->cr_uid
= kauth_cred_getuid(cr
);
2166 xcr
->cr_ngroups
= pcr
->cr_ngroups
;
2167 bcopy(pcr
->cr_groups
, xcr
->cr_groups
, sizeof(xcr
->cr_groups
));