* Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
- *
+ *
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*
*
* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
- *
+ *
*
* Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
* The Regents of the University of California. All rights reserved.
* SUCH DAMAGE.
*
* @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
- *
+ *
*
* NOTICE: This file was modified by McAfee Research in 2004 to introduce
* support for mandatory and extensible security protections. This notice
#include <sys/timeb.h>
#include <sys/times.h>
#include <sys/malloc.h>
+#include <sys/persona.h>
#include <security/audit/audit.h>
-#if CONFIG_LCTX
-#include <sys/lctx.h>
-#endif
-
#if CONFIG_MACF
#include <security/mac_framework.h>
#endif
#include <mach/host_security.h>
#include <kern/host.h>
-#include <kern/task.h> /* for current_task() */
+#include <kern/task.h> /* for current_task() */
#include <kern/assert.h>
* can be used if needed when debugging is active.
*/
#if DEBUG_CRED
-#define DEBUG_CRED_ENTER printf
-#define DEBUG_CRED_CHANGE printf
+#define DEBUG_CRED_ENTER printf
+#define DEBUG_CRED_CHANGE printf
extern void kauth_cred_print(kauth_cred_t cred);
-#else /* !DEBUG_CRED */
-#define DEBUG_CRED_ENTER(fmt, ...) do {} while (0)
-#define DEBUG_CRED_CHANGE(fmt, ...) do {} while (0)
-#endif /* !DEBUG_CRED */
+#else /* !DEBUG_CRED */
+#define DEBUG_CRED_ENTER(fmt, ...) do {} while (0)
+#define DEBUG_CRED_CHANGE(fmt, ...) do {} while (0)
+#endif /* !DEBUG_CRED */
#if DEVELOPMENT || DEBUG
extern void task_importance_update_owner_info(task_t);
AUDIT_ARG(value32, uap->flag);
*retval = p->p_debugger;
p->p_debugger = (uap->flag != 0);
- return(0);
+ return 0;
}
int
getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval)
{
-
*retval = p->p_pid;
- return (0);
+ return 0;
}
int
getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval)
{
-
*retval = p->p_ppid;
- return (0);
+ return 0;
}
int
getpgrp(proc_t p, __unused struct getpgrp_args *uap, int32_t *retval)
{
-
*retval = p->p_pgrpid;
- return (0);
+ return 0;
}
int refheld = 0;
pt = p;
- if (uap->pid == 0)
+ if (uap->pid == 0) {
goto found;
+ }
- if ((pt = proc_find(uap->pid)) == 0)
- return (ESRCH);
+ if ((pt = proc_find(uap->pid)) == 0) {
+ return ESRCH;
+ }
refheld = 1;
found:
*retval = pt->p_pgrpid;
- if (refheld != 0)
+ if (refheld != 0) {
proc_rele(pt);
- return (0);
+ }
+ return 0;
}
struct session * sessp;
pt = p;
- if (uap->pid == 0)
+ if (uap->pid == 0) {
goto found;
+ }
- if ((pt = proc_find(uap->pid)) == 0)
- return (ESRCH);
+ if ((pt = proc_find(uap->pid)) == 0) {
+ return ESRCH;
+ }
refheld = 1;
found:
sessp = proc_session(pt);
*retval = sessp->s_sid;
session_rele(sessp);
- if (refheld != 0)
+ if (refheld != 0) {
proc_rele(pt);
- return (0);
+ }
+ return 0;
}
int
getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval)
{
-
- *retval = kauth_getruid();
- return (0);
+ *retval = kauth_getruid();
+ return 0;
}
int
geteuid(__unused proc_t p, __unused struct geteuid_args *uap, int32_t *retval)
{
-
- *retval = kauth_getuid();
- return (0);
+ *retval = kauth_getuid();
+ return 0;
}
gettid(__unused proc_t p, struct gettid_args *uap, int32_t *retval)
{
struct uthread *uthread = get_bsdthread_info(current_thread());
- int error;
+ int error;
/*
* If this thread is not running with an override identity, we can't
* return one to the caller, so return an error instead.
*/
- if (!(uthread->uu_flag & UT_SETUID))
- return (ESRCH);
+ if (!(uthread->uu_flag & UT_SETUID)) {
+ return ESRCH;
+ }
- if ((error = suword(uap->uidp, kauth_cred_getruid(uthread->uu_ucred))))
- return (error);
- if ((error = suword(uap->gidp, kauth_cred_getrgid(uthread->uu_ucred))))
- return (error);
+ if ((error = suword(uap->uidp, kauth_cred_getruid(uthread->uu_ucred)))) {
+ return error;
+ }
+ if ((error = suword(uap->gidp, kauth_cred_getrgid(uthread->uu_ucred)))) {
+ return error;
+ }
*retval = 0;
- return (0);
+ return 0;
}
int
getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval)
{
-
*retval = kauth_getrgid();
- return (0);
+ return 0;
}
int
getegid(__unused proc_t p, __unused struct getegid_args *uap, int32_t *retval)
{
-
*retval = kauth_getgid();
- return (0);
+ return 0;
}
if ((ngrp = uap->gidsetsize) == 0) {
*retval = pcred->cr_ngroups;
kauth_cred_unref(&cred);
- return (0);
+ return 0;
}
if (ngrp < pcred->cr_ngroups) {
kauth_cred_unref(&cred);
- return (EINVAL);
+ return EINVAL;
}
ngrp = pcred->cr_ngroups;
if ((error = copyout((caddr_t)pcred->cr_groups,
- uap->gidset,
- ngrp * sizeof(gid_t)))) {
+ uap->gidset,
+ ngrp * sizeof(gid_t)))) {
kauth_cred_unref(&cred);
- return (error);
+ return error;
}
kauth_cred_unref(&cred);
*retval = ngrp;
- return (0);
+ return 0;
}
int
getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int32_t *retval)
{
- return(ENOTSUP);
+ return ENOTSUP;
}
/*
* Return the per-thread/per-process whiteout groups list.
- *
+ *
* XXX implement getwgroups
*
*/
int
getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int32_t *retval)
{
- return(ENOTSUP);
+ return ENOTSUP;
}
+/*
+ * setsid_internal
+ *
+ * Description: Core implementation of setsid().
+ */
+int
+setsid_internal(proc_t p)
+{
+ struct pgrp * pg = PGRP_NULL;
+
+ if (p->p_pgrpid == p->p_pid || (pg = pgfind(p->p_pid)) || p->p_lflag & P_LINVFORK) {
+ if (pg != PGRP_NULL) {
+ pg_rele(pg);
+ }
+ return EPERM;
+ } else {
+ /* enter pgrp works with its own pgrp refcount */
+ (void)enterpgrp(p, p->p_pid, 1);
+ return 0;
+ }
+}
/*
* setsid
int
setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval)
{
- struct pgrp * pg = PGRP_NULL;
-
- if (p->p_pgrpid == p->p_pid || (pg = pgfind(p->p_pid)) || p->p_lflag & P_LINVFORK) {
- if (pg != PGRP_NULL)
- pg_rele(pg);
- return (EPERM);
- } else {
- /* enter pgrp works with its own pgrp refcount */
- (void)enterpgrp(p, p->p_pid, 1);
+ int rc = setsid_internal(p);
+ if (rc == 0) {
*retval = p->p_pid;
- return (0);
}
+ return rc;
}
* is used as the target process group ID.
*
* Legacy: This system call entry point is also used to implement the
- * legacy library routine setpgrp(), which under POSIX
+ * legacy library routine setpgrp(), which under POSIX
*
* XXX: Belongs in kern_proc.c
*/
int
-setpgid(proc_t curp, register struct setpgid_args *uap, __unused int32_t *retval)
+setpgid(proc_t curp, struct setpgid_args *uap, __unused int32_t *retval)
{
- proc_t targp = PROC_NULL; /* target process */
- struct pgrp *pg = PGRP_NULL; /* target pgrp */
+ proc_t targp = PROC_NULL; /* target process */
+ struct pgrp *pg = PGRP_NULL; /* target pgrp */
int error = 0;
int refheld = 0;
int samesess = 0;
if (uap->pid != 0 && uap->pid != curp->p_pid) {
if ((targp = proc_find(uap->pid)) == 0 || !inferior(targp)) {
- if (targp != PROC_NULL)
+ if (targp != PROC_NULL) {
refheld = 1;
+ }
error = ESRCH;
goto out;
}
error = EINVAL;
goto out;
}
- if (uap->pgid == 0)
+ if (uap->pgid == 0) {
uap->pgid = targp->p_pid;
- else if (uap->pgid != targp->p_pid) {
- if ((pg = pgfind(uap->pgid)) == 0){
+ } else if (uap->pgid != targp->p_pid) {
+ if ((pg = pgfind(uap->pgid)) == 0) {
error = EPERM;
goto out;
}
- samesess = (pg->pg_session != curp_sessp);
+ samesess = (pg->pg_session != curp_sessp);
pg_rele(pg);
if (samesess != 0) {
error = EPERM;
}
error = enterpgrp(targp, uap->pgid, 0);
out:
- if (targp_sessp != SESSION_NULL)
+ if (targp_sessp != SESSION_NULL) {
session_rele(targp_sessp);
- if (curp_sessp != SESSION_NULL)
+ }
+ if (curp_sessp != SESSION_NULL) {
session_rele(curp_sessp);
- if (refheld != 0)
+ }
+ if (refheld != 0) {
proc_rele(targp);
- return(error);
+ }
+ return error;
}
* real, effective, or saved user or group IDs since beginning
* execution.
*/
+int
+proc_issetugid(proc_t p)
+{
+ return (p->p_flag & P_SUGID) ? 1 : 0;
+}
+
int
issetugid(proc_t p, __unused struct issetugid_args *uap, int32_t *retval)
{
* that libc *might* have put in their data segment.
*/
- *retval = (p->p_flag & P_SUGID) ? 1 : 0;
- return (0);
+ *retval = proc_issetugid(p);
+ return 0;
}
kauth_cred_t my_cred, my_new_cred;
posix_cred_t my_pcred;
-
uid = uap->uid;
+ /* get current credential and take a reference while we muck with it */
my_cred = kauth_cred_proc_ref(p);
my_pcred = posix_cred_get(my_cred);
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);
AUDIT_ARG(uid, uid);
- if (uid != my_pcred->cr_ruid && /* allow setuid(getuid()) */
- uid != my_pcred->cr_svuid && /* allow setuid(saved uid) */
- (error = suser(my_cred, &p->p_acflag))) {
- kauth_cred_unref(&my_cred);
- return (error);
- }
- /*
- * Everything's okay, do it.
- */
+ for (;;) {
+ if (uid != my_pcred->cr_ruid && /* allow setuid(getuid()) */
+ uid != my_pcred->cr_svuid && /* allow setuid(saved uid) */
+ (error = suser(my_cred, &p->p_acflag))) {
+ kauth_cred_unref(&my_cred);
+ return error;
+ }
- /*
- * If we are priviledged, then set the saved and real UID too;
- * otherwise, just set the effective UID
- */
- if (suser(my_cred, &p->p_acflag) == 0) {
- svuid = uid;
- ruid = uid;
/*
- * Transfer proc count to new user.
- * chgproccnt uses list lock for protection
+ * If we are privileged, then set the saved and real UID too;
+ * otherwise, just set the effective UID
*/
- (void)chgproccnt(uid, 1);
- (void)chgproccnt(my_pcred->cr_ruid, -1);
- }
-
- /* get current credential and take a reference while we muck with it */
- for (;;) {
+ if (suser(my_cred, &p->p_acflag) == 0) {
+ svuid = uid;
+ ruid = uid;
+ } else {
+ svuid = KAUTH_UID_NONE;
+ ruid = KAUTH_UID_NONE;
+ }
/*
* Only set the gmuid if the current cred has not opt'ed out;
* this normally only happens when calling setgroups() instead
* to something other than the default list for the user, as
* in entering a group or leaving an exclusion group).
*/
- if (!(my_pcred->cr_flags & CRF_NOMEMBERD))
+ if (!(my_pcred->cr_flags & CRF_NOMEMBERD)) {
gmuid = uid;
+ }
- /*
+ /*
* Set the credential with new info. If there is no change,
* we get back the same credential we passed in; if there is
* a change, we drop the reference on the credential we
* passed in. The subsequent compare is safe, because it is
* a pointer compare rather than a contents compare.
- */
+ */
my_new_cred = kauth_cred_setresuid(my_cred, ruid, uid, svuid, gmuid);
if (my_cred != my_new_cred) {
-
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);
- proc_lock(p);
+ /*
+ * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
+ * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
+ * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
+ * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
+ * may be able to decrement the proc count of B before we can increment it. This results in a panic.
+ * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
+ */
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ (void)chgproccnt(ruid, 1);
+ }
+
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another thread
* also changed the credential after we took our
* reference. If p_ucred has changed then we should
* restart this again with the new cred.
+ *
+ * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
+ /*
+ * We didn't successfully switch to the new ruid, so decrement
+ * the procs/uid count that we incremented above.
+ */
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ (void)chgproccnt(ruid, -1);
+ }
kauth_cred_unref(&my_new_cred);
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
/* try again */
continue;
}
PROC_UPDATE_CREDS_ONPROC(p);
OSBitOrAtomic(P_SUGID, &p->p_flag);
- proc_unlock(p);
+ proc_ucred_unlock(p);
+ /*
+ * If we've updated the ruid, decrement the count of procs running
+ * under the previous ruid
+ */
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ (void)chgproccnt(my_pcred->cr_ruid, -1);
+ }
}
break;
}
/* Drop old proc reference or our extra reference */
kauth_cred_unref(&my_cred);
-
+
set_security_token(p);
- return (0);
+ return 0;
}
my_cred = kauth_cred_proc_ref(p);
my_pcred = posix_cred_get(my_cred);
- if (euid != my_pcred->cr_ruid && euid != my_pcred->cr_svuid &&
- (error = suser(my_cred, &p->p_acflag))) {
- kauth_cred_unref(&my_cred);
- return (error);
- }
-
- /*
- * Everything's okay, do it. Copy credentials so other references do
- * not see our changes. get current credential and take a reference
- * while we muck with it
- */
for (;;) {
- /*
+ if (euid != my_pcred->cr_ruid && euid != my_pcred->cr_svuid &&
+ (error = suser(my_cred, &p->p_acflag))) {
+ kauth_cred_unref(&my_cred);
+ return error;
+ }
+
+ /*
* Set the credential with new info. If there is no change,
* we get back the same credential we passed in; if there is
* a change, we drop the reference on the credential we
* passed in. The subsequent compare is safe, because it is
* a pointer compare rather than a contents compare.
- */
+ */
my_new_cred = kauth_cred_setresuid(my_cred, KAUTH_UID_NONE, euid, KAUTH_UID_NONE, my_pcred->cr_gmuid);
-
- if (my_cred != my_new_cred) {
+ if (my_cred != my_new_cred) {
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);
- proc_lock(p);
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another thread
* also changed the credential after we took our
* should restart this again with the new cred.
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
kauth_cred_unref(&my_new_cred);
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
/* try again */
continue;
}
/* update cred on proc */
PROC_UPDATE_CREDS_ONPROC(p);
OSBitOrAtomic(P_SUGID, &p->p_flag);
- proc_unlock(p);
+ proc_ucred_unlock(p);
}
break;
}
kauth_cred_unref(&my_cred);
set_security_token(p);
- return (0);
+ return 0;
}
ruid = uap->ruid;
euid = uap->euid;
- if (ruid == (uid_t)-1)
+ if (ruid == (uid_t)-1) {
ruid = KAUTH_UID_NONE;
- if (euid == (uid_t)-1)
+ }
+ if (euid == (uid_t)-1) {
euid = KAUTH_UID_NONE;
+ }
AUDIT_ARG(euid, euid);
AUDIT_ARG(ruid, ruid);
my_cred = kauth_cred_proc_ref(p);
my_pcred = posix_cred_get(my_cred);
- if (((ruid != KAUTH_UID_NONE && /* allow no change of ruid */
- ruid != my_pcred->cr_ruid && /* allow ruid = ruid */
- ruid != my_pcred->cr_uid && /* allow ruid = euid */
- ruid != my_pcred->cr_svuid) || /* allow ruid = svuid */
- (euid != KAUTH_UID_NONE && /* allow no change of euid */
- euid != my_pcred->cr_uid && /* allow euid = euid */
- euid != my_pcred->cr_ruid && /* allow euid = ruid */
- euid != my_pcred->cr_svuid)) && /* allow euid = svui */
- (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
- kauth_cred_unref(&my_cred);
- return (error);
- }
-
- /*
- * Everything's okay, do it. Copy credentials so other references do
- * not see our changes. get current credential and take a reference
- * while we muck with it
- */
for (;;) {
+ if (((ruid != KAUTH_UID_NONE && /* allow no change of ruid */
+ ruid != my_pcred->cr_ruid && /* allow ruid = ruid */
+ ruid != my_pcred->cr_uid && /* allow ruid = euid */
+ ruid != my_pcred->cr_svuid) || /* allow ruid = svuid */
+ (euid != KAUTH_UID_NONE && /* allow no change of euid */
+ euid != my_pcred->cr_uid && /* allow euid = euid */
+ euid != my_pcred->cr_ruid && /* allow euid = ruid */
+ euid != my_pcred->cr_svuid)) && /* allow euid = svuid */
+ (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
+ kauth_cred_unref(&my_cred);
+ return error;
+ }
+
uid_t new_euid;
- uid_t new_ruid;
uid_t svuid = KAUTH_UID_NONE;
new_euid = my_pcred->cr_uid;
- new_ruid = my_pcred->cr_ruid;
-
- /*
+ /*
* Set the credential with new info. If there is no change,
* we get back the same credential we passed in; if there is
* a change, we drop the reference on the credential we
* passed in. The subsequent compare is safe, because it is
* a pointer compare rather than a contents compare.
- */
- if (euid == KAUTH_UID_NONE && my_pcred->cr_uid != euid) {
+ */
+ if (euid != KAUTH_UID_NONE && my_pcred->cr_uid != euid) {
/* changing the effective UID */
new_euid = euid;
OSBitOrAtomic(P_SUGID, &p->p_flag);
}
- if (ruid != KAUTH_UID_NONE && my_pcred->cr_ruid != ruid) {
- /* changing the real UID; must do user accounting */
- /* chgproccnt uses list lock for protection */
- (void)chgproccnt(ruid, 1);
- (void)chgproccnt(my_pcred->cr_ruid, -1);
- new_ruid = ruid;
- OSBitOrAtomic(P_SUGID, &p->p_flag);
- }
/*
* If the newly requested real uid or effective uid does
* not match the saved uid, then set the saved uid to the
*/
if (my_pcred->cr_svuid != uap->ruid &&
my_pcred->cr_svuid != uap->euid) {
- svuid = new_euid;
+ svuid = new_euid;
OSBitOrAtomic(P_SUGID, &p->p_flag);
}
my_new_cred = kauth_cred_setresuid(my_cred, ruid, euid, svuid, my_pcred->cr_gmuid);
-
- if (my_cred != my_new_cred) {
+ if (my_cred != my_new_cred) {
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);
- proc_lock(p);
+ /*
+ * If we're changing the ruid from A to B, we might race with another thread that's setting ruid from B to A.
+ * The current locking mechanisms don't allow us to make the entire credential switch operation atomic,
+ * thus we may be able to change the process credentials from ruid A to B, but get preempted before incrementing the proc
+ * count of B. If a second thread sees the new process credentials and switches back to ruid A, that other thread
+ * may be able to decrement the proc count of B before we can increment it. This results in a panic.
+ * Incrementing the proc count of the target ruid, B, before setting the process credentials prevents this race.
+ */
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ (void)chgproccnt(ruid, 1);
+ }
+
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another thread
* also changed the credential after we took our
* reference. If p_ucred has changed then we should
* restart this again with the new cred.
+ *
+ * Note: the kauth_cred_setresuid has consumed a reference to my_cred, it p_ucred != my_cred, then my_cred must not be dereferenced!
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ /*
+ * We didn't successfully switch to the new ruid, so decrement
+ * the procs/uid count that we incremented above.
+ */
+ (void)chgproccnt(ruid, -1);
+ }
kauth_cred_unref(&my_new_cred);
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
/* try again */
continue;
}
+
p->p_ucred = my_new_cred;
/* update cred on proc */
PROC_UPDATE_CREDS_ONPROC(p);
- OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
- proc_unlock(p);
+ OSBitOrAtomic(P_SUGID, &p->p_flag);
+ proc_ucred_unlock(p);
+
+ if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) {
+ /*
+ * We switched to a new ruid, so decrement the count of procs running
+ * under the previous ruid
+ */
+ (void)chgproccnt(my_pcred->cr_ruid, -1);
+ }
}
break;
}
kauth_cred_unref(&my_cred);
set_security_token(p);
- return (0);
+ return 0;
}
gid = uap->gid;
AUDIT_ARG(gid, gid);
+ /* get current credential and take a reference while we muck with it */
my_cred = kauth_cred_proc_ref(p);
my_pcred = posix_cred_get(my_cred);
- if (gid != my_pcred->cr_rgid && /* allow setgid(getgid()) */
- gid != my_pcred->cr_svgid && /* allow setgid(saved gid) */
- (error = suser(my_cred, &p->p_acflag))) {
- kauth_cred_unref(&my_cred);
- return (error);
- }
+ for (;;) {
+ if (gid != my_pcred->cr_rgid && /* allow setgid(getgid()) */
+ gid != my_pcred->cr_svgid && /* allow setgid(saved gid) */
+ (error = suser(my_cred, &p->p_acflag))) {
+ kauth_cred_unref(&my_cred);
+ return error;
+ }
- /*
- * If we are priviledged, then set the saved and real GID too;
- * otherwise, just set the effective GID
- */
- if (suser(my_cred, &p->p_acflag) == 0) {
- svgid = gid;
- rgid = gid;
- }
+ /*
+ * If we are privileged, then set the saved and real GID too;
+ * otherwise, just set the effective GID
+ */
+ if (suser(my_cred, &p->p_acflag) == 0) {
+ svgid = gid;
+ rgid = gid;
+ } else {
+ svgid = KAUTH_GID_NONE;
+ rgid = KAUTH_GID_NONE;
+ }
- /* get current credential and take a reference while we muck with it */
- for (;;) {
-
- /*
+ /*
* Set the credential with new info. If there is no change,
* we get back the same credential we passed in; if there is
* a change, we drop the reference on the credential we
* passed in. The subsequent compare is safe, because it is
* a pointer compare rather than a contents compare.
- */
+ */
my_new_cred = kauth_cred_setresgid(my_cred, rgid, gid, svgid);
if (my_cred != my_new_cred) {
-
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);
- proc_lock(p);
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another thread
* also changed the credential after we took our
* should restart this again with the new cred.
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
kauth_cred_unref(&my_new_cred);
/* try again */
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
continue;
}
p->p_ucred = my_new_cred;
/* update cred on proc */
PROC_UPDATE_CREDS_ONPROC(p);
OSBitOrAtomic(P_SUGID, &p->p_flag);
- proc_unlock(p);
+ proc_ucred_unlock(p);
}
break;
}
/* Drop old proc reference or our extra reference */
kauth_cred_unref(&my_cred);
-
+
set_security_token(p);
- return (0);
+ return 0;
}
egid = uap->egid;
AUDIT_ARG(egid, egid);
+ /* get current credential and take a reference while we muck with it */
my_cred = kauth_cred_proc_ref(p);
my_pcred = posix_cred_get(my_cred);
- if (egid != my_pcred->cr_rgid &&
- egid != my_pcred->cr_svgid &&
- (error = suser(my_cred, &p->p_acflag))) {
- kauth_cred_unref(&my_cred);
- return (error);
- }
- /* get current credential and take a reference while we muck with it */
for (;;) {
- /*
+ if (egid != my_pcred->cr_rgid &&
+ egid != my_pcred->cr_svgid &&
+ (error = suser(my_cred, &p->p_acflag))) {
+ kauth_cred_unref(&my_cred);
+ return error;
+ }
+ /*
* Set the credential with new info. If there is no change,
* we get back the same credential we passed in; if there is
* a change, we drop the reference on the credential we
* passed in. The subsequent compare is safe, because it is
* a pointer compare rather than a contents compare.
- */
+ */
my_new_cred = kauth_cred_setresgid(my_cred, KAUTH_GID_NONE, egid, KAUTH_GID_NONE);
if (my_cred != my_new_cred) {
-
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);
- proc_lock(p);
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another thread
* also changed the credential after we took our
* should restart this again with the new cred.
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
kauth_cred_unref(&my_new_cred);
/* try again */
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
continue;
}
p->p_ucred = my_new_cred;
/* update cred on proc */
PROC_UPDATE_CREDS_ONPROC(p);
OSBitOrAtomic(P_SUGID, &p->p_flag);
- proc_unlock(p);
+ proc_ucred_unlock(p);
}
break;
}
kauth_cred_unref(&my_cred);
set_security_token(p);
- return (0);
+ return 0;
}
/*
rgid = uap->rgid;
egid = uap->egid;
- if (rgid == (uid_t)-1)
+ if (rgid == (uid_t)-1) {
rgid = KAUTH_GID_NONE;
- if (egid == (uid_t)-1)
+ }
+ if (egid == (uid_t)-1) {
egid = KAUTH_GID_NONE;
+ }
AUDIT_ARG(egid, egid);
AUDIT_ARG(rgid, rgid);
+ /* get current credential and take a reference while we muck with it */
my_cred = kauth_cred_proc_ref(p);
my_pcred = posix_cred_get(my_cred);
- if (((rgid != KAUTH_UID_NONE && /* allow no change of rgid */
- rgid != my_pcred->cr_rgid && /* allow rgid = rgid */
- rgid != my_pcred->cr_gid && /* allow rgid = egid */
- rgid != my_pcred->cr_svgid) || /* allow rgid = svgid */
- (egid != KAUTH_UID_NONE && /* allow no change of egid */
- egid != my_pcred->cr_groups[0] && /* allow no change of egid */
- egid != my_pcred->cr_gid && /* allow egid = egid */
- egid != my_pcred->cr_rgid && /* allow egid = rgid */
- egid != my_pcred->cr_svgid)) && /* allow egid = svgid */
- (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
- kauth_cred_unref(&my_cred);
- return (error);
- }
-
- /* get current credential and take a reference while we muck with it */
for (;;) {
+ if (((rgid != KAUTH_UID_NONE && /* allow no change of rgid */
+ rgid != my_pcred->cr_rgid && /* allow rgid = rgid */
+ rgid != my_pcred->cr_gid && /* allow rgid = egid */
+ rgid != my_pcred->cr_svgid) || /* allow rgid = svgid */
+ (egid != KAUTH_UID_NONE && /* allow no change of egid */
+ egid != my_pcred->cr_groups[0] && /* allow no change of egid */
+ egid != my_pcred->cr_gid && /* allow egid = egid */
+ egid != my_pcred->cr_rgid && /* allow egid = rgid */
+ egid != my_pcred->cr_svgid)) && /* allow egid = svgid */
+ (error = suser(my_cred, &p->p_acflag))) { /* allow root user any */
+ kauth_cred_unref(&my_cred);
+ return error;
+ }
+
uid_t new_egid = my_pcred->cr_gid;
uid_t new_rgid = my_pcred->cr_rgid;
uid_t svgid = KAUTH_UID_NONE;
-
- /*
+
+ /*
* Set the credential with new info. If there is no change,
* we get back the same credential we passed in; if there is
* a change, we drop the reference on the credential we
* passed in. The subsequent compare is safe, because it is
* a pointer compare rather than a contents compare.
- */
- if (egid == KAUTH_UID_NONE && my_pcred->cr_gid != egid) {
+ */
+ if (egid != KAUTH_UID_NONE && my_pcred->cr_gid != egid) {
/* changing the effective GID */
new_egid = egid;
OSBitOrAtomic(P_SUGID, &p->p_flag);
*/
if (my_pcred->cr_svgid != uap->rgid &&
my_pcred->cr_svgid != uap->egid) {
- svgid = new_egid;
+ svgid = new_egid;
OSBitOrAtomic(P_SUGID, &p->p_flag);
}
my_new_cred = kauth_cred_setresgid(my_cred, rgid, egid, svgid);
if (my_cred != my_new_cred) {
-
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);
- proc_lock(p);
+ proc_ucred_lock(p);
/* need to protect for a race where another thread
* also changed the credential after we took our
* reference. If p_ucred has changed then we
* should restart this again with the new cred.
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
kauth_cred_unref(&my_new_cred);
/* try again */
my_cred = kauth_cred_proc_ref(p);
+ my_pcred = posix_cred_get(my_cred);
continue;
}
p->p_ucred = my_new_cred;
/* update cred on proc */
PROC_UPDATE_CREDS_ONPROC(p);
OSBitOrAtomic(P_SUGID, &p->p_flag); /* XXX redundant? */
- proc_unlock(p);
+ proc_ucred_unlock(p);
}
break;
}
kauth_cred_unref(&my_cred);
set_security_token(p);
- return (0);
+ return 0;
}
/*
* Set the per-thread override identity. The first parameter can be the
- * current real UID, KAUTH_UID_NONE, or, if the caller is priviledged, it
+ * current real UID, KAUTH_UID_NONE, or, if the caller is privileged, it
* can be any UID. If it is KAUTH_UID_NONE, then as a special case, this
* means "revert to the per process credential"; otherwise, if permitted,
* it changes the effective, real, and saved UIDs and GIDs for the current
AUDIT_ARG(uid, uid);
AUDIT_ARG(gid, gid);
- if (proc_suser(p) != 0)
- return (EPERM);
-
- if (uid == KAUTH_UID_NONE) {
+ if (proc_suser(p) != 0) {
+ return EPERM;
+ }
+ if (uid == KAUTH_UID_NONE) {
/* must already be assuming another identity in order to revert back */
- if ((uthread->uu_flag & UT_SETUID) == 0)
- return (EPERM);
+ if ((uthread->uu_flag & UT_SETUID) == 0) {
+ return EPERM;
+ }
/* revert to delayed binding of process credential */
uc = kauth_cred_proc_ref(p);
/* cannot already be assuming another identity */
if ((uthread->uu_flag & UT_SETUID) != 0) {
- return (EPERM);
+ return EPERM;
}
/*
* current credential while we muck with it, so we can do
* the post-compare for changes by pointer.
*/
- kauth_cred_ref(uthread->uu_ucred);
+ kauth_cred_ref(uthread->uu_ucred);
my_cred = uthread->uu_ucred;
my_new_cred = kauth_cred_setuidgid(my_cred, uid, gid);
- if (my_cred != my_new_cred)
+ if (my_cred != my_new_cred) {
uthread->uu_ucred = my_new_cred;
+ }
uthread->uu_flag |= UT_SETUID;
/* Drop old uthread reference or our extra reference */
* XXX it is unclear whether P_SUGID should be st at this point;
* XXX in theory, it is being deprecated.
*/
- return (0);
+ return 0;
}
AUDIT_ARG(value32, uap->assume);
if (proc_suser(p) != 0) {
- return (EPERM);
+ return EPERM;
}
/*
*/
if (uap->assume != 0) {
/* can't do this if we have already assumed an identity */
- if ((uthread->uu_flag & UT_SETUID) != 0)
- return (EPERM);
-
+ if ((uthread->uu_flag & UT_SETUID) != 0) {
+ return EPERM;
+ }
+
target_proc = proc_find(uap->pid);
/* can't assume the identity of the kernel process */
if (target_proc == NULL || target_proc == kernproc) {
- if (target_proc!= NULL)
+ if (target_proc != NULL) {
proc_rele(target_proc);
- return (ESRCH);
+ }
+ return ESRCH;
}
-
+
/*
* Take a reference on the credential used in our target
* process then use it as the identity for our current
* credential following our assumption of a per-thread one,
* since the credential cache will maintain a unique instance.
*/
- kauth_cred_ref(uthread->uu_ucred);
+ kauth_cred_ref(uthread->uu_ucred);
my_cred = uthread->uu_ucred;
my_target_cred = kauth_cred_proc_ref(target_proc);
my_target_pcred = posix_cred_get(my_target_cred);
my_new_cred = kauth_cred_setuidgid(my_cred, my_target_pcred->cr_uid, my_target_pcred->cr_gid);
- if (my_cred != my_new_cred)
+ if (my_cred != my_new_cred) {
uthread->uu_ucred = my_new_cred;
-
+ }
+
uthread->uu_flag |= UT_SETUID;
-
+
/* Drop old uthread reference or our extra reference */
proc_rele(target_proc);
kauth_cred_unref(&my_cred);
kauth_cred_unref(&my_target_cred);
- return (0);
+ return 0;
}
-
+
/*
* Otherwise, we are reverting back to normal mode of operation where
* delayed binding of the process credential sets the credential in
* the thread (uu_ucred)
*/
- if ((uthread->uu_flag & UT_SETUID) == 0)
- return (EPERM);
+ if ((uthread->uu_flag & UT_SETUID) == 0) {
+ return EPERM;
+ }
/* revert to delayed binding of process credential */
my_new_cred = kauth_cred_proc_ref(p);
kauth_cred_unref(&uthread->uu_ucred);
uthread->uu_ucred = my_new_cred;
uthread->uu_flag &= ~UT_SETUID;
-
- return (0);
+
+ return 0;
}
* flag the process as having set privilege since the last exec.
*/
static int
-setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
+setgroups1(proc_t p, u_int ngrp, user_addr_t gidset, uid_t gmuid, __unused int32_t *retval)
{
- u_int ngrp;
- gid_t newgroups[NGROUPS] = { 0 };
- int error;
- kauth_cred_t my_cred, my_new_cred;
- struct uthread *uthread = get_bsdthread_info(current_thread());
+ gid_t newgroups[NGROUPS] = { 0 };
+ int error;
- 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);
+ DEBUG_CRED_ENTER("setgroups1 (%d/%d): %d 0x%016x %d\n", p->p_pid,
+ (p->p_pptr ? p->p_pptr->p_pid : 0), ngrp, gidset, gmuid);
- ngrp = gidsetsize;
- if (ngrp > NGROUPS)
- return (EINVAL);
+ if (ngrp > NGROUPS) {
+ return EINVAL;
+ }
- if ( ngrp < 1 ) {
- ngrp = 1;
- } else {
+ if (ngrp >= 1) {
error = copyin(gidset,
- (caddr_t)newgroups, ngrp * sizeof(gid_t));
+ (caddr_t)newgroups, ngrp * sizeof(gid_t));
if (error) {
- return (error);
+ return error;
}
}
+ return setgroups_internal(p, ngrp, newgroups, gmuid);
+}
+
+int
+setgroups_internal(proc_t p, u_int ngrp, gid_t *newgroups, uid_t gmuid)
+{
+ struct uthread *uthread = get_bsdthread_info(current_thread());
+ kauth_cred_t my_cred, my_new_cred;
+ int error;
my_cred = kauth_cred_proc_ref(p);
if ((error = suser(my_cred, &p->p_acflag))) {
kauth_cred_unref(&my_cred);
- return (error);
+ return error;
+ }
+
+ if (ngrp < 1) {
+ ngrp = 1;
+ newgroups[0] = 0;
}
if ((uthread->uu_flag & UT_SETUID) != 0) {
#if DEBUG_CRED
int my_cred_flags = uthread->uu_ucred->cr_flags;
-#endif /* DEBUG_CRED */
+#endif /* DEBUG_CRED */
kauth_cred_unref(&my_cred);
/*
uthread->uu_ucred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
#if DEBUG_CRED
if (my_cred != uthread->uu_ucred) {
- 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);
+ 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);
}
-#endif /* DEBUG_CRED */
+#endif /* DEBUG_CRED */
} else {
-
/*
* get current credential and take a reference while we muck
* with it
*/
for (;;) {
- /*
+ /*
* Set the credential with new info. If there is no
* change, we get back the same credential we passed
* in; if there is a change, we drop the reference on
*/
my_new_cred = kauth_cred_setgroups(my_cred, &newgroups[0], ngrp, gmuid);
if (my_cred != my_new_cred) {
-
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);
- proc_lock(p);
+ proc_ucred_lock(p);
/*
* We need to protect for a race where another
* thread also changed the credential after we
- * took our reference. If p_ucred has
+ * took our reference. If p_ucred has
* changed then we should restart this again
* with the new cred.
*/
if (p->p_ucred != my_cred) {
- proc_unlock(p);
+ proc_ucred_unlock(p);
kauth_cred_unref(&my_new_cred);
my_cred = kauth_cred_proc_ref(p);
/* try again */
/* update cred on proc */
PROC_UPDATE_CREDS_ONPROC(p);
OSBitOrAtomic(P_SUGID, &p->p_flag);
- proc_unlock(p);
+ proc_ucred_unlock(p);
}
break;
}
set_security_token(p);
}
- return (0);
+ return 0;
}
{
DEBUG_CRED_ENTER("initgroups\n");
- return(setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval));
+ return setgroups1(p, uap->gidsetsize, uap->gidset, uap->gmuid, retval);
}
{
DEBUG_CRED_ENTER("setgroups\n");
- return(setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval));
+ return setgroups1(p, uap->gidsetsize, uap->gidset, KAUTH_UID_NONE, retval);
}
/*
* Set the per-thread/per-process supplementary groups list.
- *
+ *
* XXX implement setsgroups
*
*/
int
setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int32_t *retval)
{
- return(ENOTSUP);
+ return ENOTSUP;
}
/*
* Set the per-thread/per-process whiteout groups list.
- *
+ *
* XXX implement setwgroups
*
*/
int
setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval)
{
- return(ENOTSUP);
+ return ENOTSUP;
}
{
int is_member;
- if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member)
- return (1);
- return (0);
+ if (kauth_cred_ismember_gid(cred, gid, &is_member) == 0 && is_member) {
+ return 1;
+ }
+ return 0;
}
suser(kauth_cred_t cred, u_short *acflag)
{
#if DIAGNOSTIC
- if (!IS_VALID_CRED(cred))
+ if (!IS_VALID_CRED(cred)) {
panic("suser");
+ }
#endif
if (kauth_cred_getuid(cred) == 0) {
- if (acflag)
+ if (acflag) {
*acflag |= ASU;
- return (0);
+ }
+ return 0;
}
- return (EPERM);
+ return EPERM;
}
int
getlogin(proc_t p, struct getlogin_args *uap, __unused int32_t *retval)
{
- char buffer[MAXLOGNAME+1];
+ char buffer[MAXLOGNAME + 1];
struct session * sessp;
- bzero(buffer, MAXLOGNAME+1);
+ bzero(buffer, MAXLOGNAME + 1);
sessp = proc_session(p);
- if (uap->namelen > MAXLOGNAME)
+ if (uap->namelen > MAXLOGNAME) {
uap->namelen = MAXLOGNAME;
+ }
- if(sessp != SESSION_NULL) {
+ if (sessp != SESSION_NULL) {
session_lock(sessp);
bcopy( sessp->s_login, buffer, uap->namelen);
session_unlock(sessp);
}
session_rele(sessp);
- return (copyout((caddr_t)buffer, uap->namebuf, uap->namelen));
+ return copyout((caddr_t)buffer, uap->namebuf, uap->namelen);
}
+void
+setlogin_internal(proc_t p, const char login[static MAXLOGNAME])
+{
+ struct session *sessp = proc_session(p);
+
+ if (sessp != SESSION_NULL) {
+ session_lock(sessp);
+ bcopy(login, sessp->s_login, MAXLOGNAME);
+ session_unlock(sessp);
+ session_rele(sessp);
+ }
+}
/*
* setlogin
setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval)
{
int error;
- size_t dummy=0;
- char buffer[MAXLOGNAME+1];
- struct session * sessp;
+ size_t dummy = 0;
+ char buffer[MAXLOGNAME + 1];
- if ((error = proc_suser(p)))
- return (error);
+ if ((error = proc_suser(p))) {
+ return error;
+ }
- bzero(&buffer[0], MAXLOGNAME+1);
+ bzero(&buffer[0], MAXLOGNAME + 1);
error = copyinstr(uap->namebuf,
(caddr_t) &buffer[0],
MAXLOGNAME - 1, (size_t *)&dummy);
- sessp = proc_session(p);
-
- if (sessp != SESSION_NULL) {
- session_lock(sessp);
- bcopy(buffer, sessp->s_login, MAXLOGNAME);
- session_unlock(sessp);
- session_rele(sessp);
- }
-
+ setlogin_internal(p, buffer);
if (!error) {
AUDIT_ARG(text, buffer);
- } else if (error == ENAMETOOLONG)
+ } else if (error == ENAMETOOLONG) {
error = EINVAL;
- return (error);
+ }
+ return error;
}
int
set_security_token(proc_t p)
{
+ return set_security_token_task_internal(p, p->task);
+}
+
+static void
+proc_calc_audit_token(proc_t p, kauth_cred_t my_cred, audit_token_t *audit_token)
+{
+ posix_cred_t my_pcred = posix_cred_get(my_cred);
+
+ /*
+ * The current layout of the Mach audit token explicitly
+ * adds these fields. But nobody should rely on such
+ * a literal representation. Instead, the BSM library
+ * provides a function to convert an audit token into
+ * a BSM subject. Use of that mechanism will isolate
+ * the user of the trailer from future representation
+ * changes.
+ */
+ audit_token->val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
+ audit_token->val[1] = my_pcred->cr_uid;
+ audit_token->val[2] = my_pcred->cr_gid;
+ audit_token->val[3] = my_pcred->cr_ruid;
+ audit_token->val[4] = my_pcred->cr_rgid;
+ audit_token->val[5] = p->p_pid;
+ audit_token->val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
+ audit_token->val[7] = p->p_idversion;
+}
+
+/*
+ * Set the secrity token of the task with current euid and eguid
+ * The function takes a proc and a task, where proc->task might point to a
+ * different task if called from exec.
+ */
+
+int
+set_security_token_task_internal(proc_t p, void *t)
+{
+ kauth_cred_t my_cred;
security_token_t sec_token;
audit_token_t audit_token;
- kauth_cred_t my_cred;
- posix_cred_t my_pcred;
host_priv_t host_priv;
+ task_t task = t;
/*
* Don't allow a vfork child to override the parent's token settings
* suffer along using the parent's token until the exec(). It's all
* undefined behavior anyway, right?
*/
- if (p->task == current_task()) {
- uthread_t uthread;
+ if (task == current_task()) {
+ uthread_t uthread;
uthread = (uthread_t)get_bsdthread_info(current_thread());
- if (uthread->uu_flag & UT_VFORK)
- return (1);
+ if (uthread->uu_flag & UT_VFORK) {
+ return 1;
+ }
}
-
+
my_cred = kauth_cred_proc_ref(p);
- my_pcred = posix_cred_get(my_cred);
+
+ proc_calc_audit_token(p, my_cred, &audit_token);
/* XXX mach_init doesn't have a p_ucred when it calls this function */
if (IS_VALID_CRED(my_cred)) {
sec_token.val[1] = 0;
}
- /*
- * The current layout of the Mach audit token explicitly
- * adds these fields. But nobody should rely on such
- * a literal representation. Instead, the BSM library
- * provides a function to convert an audit token into
- * a BSM subject. Use of that mechanism will isolate
- * the user of the trailer from future representation
- * changes.
- */
- audit_token.val[0] = my_cred->cr_audit.as_aia_p->ai_auid;
- audit_token.val[1] = my_pcred->cr_uid;
- audit_token.val[2] = my_pcred->cr_gid;
- audit_token.val[3] = my_pcred->cr_ruid;
- audit_token.val[4] = my_pcred->cr_rgid;
- audit_token.val[5] = p->p_pid;
- audit_token.val[6] = my_cred->cr_audit.as_aia_p->ai_asid;
- audit_token.val[7] = p->p_idversion;
-
host_priv = (sec_token.val[0]) ? HOST_PRIV_NULL : host_priv_self();
#if CONFIG_MACF
- if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred))
+ if (host_priv != HOST_PRIV_NULL && mac_system_check_host_priv(my_cred)) {
host_priv = HOST_PRIV_NULL;
+ }
#endif
kauth_cred_unref(&my_cred);
#if DEVELOPMENT || DEBUG
- /*
+ /*
* Update the pid an proc name for importance base if any
*/
- task_importance_update_owner_info(p->task);
+ task_importance_update_owner_info(task);
#endif
- return (host_security_set_task_token(host_security_self(),
- p->task,
- sec_token,
- audit_token,
- host_priv) != KERN_SUCCESS);
+ return host_security_set_task_token(host_security_self(),
+ task,
+ sec_token,
+ audit_token,
+ host_priv) != KERN_SUCCESS;
}
-
-/*
- * Fill in a struct xucred based on a kauth_cred_t.
- */
-__private_extern__
void
-cru2x(kauth_cred_t cr, struct xucred *xcr)
-{
- posix_cred_t pcr = posix_cred_get(cr);
-
- bzero(xcr, sizeof(*xcr));
- xcr->cr_version = XUCRED_VERSION;
- xcr->cr_uid = kauth_cred_getuid(cr);
- xcr->cr_ngroups = pcr->cr_ngroups;
- bcopy(pcr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
-}
-
-#if CONFIG_LCTX
-
-/*
- * Set Login Context ID
- */
-/*
- * MPSAFE - assignment of (visible) process to context protected by ALLLCTX_LOCK,
- * LCTX by its own locks.
- */
-int
-setlcid(proc_t p0, struct setlcid_args *uap, __unused int32_t *retval)
+proc_parent_audit_token(proc_t p, audit_token_t *token_out)
{
- proc_t p;
- struct lctx *l;
- int error = 0;
- int refheld = 0;
-
- AUDIT_ARG(pid, uap->pid);
- AUDIT_ARG(value32, uap->lcid);
- if (uap->pid == LCID_PROC_SELF) { /* Create/Join/Leave */
- p = p0;
- } else { /* Adopt/Orphan */
- p = proc_find(uap->pid);
- if (p == NULL)
- return (ESRCH);
- refheld = 1;
- }
-
-#if CONFIG_MACF
- error = mac_proc_check_setlcid(p0, p, uap->pid, uap->lcid);
- if (error)
- goto out;
-#endif
-
- switch (uap->lcid) {
- /* Leave/Orphan */
- case LCID_REMOVE:
-
- /* Only root may Leave/Orphan. */
- if (!kauth_cred_issuser(kauth_cred_get())) {
- error = EPERM;
- goto out;
- }
-
- /* Process not in login context. */
- if (p->p_lctx == NULL) {
- error = ENOATTR;
- goto out;
- }
-
- l = NULL;
-
- break;
-
- /* Create */
- case LCID_CREATE:
-
- /* Create only valid for self! */
- if (uap->pid != LCID_PROC_SELF) {
- error = EPERM;
- goto out;
- }
-
- /* Already in a login context. */
- if (p->p_lctx != NULL) {
- error = EPERM;
- goto out;
- }
-
- l = lccreate();
- if (l == NULL) {
- error = ENOMEM;
- goto out;
- }
-
- LCTX_LOCK(l);
-
- break;
+ proc_t parent;
+ kauth_cred_t my_cred;
- /* Join/Adopt */
- default:
+ proc_list_lock();
- /* Only root may Join/Adopt. */
- if (!kauth_cred_issuser(kauth_cred_get())) {
- error = EPERM;
- goto out;
- }
+ parent = p->p_pptr;
+ my_cred = kauth_cred_proc_ref(parent);
+ proc_calc_audit_token(parent, my_cred, token_out);
+ kauth_cred_unref(&my_cred);
- l = lcfind(uap->lcid);
- if (l == NULL) {
- error = ENOATTR;
- goto out;
- }
+ proc_list_unlock();
+}
- break;
- }
- ALLLCTX_LOCK;
- leavelctx(p);
- enterlctx(p, l, (uap->lcid == LCID_CREATE) ? 1 : 0);
- ALLLCTX_UNLOCK;
+int get_audit_token_pid(audit_token_t *audit_token);
-out:
- if (refheld != 0)
- proc_rele(p);
- return (error);
-}
-
-/*
- * Get Login Context ID
- */
-/*
- * MPSAFE - membership of (visible) process in a login context
- * protected by the all-context lock.
- */
int
-getlcid(proc_t p0, struct getlcid_args *uap, int32_t *retval)
+get_audit_token_pid(audit_token_t *audit_token)
{
- proc_t p;
- int error = 0;
- int refheld = 0;
-
- AUDIT_ARG(pid, uap->pid);
- if (uap->pid == LCID_PROC_SELF) {
- p = p0;
- } else {
- p = proc_find(uap->pid);
- if (p == NULL)
- return (ESRCH);
- refheld = 1;
+ /* keep in-sync with set_security_token (above) */
+ if (audit_token) {
+ return (int)audit_token->val[5];
}
-
-#if CONFIG_MACF
- error = mac_proc_check_getlcid(p0, p, uap->pid);
- if (error)
- goto out;
-#endif
- ALLLCTX_LOCK;
- if (p->p_lctx == NULL) {
- error = ENOATTR;
- ALLLCTX_UNLOCK;
- goto out;
- }
- *retval = p->p_lctx->lc_id;
- ALLLCTX_UNLOCK;
- out:
- if (refheld != 0)
- proc_rele(p);
-
- return (error);
+ return -1;
}
-#else /* LCTX */
-int
-setlcid(proc_t p0, struct setlcid_args *uap, int32_t *retval)
-{
- return (ENOSYS);
-}
-int
-getlcid(proc_t p0, struct getlcid_args *uap, int32_t *retval)
+/*
+ * Fill in a struct xucred based on a kauth_cred_t.
+ */
+__private_extern__
+void
+cru2x(kauth_cred_t cr, struct xucred *xcr)
{
+ posix_cred_t pcr = posix_cred_get(cr);
- return (ENOSYS);
+ bzero(xcr, sizeof(*xcr));
+ xcr->cr_version = XUCRED_VERSION;
+ xcr->cr_uid = kauth_cred_getuid(cr);
+ xcr->cr_ngroups = pcr->cr_ngroups;
+ bcopy(pcr->cr_groups, xcr->cr_groups, sizeof(xcr->cr_groups));
}
-#endif /* !LCTX */