2 * Copyright (c) 2000-2007 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@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
31 * The Regents of the University of California. All rights reserved.
32 * (c) UNIX System Laboratories, Inc.
33 * All or some portions of this file are derived from material licensed
34 * to the University of California by American Telephone and Telegraph
35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36 * the permission of UNIX System Laboratories, Inc.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
69 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
70 * support for mandatory and extensible security protections. This notice
71 * is included in support of clause 2.2 (b) of the Apple Public License,
75 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
76 * support for mandatory and extensible security protections. This notice
77 * is included in support of clause 2.2 (b) of the Apple Public License,
82 * System calls related to processes and protection
85 #include <sys/param.h>
87 #include <sys/systm.h>
88 #include <sys/ucred.h>
89 #include <sys/proc_internal.h>
91 #include <sys/kauth.h>
92 #include <sys/timeb.h>
93 #include <sys/times.h>
94 #include <sys/malloc.h>
96 #include <bsm/audit_kernel.h>
103 #include <security/mac_framework.h>
105 #include <secuity/mac_mach_internal.h>
109 #include <sys/mount_internal.h>
110 #include <sys/sysproto.h>
111 #include <mach/message.h>
112 #include <mach/host_security.h>
114 #include <kern/host.h>
115 #include <kern/task.h> /* for current_task() */
116 #include <kern/assert.h>
119 int groupmember(gid_t gid
, kauth_cred_t cred
);
122 * Credential debugging; we can track entry into a function that might
123 * change a credential, and we can track actual credential changes that
126 * Note: Does *NOT* currently include per-thread credential changes
128 * We don't use kauth_cred_print() in current debugging, but it
129 * can be used if needed when debugging is active.
132 #define DEBUG_CRED_ENTER printf
133 #define DEBUG_CRED_CHANGE printf
134 extern void kauth_cred_print(kauth_cred_t cred
);
135 #else /* !DEBUG_CRED */
136 #define DEBUG_CRED_ENTER(fmt, ...) do {} while (0)
137 #define DEBUG_CRED_CHANGE(fmt, ...) do {} while (0)
138 #endif /* !DEBUG_CRED */
145 * Description: (dis)allow this process to hold task, thread, or execption
146 * ports of processes about to exec.
148 * Parameters: uap->flag New value for flag
150 * Returns: int Previous value of flag
152 * XXX: Belongs in kern_proc.c
155 setprivexec(proc_t p
, struct setprivexec_args
*uap
, register_t
*retval
)
157 AUDIT_ARG(value
, uap
->flag
);
158 *retval
= p
->p_debugger
;
159 p
->p_debugger
= (uap
->flag
!= 0);
167 * Description: get the process ID
171 * Returns: pid_t Current process ID
173 * XXX: Belongs in kern_proc.c
176 getpid(proc_t p
, __unused
struct getpid_args
*uap
, register_t
*retval
)
187 * Description: get the parent process ID
191 * Returns: pid_t Parent process ID
193 * XXX: Belongs in kern_proc.c
196 getppid(proc_t p
, __unused
struct getppid_args
*uap
, register_t
*retval
)
207 * Description: get the process group ID of the calling process
211 * Returns: pid_t Process group ID
213 * XXX: Belongs in kern_proc.c
216 getpgrp(proc_t p
, __unused
struct getpgrp_args
*uap
, register_t
*retval
)
219 *retval
= p
->p_pgrpid
;
227 * Description: Get an arbitary pid's process group id
229 * Parameters: uap->pid The target pid
232 * ESRCH No such process
234 * Notes: We are permitted to return EPERM in the case that the target
235 * process is not in the same session as the calling process,
236 * which could be a security consideration
238 * XXX: Belongs in kern_proc.c
241 getpgid(proc_t p
, struct getpgid_args
*uap
, register_t
*retval
)
250 if ((pt
= proc_find(uap
->pid
)) == 0)
254 *retval
= pt
->p_pgrpid
;
264 * Description: Get an arbitary pid's session leaders process group ID
266 * Parameters: uap->pid The target pid
269 * ESRCH No such process
271 * Notes: We are permitted to return EPERM in the case that the target
272 * process is not in the same session as the calling process,
273 * which could be a security consideration
275 * XXX: Belongs in kern_proc.c
278 getsid(proc_t p
, struct getsid_args
*uap
, register_t
*retval
)
282 struct session
* sessp
;
288 if ((pt
= proc_find(uap
->pid
)) == 0)
292 sessp
= proc_session(pt
);
293 *retval
= sessp
->s_sid
;
305 * Description: get real user ID for caller
309 * Returns: uid_t The real uid of the caller
312 getuid(__unused proc_t p
, __unused
struct getuid_args
*uap
, register_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
, register_t
*retval
)
333 *retval
= kauth_getuid();
341 * Description: Return the per-thread override identity.
343 * Parameters: uap->uidp Address of uid_t to get uid
344 * uap->gidp Address of gid_t to get gid
347 * ESRCH No per thread identity active
350 gettid(__unused proc_t p
, struct gettid_args
*uap
, register_t
*retval
)
352 struct uthread
*uthread
= get_bsdthread_info(current_thread());
356 * If this thread is not running with an override identity, we can't
357 * return one to the caller, so return an error instead.
359 if (!(uthread
->uu_flag
& UT_SETUID
))
362 if ((error
= suword(uap
->uidp
, uthread
->uu_ucred
->cr_ruid
)))
364 if ((error
= suword(uap
->gidp
, uthread
->uu_ucred
->cr_rgid
)))
375 * Description: get the real group ID for the calling process
379 * Returns: gid_t The real gid of the caller
382 getgid(__unused proc_t p
, __unused
struct getgid_args
*uap
, register_t
*retval
)
385 *retval
= kauth_getrgid();
393 * Description: get the effective group ID for the calling process
397 * Returns: gid_t The effective gid of the caller
399 * Notes: As an implementation detail, the effective gid is stored as
400 * the first element of the supplementary group list.
402 * This could be implemented in Libc instead because of the above
406 getegid(__unused proc_t p
, __unused
struct getegid_args
*uap
, register_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
, register_t
*retval
)
451 /* grab reference while we muck around with the credential */
452 cred
= kauth_cred_get_with_ref();
454 if ((ngrp
= uap
->gidsetsize
) == 0) {
455 *retval
= cred
->cr_ngroups
;
456 kauth_cred_unref(&cred
);
459 if (ngrp
< cred
->cr_ngroups
) {
460 kauth_cred_unref(&cred
);
463 ngrp
= cred
->cr_ngroups
;
464 if ((error
= copyout((caddr_t
)cred
->cr_groups
,
466 ngrp
* sizeof(gid_t
)))) {
467 kauth_cred_unref(&cred
);
470 kauth_cred_unref(&cred
);
477 * Return the per-thread/per-process supplementary groups list.
479 #warning XXX implement getsgroups
481 getsgroups(__unused proc_t p
, __unused
struct getsgroups_args
*uap
, __unused register_t
*retval
)
488 * Return the per-thread/per-process whiteout groups list.
490 #warning XXX implement getwgroups
492 getwgroups(__unused proc_t p
, __unused
struct getwgroups_args
*uap
, __unused register_t
*retval
)
502 * Description: Create a new session and set the process group ID to the
508 * EPERM Permission denied
510 * Notes: If the calling process is not the process group leader; there
511 * is no existing process group with its ID, and we are not
512 * currently in vfork, then this function will create a new
513 * session, a new process group, and put the caller in the
514 * process group (as the sole member) and make it the session
515 * leader (as the sole process in the session).
517 * The existing controlling tty (if any) will be dissociated
518 * from the process, and the next non-O_NOCTTY open of a tty
519 * will establish a new controlling tty.
521 * XXX: Belongs in kern_proc.c
524 setsid(proc_t p
, __unused
struct setsid_args
*uap
, register_t
*retval
)
526 struct pgrp
* pg
= PGRP_NULL
;
528 if (p
->p_pgrpid
== p
->p_pid
|| (pg
= pgfind(p
->p_pid
)) || p
->p_lflag
& P_LINVFORK
) {
533 /* enter pgrp works with its own pgrp refcount */
534 (void)enterpgrp(p
, p
->p_pid
, 1);
544 * Description: set process group ID for job control
546 * Parameters: uap->pid Process to change
547 * uap->pgid Process group to join or create
550 * ESRCH pid is not the caller or a child of
552 * enterpgrp:ESRCH No such process
553 * EACCES Permission denied due to exec
554 * EINVAL Invalid argument
555 * EPERM The target process is not in the same
556 * session as the calling process
557 * EPERM The target process is a session leader
558 * EPERM pid and pgid are not the same, and
559 * there is no process in the calling
560 * process whose process group ID matches
563 * Notes: This function will cause the target process to either join
564 * an existing process process group, or create a new process
565 * group in the session of the calling process. It cannot be
566 * used to change the process group ID of a process which is
567 * already a session leader.
569 * If the target pid is 0, the pid of the calling process is
570 * substituted as the new target; if pgid is 0, the target pid
571 * is used as the target process group ID.
573 * Legacy: This system call entry point is also used to implement the
574 * legacy library routine setpgrp(), which under POSIX
576 * XXX: Belongs in kern_proc.c
579 setpgid(proc_t curp
, register struct setpgid_args
*uap
, __unused register_t
*retval
)
581 proc_t targp
= PROC_NULL
; /* target process */
582 struct pgrp
*pg
= PGRP_NULL
; /* target pgrp */
586 struct session
* curp_sessp
= SESSION_NULL
;
587 struct session
* targp_sessp
= SESSION_NULL
;
589 curp_sessp
= proc_session(curp
);
591 if (uap
->pid
!= 0 && uap
->pid
!= curp
->p_pid
) {
592 if ((targp
= proc_find(uap
->pid
)) == 0 || !inferior(targp
)) {
593 if (targp
!= PROC_NULL
)
599 targp_sessp
= proc_session(targp
);
600 if (targp_sessp
!= curp_sessp
) {
604 if (targp
->p_flag
& P_EXEC
) {
610 targp_sessp
= proc_session(targp
);
613 if (SESS_LEADER(targp
, targp_sessp
)) {
617 if (targp_sessp
!= SESSION_NULL
) {
618 session_rele(targp_sessp
);
619 targp_sessp
= SESSION_NULL
;
627 uap
->pgid
= targp
->p_pid
;
628 else if (uap
->pgid
!= targp
->p_pid
) {
629 if ((pg
= pgfind(uap
->pgid
)) == 0){
633 samesess
= (pg
->pg_session
!= curp_sessp
);
640 error
= enterpgrp(targp
, uap
->pgid
, 0);
642 if (targp_sessp
!= SESSION_NULL
)
643 session_rele(targp_sessp
);
644 if (curp_sessp
!= SESSION_NULL
)
645 session_rele(curp_sessp
);
655 * Description: Is current process tainted by uid or gid changes system call
659 * Returns: 0 Not tainted
662 * Notes: A process is considered tainted if it was created as a retult
663 * of an execve call from an imnage that had either the SUID or
664 * SGID bit set on the executable, or if it has changed any of its
665 * real, effective, or saved user or group IDs since beginning
669 issetugid(proc_t p
, __unused
struct issetugid_args
*uap
, register_t
*retval
)
672 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
673 * we use P_SUGID because we consider changing the owners as
674 * "tainting" as well.
675 * This is significant for procs that start as root and "become"
676 * a user without an exec - programs cannot know *everything*
677 * that libc *might* have put in their data segment.
680 *retval
= (p
->p_flag
& P_SUGID
) ? 1 : 0;
688 * Description: Set user ID system call
690 * Parameters: uap->uid uid to set
693 * suser:EPERM Permission denied
695 * Notes: If called by a privileged process, this function will set the
696 * real, effective, and saved uid to the requested value.
698 * If called from an unprivileged process, but uid is equal to the
699 * real or saved uid, then the effective uid will be set to the
700 * requested value, but the real and saved uid will not change.
702 * If the credential is changed as a result of this call, then we
703 * flag the process as having set privilege since the last exec.
706 setuid(proc_t p
, struct setuid_args
*uap
, __unused register_t
*retval
)
709 uid_t svuid
= KAUTH_UID_NONE
;
710 uid_t ruid
= KAUTH_UID_NONE
;
711 uid_t gmuid
= KAUTH_UID_NONE
;
713 kauth_cred_t my_cred
, my_new_cred
;
718 my_cred
= kauth_cred_proc_ref(p
);
720 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
);
721 AUDIT_ARG(uid
, uid
, 0, 0, 0);
723 if (uid
!= my_cred
->cr_ruid
&& /* allow setuid(getuid()) */
724 uid
!= my_cred
->cr_svuid
&& /* allow setuid(saved uid) */
725 (error
= suser(my_cred
, &p
->p_acflag
))) {
726 kauth_cred_unref(&my_cred
);
730 * Everything's okay, do it.
734 * If we are priviledged, then set the saved and real UID too;
735 * otherwise, just set the effective UID
737 if (suser(my_cred
, &p
->p_acflag
) == 0) {
741 * Transfer proc count to new user.
742 * chgproccnt uses list lock for protection
744 (void)chgproccnt(uid
, 1);
745 (void)chgproccnt(kauth_getruid(), -1);
748 /* get current credential and take a reference while we muck with it */
751 * Only set the gmuid if the current cred has not opt'ed out;
752 * this normally only happens when calling setgroups() instead
753 * of initgroups() to set an explicit group list, or one of the
754 * other group manipulation functions is invoked and results in
755 * a dislocation (i.e. the credential group membership changes
756 * to something other than the default list for the user, as
757 * in entering a group or leaving an exclusion group).
759 if (!(my_cred
->cr_flags
& CRF_NOMEMBERD
))
763 * Set the credential with new info. If there is no change,
764 * we get back the same credential we passed in; if there is
765 * a change, we drop the reference on the credential we
766 * passed in. The subsequent compare is safe, because it is
767 * a pointer compare rather than a contents compare.
769 my_new_cred
= kauth_cred_setresuid(my_cred
, ruid
, uid
, svuid
, gmuid
);
770 if (my_cred
!= my_new_cred
) {
772 DEBUG_CRED_CHANGE("setuid 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
);
776 * We need to protect for a race where another thread
777 * also changed the credential after we took our
778 * reference. If p_ucred has changed then we should
779 * restart this again with the new cred.
781 if (p
->p_ucred
!= my_cred
) {
783 kauth_cred_unref(&my_new_cred
);
784 my_cred
= kauth_cred_proc_ref(p
);
788 p
->p_ucred
= my_new_cred
;
789 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
794 /* Drop old proc reference or our extra reference */
795 kauth_cred_unref(&my_cred
);
797 set_security_token(p
);
805 * Description: Set effective user ID system call
807 * Parameters: uap->euid effective uid to set
810 * suser:EPERM Permission denied
812 * Notes: If called by a privileged process, or called from an
813 * unprivileged process but euid is equal to the real or saved
814 * uid, then the effective uid will be set to the requested
815 * value, but the real and saved uid will not change.
817 * If the credential is changed as a result of this call, then we
818 * flag the process as having set privilege since the last exec.
821 seteuid(proc_t p
, struct seteuid_args
*uap
, __unused register_t
*retval
)
825 kauth_cred_t my_cred
, my_new_cred
;
827 DEBUG_CRED_ENTER("seteuid: %d\n", uap
->euid
);
830 AUDIT_ARG(uid
, 0, euid
, 0, 0);
832 my_cred
= kauth_cred_proc_ref(p
);
834 if (euid
!= my_cred
->cr_ruid
&& euid
!= my_cred
->cr_svuid
&&
835 (error
= suser(my_cred
, &p
->p_acflag
))) {
836 kauth_cred_unref(&my_cred
);
841 * Everything's okay, do it. Copy credentials so other references do
842 * not see our changes. get current credential and take a reference
843 * while we muck with it
847 * Set the credential with new info. If there is no change,
848 * we get back the same credential we passed in; if there is
849 * a change, we drop the reference on the credential we
850 * passed in. The subsequent compare is safe, because it is
851 * a pointer compare rather than a contents compare.
853 my_new_cred
= kauth_cred_setresuid(my_cred
, KAUTH_UID_NONE
, euid
, KAUTH_UID_NONE
, my_cred
->cr_gmuid
);
855 if (my_cred
!= my_new_cred
) {
857 DEBUG_CRED_CHANGE("seteuid 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
);
861 * We need to protect for a race where another thread
862 * also changed the credential after we took our
863 * reference. If p_ucred has changed then we
864 * should restart this again with the new cred.
866 if (p
->p_ucred
!= my_cred
) {
868 kauth_cred_unref(&my_new_cred
);
869 my_cred
= kauth_cred_proc_ref(p
);
873 p
->p_ucred
= my_new_cred
;
874 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
879 /* drop old proc reference or our extra reference */
880 kauth_cred_unref(&my_cred
);
882 set_security_token(p
);
890 * Description: Set real and effective user ID system call
892 * Parameters: uap->ruid real uid to set
893 * uap->euid effective uid to set
896 * suser:EPERM Permission denied
898 * Notes: A value of -1 is a special case indicating that the uid for
899 * which that value is specified not be changed. If both values
900 * are specified as -1, no action is taken.
902 * If called by a privileged process, the real and effective uid
903 * will be set to the new value(s) specified.
905 * If called from an unprivileged process, the real uid may be
906 * set to the current value of the real uid, or to the current
907 * value of the saved uid. The effective uid may be set to the
908 * current value of any of the effective, real, or saved uid.
910 * If the newly requested real uid or effective uid does not
911 * match the saved uid, then set the saved uid to the new
912 * effective uid (potentially unrecoverably dropping saved
915 * If the credential is changed as a result of this call, then we
916 * flag the process as having set privilege since the last exec.
919 setreuid(proc_t p
, struct setreuid_args
*uap
, __unused register_t
*retval
)
923 kauth_cred_t my_cred
, my_new_cred
;
925 DEBUG_CRED_ENTER("setreuid %d %d\n", uap
->ruid
, uap
->euid
);
929 if (ruid
== (uid_t
)-1)
930 ruid
= KAUTH_UID_NONE
;
931 if (euid
== (uid_t
)-1)
932 euid
= KAUTH_UID_NONE
;
933 AUDIT_ARG(uid
, euid
, ruid
, 0, 0);
935 my_cred
= kauth_cred_proc_ref(p
);
937 if (((ruid
!= KAUTH_UID_NONE
&& /* allow no change of ruid */
938 ruid
!= my_cred
->cr_ruid
&& /* allow ruid = ruid */
939 ruid
!= my_cred
->cr_uid
&& /* allow ruid = euid */
940 ruid
!= my_cred
->cr_svuid
) || /* allow ruid = svuid */
941 (euid
!= KAUTH_UID_NONE
&& /* allow no change of euid */
942 euid
!= my_cred
->cr_uid
&& /* allow euid = euid */
943 euid
!= my_cred
->cr_ruid
&& /* allow euid = ruid */
944 euid
!= my_cred
->cr_svuid
)) && /* allow euid = svui */
945 (error
= suser(my_cred
, &p
->p_acflag
))) { /* allow root user any */
946 kauth_cred_unref(&my_cred
);
951 * Everything's okay, do it. Copy credentials so other references do
952 * not see our changes. get current credential and take a reference
953 * while we muck with it
958 uid_t svuid
= KAUTH_UID_NONE
;
960 new_euid
= my_cred
->cr_uid
;
961 new_ruid
= my_cred
->cr_ruid
;
964 * Set the credential with new info. If there is no change,
965 * we get back the same credential we passed in; if there is
966 * a change, we drop the reference on the credential we
967 * passed in. The subsequent compare is safe, because it is
968 * a pointer compare rather than a contents compare.
970 if (euid
== KAUTH_UID_NONE
&& my_cred
->cr_uid
!= euid
) {
971 /* changing the effective UID */
973 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
975 if (ruid
!= KAUTH_UID_NONE
&& my_cred
->cr_ruid
!= ruid
) {
976 /* changing the real UID; must do user accounting */
977 /* chgproccnt uses list lock for protection */
978 (void)chgproccnt(ruid
, 1);
979 (void)chgproccnt(my_cred
->cr_ruid
, -1);
981 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
984 * If the newly requested real uid or effective uid does
985 * not match the saved uid, then set the saved uid to the
986 * new effective uid. We are protected from escalation
987 * by the prechecking.
989 if (my_cred
->cr_svuid
!= uap
->ruid
&&
990 my_cred
->cr_svuid
!= uap
->euid
) {
992 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
995 my_new_cred
= kauth_cred_setresuid(my_cred
, ruid
, euid
, svuid
, my_cred
->cr_gmuid
);
997 if (my_cred
!= my_new_cred
) {
999 DEBUG_CRED_CHANGE("setreuid 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
);
1003 * We need to protect for a race where another thread
1004 * also changed the credential after we took our
1005 * reference. If p_ucred has changed then we should
1006 * restart this again with the new cred.
1008 if (p
->p_ucred
!= my_cred
) {
1010 kauth_cred_unref(&my_new_cred
);
1011 my_cred
= kauth_cred_proc_ref(p
);
1015 p
->p_ucred
= my_new_cred
;
1016 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
); /* XXX redundant? */
1021 /* drop old proc reference or our extra reference */
1022 kauth_cred_unref(&my_cred
);
1024 set_security_token(p
);
1032 * Description: Set group ID system call
1034 * Parameters: uap->gid gid to set
1036 * Returns: 0 Success
1037 * suser:EPERM Permission denied
1039 * Notes: If called by a privileged process, this function will set the
1040 * real, effective, and saved gid to the requested value.
1042 * If called from an unprivileged process, but gid is equal to the
1043 * real or saved gid, then the effective gid will be set to the
1044 * requested value, but the real and saved gid will not change.
1046 * If the credential is changed as a result of this call, then we
1047 * flag the process as having set privilege since the last exec.
1049 * As an implementation detail, the effective gid is stored as
1050 * the first element of the supplementary group list, and
1051 * therefore the effective group list may be reordered to keep
1052 * the supplementary group list unchanged.
1055 setgid(proc_t p
, struct setgid_args
*uap
, __unused register_t
*retval
)
1058 gid_t rgid
= KAUTH_GID_NONE
;
1059 gid_t svgid
= KAUTH_GID_NONE
;
1061 kauth_cred_t my_cred
, my_new_cred
;
1063 DEBUG_CRED_ENTER("setgid(%d/%d): %d\n", p
->p_pid
, (p
->p_pptr
? p
->p_pptr
->p_pid
: 0), uap
->gid
);
1066 AUDIT_ARG(gid
, gid
, 0, 0, 0);
1068 my_cred
= kauth_cred_proc_ref(p
);
1070 if (gid
!= my_cred
->cr_rgid
&& /* allow setgid(getgid()) */
1071 gid
!= my_cred
->cr_svgid
&& /* allow setgid(saved gid) */
1072 (error
= suser(my_cred
, &p
->p_acflag
))) {
1073 kauth_cred_unref(&my_cred
);
1078 * If we are priviledged, then set the saved and real GID too;
1079 * otherwise, just set the effective GID
1081 if (suser(my_cred
, &p
->p_acflag
) == 0) {
1086 /* get current credential and take a reference while we muck with it */
1090 * Set the credential with new info. If there is no change,
1091 * we get back the same credential we passed in; if there is
1092 * a change, we drop the reference on the credential we
1093 * passed in. The subsequent compare is safe, because it is
1094 * a pointer compare rather than a contents compare.
1096 my_new_cred
= kauth_cred_setresgid(my_cred
, rgid
, gid
, svgid
);
1097 if (my_cred
!= my_new_cred
) {
1099 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
);
1103 * We need to protect for a race where another thread
1104 * also changed the credential after we took our
1105 * reference. If p_ucred has changed then we
1106 * should restart this again with the new cred.
1108 if (p
->p_ucred
!= my_cred
) {
1110 kauth_cred_unref(&my_new_cred
);
1112 my_cred
= kauth_cred_proc_ref(p
);
1115 p
->p_ucred
= my_new_cred
;
1116 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
1121 /* Drop old proc reference or our extra reference */
1122 kauth_cred_unref(&my_cred
);
1124 set_security_token(p
);
1132 * Description: Set effective group ID system call
1134 * Parameters: uap->egid effective gid to set
1136 * Returns: 0 Success
1139 * Notes: If called by a privileged process, or called from an
1140 * unprivileged process but egid is equal to the real or saved
1141 * gid, then the effective gid will be set to the requested
1142 * value, but the real and saved gid will not change.
1144 * If the credential is changed as a result of this call, then we
1145 * flag the process as having set privilege since the last exec.
1147 * As an implementation detail, the effective gid is stored as
1148 * the first element of the supplementary group list, and
1149 * therefore the effective group list may be reordered to keep
1150 * the supplementary group list unchanged.
1153 setegid(proc_t p
, struct setegid_args
*uap
, __unused register_t
*retval
)
1157 kauth_cred_t my_cred
, my_new_cred
;
1159 DEBUG_CRED_ENTER("setegid %d\n", uap
->egid
);
1162 AUDIT_ARG(gid
, 0, egid
, 0, 0);
1164 my_cred
= kauth_cred_proc_ref(p
);
1166 if (egid
!= my_cred
->cr_rgid
&&
1167 egid
!= my_cred
->cr_svgid
&&
1168 (error
= suser(my_cred
, &p
->p_acflag
))) {
1169 kauth_cred_unref(&my_cred
);
1173 /* get current credential and take a reference while we muck with it */
1176 * Set the credential with new info. If there is no change,
1177 * we get back the same credential we passed in; if there is
1178 * a change, we drop the reference on the credential we
1179 * passed in. The subsequent compare is safe, because it is
1180 * a pointer compare rather than a contents compare.
1182 my_new_cred
= kauth_cred_setresgid(my_cred
, KAUTH_GID_NONE
, egid
, KAUTH_GID_NONE
);
1183 if (my_cred
!= my_new_cred
) {
1185 DEBUG_CRED_CHANGE("setegid(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
);
1189 * We need to protect for a race where another thread
1190 * also changed the credential after we took our
1191 * reference. If p_ucred has changed then we
1192 * should restart this again with the new cred.
1194 if (p
->p_ucred
!= my_cred
) {
1196 kauth_cred_unref(&my_new_cred
);
1198 my_cred
= kauth_cred_proc_ref(p
);
1201 p
->p_ucred
= my_new_cred
;
1202 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
1208 /* Drop old proc reference or our extra reference */
1209 kauth_cred_unref(&my_cred
);
1211 set_security_token(p
);
1218 * Description: Set real and effective group ID system call
1220 * Parameters: uap->rgid real gid to set
1221 * uap->egid effective gid to set
1223 * Returns: 0 Success
1224 * suser:EPERM Permission denied
1226 * Notes: A value of -1 is a special case indicating that the gid for
1227 * which that value is specified not be changed. If both values
1228 * are specified as -1, no action is taken.
1230 * If called by a privileged process, the real and effective gid
1231 * will be set to the new value(s) specified.
1233 * If called from an unprivileged process, the real gid may be
1234 * set to the current value of the real gid, or to the current
1235 * value of the saved gid. The effective gid may be set to the
1236 * current value of any of the effective, real, or saved gid.
1238 * If the new real and effective gid will not be equal, or the
1239 * new real or effective gid is not the same as the saved gid,
1240 * then the saved gid will be updated to reflect the new
1241 * effective gid (potentially unrecoverably dropping saved
1244 * If the credential is changed as a result of this call, then we
1245 * flag the process as having set privilege since the last exec.
1247 * As an implementation detail, the effective gid is stored as
1248 * the first element of the supplementary group list, and
1249 * therefore the effective group list may be reordered to keep
1250 * the supplementary group list unchanged.
1253 setregid(proc_t p
, struct setregid_args
*uap
, __unused register_t
*retval
)
1257 kauth_cred_t my_cred
, my_new_cred
;
1259 DEBUG_CRED_ENTER("setregid %d %d\n", uap
->rgid
, uap
->egid
);
1264 if (rgid
== (uid_t
)-1)
1265 rgid
= KAUTH_GID_NONE
;
1266 if (egid
== (uid_t
)-1)
1267 egid
= KAUTH_GID_NONE
;
1268 AUDIT_ARG(gid
, egid
, rgid
, 0, 0);
1270 my_cred
= kauth_cred_proc_ref(p
);
1272 if (((rgid
!= KAUTH_UID_NONE
&& /* allow no change of rgid */
1273 rgid
!= my_cred
->cr_rgid
&& /* allow rgid = rgid */
1274 rgid
!= my_cred
->cr_gid
&& /* allow rgid = egid */
1275 rgid
!= my_cred
->cr_svgid
) || /* allow rgid = svgid */
1276 (egid
!= KAUTH_UID_NONE
&& /* allow no change of egid */
1277 egid
!= my_cred
->cr_groups
[0] && /* allow no change of egid */
1278 egid
!= my_cred
->cr_gid
&& /* allow egid = egid */
1279 egid
!= my_cred
->cr_rgid
&& /* allow egid = rgid */
1280 egid
!= my_cred
->cr_svgid
)) && /* allow egid = svgid */
1281 (error
= suser(my_cred
, &p
->p_acflag
))) { /* allow root user any */
1282 kauth_cred_unref(&my_cred
);
1286 /* get current credential and take a reference while we muck with it */
1288 uid_t new_egid
= my_cred
->cr_gid
;
1289 uid_t new_rgid
= my_cred
->cr_rgid
;
1290 uid_t svgid
= KAUTH_UID_NONE
;
1294 * Set the credential with new info. If there is no change,
1295 * we get back the same credential we passed in; if there is
1296 * a change, we drop the reference on the credential we
1297 * passed in. The subsequent compare is safe, because it is
1298 * a pointer compare rather than a contents compare.
1300 if (egid
== KAUTH_UID_NONE
&& my_cred
->cr_groups
[0] != egid
) {
1301 /* changing the effective GID */
1303 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
1305 if (rgid
!= KAUTH_UID_NONE
&& my_cred
->cr_rgid
!= rgid
) {
1306 /* changing the real GID */
1308 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
1311 * If the newly requested real gid or effective gid does
1312 * not match the saved gid, then set the saved gid to the
1313 * new effective gid. We are protected from escalation
1314 * by the prechecking.
1316 if (my_cred
->cr_svgid
!= uap
->rgid
&&
1317 my_cred
->cr_svgid
!= uap
->egid
) {
1319 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
1322 my_new_cred
= kauth_cred_setresgid(my_cred
, rgid
, egid
, svgid
);
1323 if (my_cred
!= my_new_cred
) {
1325 DEBUG_CRED_CHANGE("setregid(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
);
1328 /* need to protect for a race where another thread
1329 * also changed the credential after we took our
1330 * reference. If p_ucred has changed then we
1331 * should restart this again with the new cred.
1333 if (p
->p_ucred
!= my_cred
) {
1335 kauth_cred_unref(&my_new_cred
);
1337 my_cred
= kauth_cred_proc_ref(p
);
1340 p
->p_ucred
= my_new_cred
;
1341 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
); /* XXX redundant? */
1346 /* Drop old proc reference or our extra reference */
1347 kauth_cred_unref(&my_cred
);
1349 set_security_token(p
);
1355 * Set the per-thread override identity. The first parameter can be the
1356 * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it
1357 * can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
1358 * means "revert to the per process credential"; otherwise, if permitted,
1359 * it changes the effective, real, and saved UIDs and GIDs for the current
1360 * thread to the requested UID and single GID, and clears all other GIDs.
1363 settid(proc_t p
, struct settid_args
*uap
, __unused register_t
*retval
)
1366 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1372 AUDIT_ARG(uid
, uid
, gid
, gid
, 0);
1374 if (proc_suser(p
) != 0)
1377 if (uid
== KAUTH_UID_NONE
) {
1379 /* must already be assuming another identity in order to revert back */
1380 if ((uthread
->uu_flag
& UT_SETUID
) == 0)
1383 /* revert to delayed binding of process credential */
1384 uc
= kauth_cred_proc_ref(p
);
1385 kauth_cred_unref(&uthread
->uu_ucred
);
1386 uthread
->uu_ucred
= uc
;
1387 uthread
->uu_flag
&= ~UT_SETUID
;
1389 kauth_cred_t my_cred
, my_new_cred
;
1391 /* cannot already be assuming another identity */
1392 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1397 * Get a new credential instance from the old if this one
1398 * changes; otherwise kauth_cred_setuidgid() returns the
1399 * same credential. We take an extra reference on the
1400 * current credential while we muck with it, so we can do
1401 * the post-compare for changes by pointer.
1403 kauth_cred_ref(uthread
->uu_ucred
);
1404 my_cred
= uthread
->uu_ucred
;
1405 my_new_cred
= kauth_cred_setuidgid(my_cred
, uid
, gid
);
1406 if (my_cred
!= my_new_cred
)
1407 uthread
->uu_ucred
= my_new_cred
;
1408 uthread
->uu_flag
|= UT_SETUID
;
1410 /* Drop old uthread reference or our extra reference */
1411 kauth_cred_unref(&my_cred
);
1414 * XXX should potentially set per thread security token (there is
1416 * XXX it is unclear whether P_SUGID should be st at this point;
1417 * XXX in theory, it is being deprecated.
1424 * Set the per-thread override identity. Use this system call for a thread to
1425 * assume the identity of another process or to revert back to normal identity
1426 * of the current process.
1428 * When the "assume" argument is non zero the current thread will assume the
1429 * identity of the process represented by the pid argument.
1431 * When the assume argument is zero we revert back to our normal identity.
1434 settid_with_pid(proc_t p
, struct settid_with_pid_args
*uap
, __unused register_t
*retval
)
1437 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1438 kauth_cred_t my_cred
, my_target_cred
, my_new_cred
;
1440 AUDIT_ARG(pid
, uap
->pid
);
1441 AUDIT_ARG(value
, uap
->assume
);
1443 if (proc_suser(p
) != 0) {
1448 * XXX should potentially set per thread security token (there is
1450 * XXX it is unclear whether P_SUGID should be st at this point;
1451 * XXX in theory, it is being deprecated.
1455 * assume argument tells us to assume the identity of the process with the
1456 * id passed in the pid argument.
1458 if (uap
->assume
!= 0) {
1459 /* can't do this if we have already assumed an identity */
1460 if ((uthread
->uu_flag
& UT_SETUID
) != 0)
1463 target_proc
= proc_find(uap
->pid
);
1464 /* can't assume the identity of the kernel process */
1465 if (target_proc
== NULL
|| target_proc
== kernproc
) {
1466 if (target_proc
!= NULL
)
1467 proc_rele(target_proc
);
1472 * Take a reference on the credential used in our target
1473 * process then use it as the identity for our current
1474 * thread. We take an extra reference on the current
1475 * credential while we muck with it, so we can do the
1476 * post-compare for changes by pointer.
1478 * The post-compare is needed for the case that our process
1479 * credential has been changed to be identical to our thread
1480 * credential following our assumption of a per-thread one,
1481 * since the credential cache will maintain a unique instance.
1483 kauth_cred_ref(uthread
->uu_ucred
);
1484 my_cred
= uthread
->uu_ucred
;
1485 my_target_cred
= kauth_cred_proc_ref(target_proc
);
1486 my_new_cred
= kauth_cred_setuidgid(my_cred
, my_target_cred
->cr_uid
, my_target_cred
->cr_gid
);
1487 if (my_cred
!= my_new_cred
)
1488 uthread
->uu_ucred
= my_new_cred
;
1490 uthread
->uu_flag
|= UT_SETUID
;
1492 /* Drop old uthread reference or our extra reference */
1493 proc_rele(target_proc
);
1494 kauth_cred_unref(&my_cred
);
1495 kauth_cred_unref(&my_target_cred
);
1501 * Otherwise, we are reverting back to normal mode of operation where
1502 * delayed binding of the process credential sets the credential in
1503 * the thread (uu_ucred)
1505 if ((uthread
->uu_flag
& UT_SETUID
) == 0)
1508 /* revert to delayed binding of process credential */
1509 my_new_cred
= kauth_cred_proc_ref(p
);
1510 kauth_cred_unref(&uthread
->uu_ucred
);
1511 uthread
->uu_ucred
= my_new_cred
;
1512 uthread
->uu_flag
&= ~UT_SETUID
;
1521 * Description: Internal implementation for both the setgroups and initgroups
1524 * Parameters: gidsetsize Number of groups in set
1525 * gidset Pointer to group list
1526 * gmuid Base gid (initgroups only!)
1528 * Returns: 0 Success
1529 * suser:EPERM Permision denied
1530 * EINVAL Invalid gidsetsize value
1531 * copyin:EFAULT Bad gidset or gidsetsize is
1534 * Notes: When called from a thread running under an assumed per-thread
1535 * identity, this function will operate against the per-thread
1536 * credential, rather than against the process credential. In
1537 * this specific case, the process credential is verified to
1538 * still be privileged at the time of the call, rather than the
1539 * per-thread credential for this operation to be permitted.
1541 * This effectively means that setgroups/initigroups calls in
1542 * a thread running a per-thread credential should occur *after*
1543 * the settid call that created it, not before (unlike setuid,
1544 * which must be called after, since it will result in privilege
1547 * When called normally (i.e. no per-thread assumed identity),
1548 * the per process credential is updated per POSIX.
1550 * If the credential is changed as a result of this call, then we
1551 * flag the process as having set privilege since the last exec.
1554 setgroups1(proc_t p
, u_int gidsetsize
, user_addr_t gidset
, uid_t gmuid
, __unused register_t
*retval
)
1557 gid_t newgroups
[NGROUPS
] = { 0 };
1559 kauth_cred_t my_cred
, my_new_cred
;
1560 struct uthread
*uthread
= get_bsdthread_info(current_thread());
1562 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
);
1571 error
= copyin(gidset
,
1572 (caddr_t
)newgroups
, ngrp
* sizeof(gid_t
));
1578 my_cred
= kauth_cred_proc_ref(p
);
1579 if ((error
= suser(my_cred
, &p
->p_acflag
))) {
1580 kauth_cred_unref(&my_cred
);
1584 if ((uthread
->uu_flag
& UT_SETUID
) != 0) {
1586 int my_cred_flags
= uthread
->uu_ucred
->cr_flags
;
1587 #endif /* DEBUG_CRED */
1588 kauth_cred_unref(&my_cred
);
1591 * If this thread is under an assumed identity, set the
1592 * supplementary grouplist on the thread credential instead
1593 * of the process one. If we were the only reference holder,
1594 * the credential is updated in place, otherwise, our reference
1595 * is dropped and we get back a different cred with a reference
1596 * already held on it. Because this is per-thread, we don't
1597 * need the referencing/locking/retry required for per-process.
1599 my_cred
= uthread
->uu_ucred
;
1600 uthread
->uu_ucred
= kauth_cred_setgroups(my_cred
, &newgroups
[0], ngrp
, gmuid
);
1602 if (my_cred
!= uthread
->uu_ucred
) {
1603 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
);
1605 #endif /* DEBUG_CRED */
1609 * get current credential and take a reference while we muck
1614 * Set the credential with new info. If there is no
1615 * change, we get back the same credential we passed
1616 * in; if there is a change, we drop the reference on
1617 * the credential we passed in. The subsequent
1618 * compare is safe, because it is a pointer compare
1619 * rather than a contents compare.
1621 my_new_cred
= kauth_cred_setgroups(my_cred
, &newgroups
[0], ngrp
, gmuid
);
1622 if (my_cred
!= my_new_cred
) {
1624 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
);
1628 * We need to protect for a race where another
1629 * thread also changed the credential after we
1630 * took our reference. If p_ucred has
1631 * changed then we should restart this again
1632 * with the new cred.
1634 if (p
->p_ucred
!= my_cred
) {
1636 kauth_cred_unref(&my_new_cred
);
1637 my_cred
= kauth_cred_proc_ref(p
);
1641 p
->p_ucred
= my_new_cred
;
1642 OSBitOrAtomic(P_SUGID
, (UInt32
*)&p
->p_flag
);
1647 /* Drop old proc reference or our extra reference */
1648 AUDIT_ARG(groupset
, my_cred
->cr_groups
, ngrp
);
1649 kauth_cred_unref(&my_cred
);
1652 set_security_token(p
);
1662 * Description: Initialize the default supplementary groups list and set the
1663 * gmuid for use by the external group resolver (if any)
1665 * Parameters: uap->gidsetsize Number of groups in set
1666 * uap->gidset Pointer to group list
1667 * uap->gmuid Base gid
1669 * Returns: 0 Success
1670 * setgroups1:EPERM Permision denied
1671 * setgroups1:EINVAL Invalid gidsetsize value
1672 * setgroups1:EFAULT Bad gidset or gidsetsize is
1674 * Notes: This function opts *IN* to memberd participation
1676 * The normal purpose of this function is for a privileged
1677 * process to indicate supplementary groups and identity for
1678 * participation in extended group membership resolution prior
1679 * to dropping privilege by assuming a specific user identity.
1681 * It is the first half of the primary mechanism whereby user
1682 * identity is established to the system by programs such as
1683 * /usr/bin/login. The second half is the drop of uid privilege
1684 * for a specific uid corresponding to the user.
1686 * See also: setgroups1()
1689 initgroups(proc_t p
, struct initgroups_args
*uap
, __unused register_t
*retval
)
1691 DEBUG_CRED_ENTER("initgroups\n");
1693 return(setgroups1(p
, uap
->gidsetsize
, uap
->gidset
, uap
->gmuid
, retval
));
1700 * Description: Initialize the default supplementary groups list
1702 * Parameters: gidsetsize Number of groups in set
1703 * gidset Pointer to group list
1705 * Returns: 0 Success
1706 * setgroups1:EPERM Permision denied
1707 * setgroups1:EINVAL Invalid gidsetsize value
1708 * setgroups1:EFAULT Bad gidset or gidsetsize is
1710 * Notes: This functions opts *OUT* of memberd participation.
1712 * This function exists for compatibility with POSIX. Most user
1713 * programs should use initgroups() instead to ensure correct
1714 * participation in group membership resolution when utilizing
1715 * a directory service for authentication.
1717 * It is identical to an initgroups() call with a gmuid argument
1718 * of KAUTH_UID_NONE.
1720 * See also: setgroups1()
1723 setgroups(proc_t p
, struct setgroups_args
*uap
, __unused register_t
*retval
)
1725 DEBUG_CRED_ENTER("setgroups\n");
1727 return(setgroups1(p
, uap
->gidsetsize
, uap
->gidset
, KAUTH_UID_NONE
, retval
));
1732 * Set the per-thread/per-process supplementary groups list.
1734 #warning XXX implement setsgroups
1736 setsgroups(__unused proc_t p
, __unused
struct setsgroups_args
*uap
, __unused register_t
*retval
)
1742 * Set the per-thread/per-process whiteout groups list.
1744 #warning XXX implement setwgroups
1746 setwgroups(__unused proc_t p
, __unused
struct setwgroups_args
*uap
, __unused register_t
*retval
)
1753 * Check if gid is a member of the group set.
1755 * XXX This interface is going away; use kauth_cred_ismember_gid() directly
1759 groupmember(gid_t gid
, kauth_cred_t cred
)
1763 if (kauth_cred_ismember_gid(cred
, gid
, &is_member
) == 0 && is_member
)
1770 * Test whether the specified credentials imply "super-user"
1771 * privilege; if so, and we have accounting info, set the flag
1772 * indicating use of super-powers.
1773 * Returns 0 or error.
1775 * XXX This interface is going away; use kauth_cred_issuser() directly
1778 * Note: This interface exists to implement the "has used privilege"
1779 * bit (ASU) in the p_acflags field of the process, which is
1780 * only externalized via private sysctl and in process accounting
1781 * records. The flag is technically not required in either case.
1784 suser(kauth_cred_t cred
, u_short
*acflag
)
1787 if (!IS_VALID_CRED(cred
))
1790 if (kauth_cred_getuid(cred
) == 0) {
1800 * XXX This interface is going away; use kauth_cred_issuser() directly
1806 proc_t p
= current_proc();
1811 return (proc_suser(p
) == 0);
1816 * XXX This interface is going away; use kauth_cred_issuser() directly
1822 proc_t p
= current_proc();
1823 kauth_cred_t my_cred
;
1829 my_cred
= kauth_cred_proc_ref(p
);
1831 err
= (suser(my_cred
, &p
->p_acflag
) == 0 ||
1832 my_cred
->cr_ruid
== 0 || my_cred
->cr_svuid
== 0);
1833 kauth_cred_unref(&my_cred
);
1841 * Description: Get login name, if available.
1843 * Parameters: uap->namebuf User buffer for return
1844 * uap->namelen User buffer length
1846 * Returns: 0 Success
1849 * Notes: Intended to obtain a string containing the user name of the
1850 * user associated with the controlling terminal for the calling
1853 * Not very useful on modern systems, due to inherent length
1854 * limitations for the static array in the session structure
1855 * which is used to store the login name.
1857 * Permitted to return NULL
1859 * XXX: Belongs in kern_proc.c
1862 getlogin(proc_t p
, struct getlogin_args
*uap
, __unused register_t
*retval
)
1864 char buffer
[MAXLOGNAME
+1];
1865 struct session
* sessp
;
1867 bzero(buffer
, MAXLOGNAME
+1);
1869 sessp
= proc_session(p
);
1871 if (uap
->namelen
> MAXLOGNAME
)
1872 uap
->namelen
= MAXLOGNAME
;
1874 if(sessp
!= SESSION_NULL
) {
1875 session_lock(sessp
);
1876 bcopy( sessp
->s_login
, buffer
, uap
->namelen
);
1877 session_unlock(sessp
);
1879 session_rele(sessp
);
1881 return (copyout((caddr_t
)buffer
, uap
->namebuf
, uap
->namelen
));
1888 * Description: Set login name.
1890 * Parameters: uap->namebuf User buffer containing name
1892 * Returns: 0 Success
1893 * suser:EPERM Permission denied
1894 * copyinstr:EFAULT User buffer invalid
1895 * copyinstr:EINVAL Supplied name was too long
1897 * Notes: This is a utility system call to support getlogin().
1899 * XXX: Belongs in kern_proc.c
1902 setlogin(proc_t p
, struct setlogin_args
*uap
, __unused register_t
*retval
)
1906 char buffer
[MAXLOGNAME
+1];
1907 struct session
* sessp
;
1909 if ((error
= proc_suser(p
)))
1912 bzero(&buffer
[0], MAXLOGNAME
+1);
1915 error
= copyinstr(uap
->namebuf
,
1916 (caddr_t
) &buffer
[0],
1917 MAXLOGNAME
- 1, (size_t *)&dummy
);
1919 sessp
= proc_session(p
);
1921 if (sessp
!= SESSION_NULL
) {
1922 session_lock(sessp
);
1923 bcopy(buffer
, sessp
->s_login
, MAXLOGNAME
);
1924 session_unlock(sessp
);
1925 session_rele(sessp
);
1930 AUDIT_ARG(text
, buffer
);
1931 } else if (error
== ENAMETOOLONG
)
1937 /* Set the secrity token of the task with current euid and eguid */
1939 * XXX This needs to change to give the task a reference and/or an opaque
1943 set_security_token(proc_t p
)
1945 security_token_t sec_token
;
1946 audit_token_t audit_token
;
1947 kauth_cred_t my_cred
;
1948 host_priv_t host_priv
;
1951 * Don't allow a vfork child to override the parent's token settings
1952 * (since they share a task). Instead, the child will just have to
1953 * suffer along using the parent's token until the exec(). It's all
1954 * undefined behavior anyway, right?
1956 if (p
->task
== current_task()) {
1958 uthread
= (uthread_t
)get_bsdthread_info(current_thread());
1959 if (uthread
->uu_flag
& UT_VFORK
)
1963 my_cred
= kauth_cred_proc_ref(p
);
1964 /* XXX mach_init doesn't have a p_ucred when it calls this function */
1965 if (IS_VALID_CRED(my_cred
)) {
1966 sec_token
.val
[0] = kauth_cred_getuid(my_cred
);
1967 sec_token
.val
[1] = my_cred
->cr_gid
;
1969 sec_token
.val
[0] = 0;
1970 sec_token
.val
[1] = 0;
1974 * The current layout of the Mach audit token explicitly
1975 * adds these fields. But nobody should rely on such
1976 * a literal representation. Instead, the BSM library
1977 * provides a function to convert an audit token into
1978 * a BSM subject. Use of that mechanism will isolate
1979 * the user of the trailer from future representation
1982 audit_token
.val
[0] = my_cred
->cr_au
.ai_auid
;
1983 audit_token
.val
[1] = my_cred
->cr_uid
;
1984 audit_token
.val
[2] = my_cred
->cr_gid
;
1985 audit_token
.val
[3] = my_cred
->cr_ruid
;
1986 audit_token
.val
[4] = my_cred
->cr_rgid
;
1987 audit_token
.val
[5] = p
->p_pid
;
1988 audit_token
.val
[6] = my_cred
->cr_au
.ai_asid
;
1989 audit_token
.val
[7] = p
->p_idversion
;
1991 #if CONFIG_MACF_MACH
1992 mac_task_label_update_cred(my_cred
, p
->task
);
1995 host_priv
= (sec_token
.val
[0]) ? HOST_PRIV_NULL
: host_priv_self();
1997 if (host_priv
!= HOST_PRIV_NULL
&& mac_system_check_host_priv(my_cred
))
1998 host_priv
= HOST_PRIV_NULL
;
2000 kauth_cred_unref(&my_cred
);
2002 return (host_security_set_task_token(host_security_self(),
2006 host_priv
) != KERN_SUCCESS
);
2011 * Fill in a struct xucred based on a kauth_cred_t.
2015 cru2x(kauth_cred_t cr
, struct xucred
*xcr
)
2018 bzero(xcr
, sizeof(*xcr
));
2019 xcr
->cr_version
= XUCRED_VERSION
;
2020 xcr
->cr_uid
= kauth_cred_getuid(cr
);
2021 xcr
->cr_ngroups
= cr
->cr_ngroups
;
2022 bcopy(cr
->cr_groups
, xcr
->cr_groups
, sizeof(xcr
->cr_groups
));
2028 * Set Login Context ID
2031 * MPSAFE - assignment of (visible) process to context protected by ALLLCTX_LOCK,
2032 * LCTX by its own locks.
2035 setlcid(proc_t p0
, struct setlcid_args
*uap
, __unused register_t
*retval
)
2042 AUDIT_ARG(pid
, uap
->pid
);
2043 AUDIT_ARG(value
, uap
->lcid
);
2044 if (uap
->pid
== LCID_PROC_SELF
) { /* Create/Join/Leave */
2046 } else { /* Adopt/Orphan */
2047 p
= proc_find(uap
->pid
);
2054 error
= mac_proc_check_setlcid(p0
, p
, uap
->pid
, uap
->lcid
);
2059 switch (uap
->lcid
) {
2063 /* Only root may Leave/Orphan. */
2069 /* Process not in login context. */
2070 if (p
->p_lctx
== NULL
) {
2082 /* Create only valid for self! */
2083 if (uap
->pid
!= LCID_PROC_SELF
) {
2088 /* Already in a login context. */
2089 if (p
->p_lctx
!= NULL
) {
2107 /* Only root may Join/Adopt. */
2113 l
= lcfind(uap
->lcid
);
2124 enterlctx(p
, l
, (uap
->lcid
== LCID_CREATE
) ? 1 : 0);
2134 * Get Login Context ID
2137 * MPSAFE - membership of (visible) process in a login context
2138 * protected by the all-context lock.
2141 getlcid(proc_t p0
, struct getlcid_args
*uap
, register_t
*retval
)
2147 AUDIT_ARG(pid
, uap
->pid
);
2148 if (uap
->pid
== LCID_PROC_SELF
) {
2151 p
= proc_find(uap
->pid
);
2158 error
= mac_proc_check_getlcid(p0
, p
, uap
->pid
);
2163 if (p
->p_lctx
== NULL
) {
2168 *retval
= p
->p_lctx
->lc_id
;
2178 setlcid(proc_t p0
, struct setlcid_args
*uap
, register_t
*retval
)
2185 getlcid(proc_t p0
, struct getlcid_args
*uap
, register_t
*retval
)