X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/4bd07ac2140668789aa3ee8ec4dde4a3e0a3bba5..a991bd8d3e7fe02dbca0644054bab73c5b75324a:/bsd/kern/kern_prot.c diff --git a/bsd/kern/kern_prot.c b/bsd/kern/kern_prot.c index e90c68c55..d689b70d5 100644 --- a/bsd/kern/kern_prot.c +++ b/bsd/kern/kern_prot.c @@ -2,7 +2,7 @@ * 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 @@ -11,10 +11,10 @@ * 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, @@ -22,12 +22,12 @@ * 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. @@ -66,7 +66,7 @@ * 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 @@ -95,8 +95,7 @@ #include #include #include - -#define chgproccnt_ok(p) 1 +#include #include @@ -110,7 +109,7 @@ #include #include -#include /* for current_task() */ +#include /* for current_task() */ #include @@ -125,13 +124,13 @@ * 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); @@ -156,7 +155,7 @@ setprivexec(proc_t p, struct setprivexec_args *uap, int32_t *retval) AUDIT_ARG(value32, uap->flag); *retval = p->p_debugger; p->p_debugger = (uap->flag != 0); - return(0); + return 0; } @@ -174,9 +173,8 @@ setprivexec(proc_t p, struct setprivexec_args *uap, int32_t *retval) int getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval) { - *retval = p->p_pid; - return (0); + return 0; } @@ -194,9 +192,8 @@ getpid(proc_t p, __unused struct getpid_args *uap, int32_t *retval) int getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval) { - *retval = p->p_ppid; - return (0); + return 0; } @@ -214,9 +211,8 @@ getppid(proc_t p, __unused struct getppid_args *uap, int32_t *retval) int getpgrp(proc_t p, __unused struct getpgrp_args *uap, int32_t *retval) { - *retval = p->p_pgrpid; - return (0); + return 0; } @@ -243,17 +239,20 @@ getpgid(proc_t p, struct getpgid_args *uap, int32_t *retval) 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; } @@ -281,20 +280,23 @@ getsid(proc_t p, struct getsid_args *uap, int32_t *retval) 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; } @@ -310,9 +312,8 @@ found: int getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval) { - - *retval = kauth_getruid(); - return (0); + *retval = kauth_getruid(); + return 0; } @@ -328,9 +329,8 @@ getuid(__unused proc_t p, __unused struct getuid_args *uap, int32_t *retval) int geteuid(__unused proc_t p, __unused struct geteuid_args *uap, int32_t *retval) { - - *retval = kauth_getuid(); - return (0); + *retval = kauth_getuid(); + return 0; } @@ -349,22 +349,25 @@ int 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; } @@ -380,9 +383,8 @@ gettid(__unused proc_t p, struct gettid_args *uap, int32_t *retval) int getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval) { - *retval = kauth_getrgid(); - return (0); + return 0; } @@ -404,9 +406,8 @@ getgid(__unused proc_t p, __unused struct getgid_args *uap, int32_t *retval) int getegid(__unused proc_t p, __unused struct getegid_args *uap, int32_t *retval) { - *retval = kauth_getgid(); - return (0); + return 0; } @@ -455,22 +456,22 @@ getgroups(__unused proc_t p, struct getgroups_args *uap, int32_t *retval) 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; } @@ -484,12 +485,12 @@ getgroups(__unused proc_t p, struct getgroups_args *uap, int32_t *retval) 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 * */ @@ -497,9 +498,30 @@ getsgroups(__unused proc_t p, __unused struct getsgroups_args *uap, __unused int 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 @@ -528,18 +550,11 @@ getwgroups(__unused proc_t p, __unused struct getwgroups_args *uap, __unused int 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; } @@ -576,15 +591,15 @@ setsid(proc_t p, __unused struct setsid_args *uap, int32_t *retval) * 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; @@ -595,8 +610,9 @@ setpgid(proc_t curp, register struct setpgid_args *uap, __unused int32_t *retval 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; } @@ -628,14 +644,14 @@ setpgid(proc_t curp, register struct setpgid_args *uap, __unused int32_t *retval 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; @@ -644,13 +660,16 @@ setpgid(proc_t curp, register struct setpgid_args *uap, __unused int32_t *retval } 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; } @@ -670,6 +689,12 @@ out: * 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) { @@ -682,8 +707,8 @@ 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; } @@ -728,11 +753,11 @@ setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval) AUDIT_ARG(uid, uid); for (;;) { - if (uid != my_pcred->cr_ruid && /* allow setuid(getuid()) */ - uid != my_pcred->cr_svuid && /* allow setuid(saved 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); + return error; } /* @@ -755,19 +780,19 @@ setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval) * 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); /* @@ -778,7 +803,7 @@ setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval) * 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 && chgproccnt_ok(p)) { + if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) { (void)chgproccnt(ruid, 1); } @@ -797,7 +822,7 @@ setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval) * We didn't successfully switch to the new ruid, so decrement * the procs/uid count that we incremented above. */ - if (ruid != KAUTH_UID_NONE && chgproccnt_ok(p)) { + if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) { (void)chgproccnt(ruid, -1); } kauth_cred_unref(&my_new_cred); @@ -816,7 +841,7 @@ setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval) * If we've updated the ruid, decrement the count of procs running * under the previous ruid */ - if (ruid != KAUTH_UID_NONE && chgproccnt_ok(p)) { + if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) { (void)chgproccnt(my_pcred->cr_ruid, -1); } } @@ -824,9 +849,9 @@ setuid(proc_t p, struct setuid_args *uap, __unused int32_t *retval) } /* Drop old proc reference or our extra reference */ kauth_cred_unref(&my_cred); - + set_security_token(p); - return (0); + return 0; } @@ -865,24 +890,22 @@ seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval) my_pcred = posix_cred_get(my_cred); for (;;) { - if (euid != my_pcred->cr_ruid && euid != my_pcred->cr_svuid && - (error = suser(my_cred, &p->p_acflag))) { + (error = suser(my_cred, &p->p_acflag))) { kauth_cred_unref(&my_cred); - return (error); + 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_ucred_lock(p); @@ -912,7 +935,7 @@ seteuid(proc_t p, struct seteuid_args *uap, __unused int32_t *retval) kauth_cred_unref(&my_cred); set_security_token(p); - return (0); + return 0; } @@ -959,10 +982,12 @@ setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval) 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); @@ -970,31 +995,30 @@ setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval) my_pcred = posix_cred_get(my_cred); 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 */ + 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); + return error; } uid_t new_euid; uid_t svuid = KAUTH_UID_NONE; new_euid = my_pcred->cr_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. - */ + */ if (euid != KAUTH_UID_NONE && my_pcred->cr_uid != euid) { /* changing the effective UID */ new_euid = euid; @@ -1008,14 +1032,13 @@ setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval) */ 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); /* @@ -1026,7 +1049,7 @@ setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval) * 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 && chgproccnt_ok(p)) { + if (ruid != KAUTH_UID_NONE && !proc_has_persona(p)) { (void)chgproccnt(ruid, 1); } @@ -1041,7 +1064,7 @@ setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval) */ if (p->p_ucred != my_cred) { proc_ucred_unlock(p); - if (ruid != KAUTH_UID_NONE && chgproccnt_ok(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. @@ -1061,7 +1084,7 @@ setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval) OSBitOrAtomic(P_SUGID, &p->p_flag); proc_ucred_unlock(p); - if (ruid != KAUTH_UID_NONE && chgproccnt_ok(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 @@ -1075,7 +1098,7 @@ setreuid(proc_t p, struct setreuid_args *uap, __unused int32_t *retval) kauth_cred_unref(&my_cred); set_security_token(p); - return (0); + return 0; } @@ -1124,18 +1147,18 @@ setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval) my_pcred = posix_cred_get(my_cred); for (;;) { - if (gid != my_pcred->cr_rgid && /* allow setgid(getgid()) */ - gid != my_pcred->cr_svgid && /* allow setgid(saved gid) */ + 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); + return error; } /* * 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) { + if (suser(my_cred, &p->p_acflag) == 0) { svgid = gid; rgid = gid; } else { @@ -1143,16 +1166,15 @@ setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval) rgid = KAUTH_GID_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. - */ + */ 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_ucred_lock(p); @@ -1180,9 +1202,9 @@ setgid(proc_t p, struct setgid_args *uap, __unused int32_t *retval) } /* Drop old proc reference or our extra reference */ kauth_cred_unref(&my_cred); - + set_security_token(p); - return (0); + return 0; } @@ -1232,18 +1254,17 @@ setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval) egid != my_pcred->cr_svgid && (error = suser(my_cred, &p->p_acflag))) { kauth_cred_unref(&my_cred); - return (error); + 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_ucred_lock(p); @@ -1274,7 +1295,7 @@ setegid(proc_t p, struct setegid_args *uap, __unused int32_t *retval) kauth_cred_unref(&my_cred); set_security_token(p); - return (0); + return 0; } /* @@ -1327,10 +1348,12 @@ setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval) 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); @@ -1339,33 +1362,32 @@ setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval) my_pcred = posix_cred_get(my_cred); 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 */ + 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); + 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) { /* changing the effective GID */ new_egid = egid; @@ -1384,13 +1406,12 @@ setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval) */ 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_ucred_lock(p); @@ -1419,7 +1440,7 @@ setregid(proc_t p, struct setregid_args *uap, __unused int32_t *retval) kauth_cred_unref(&my_cred); set_security_token(p); - return (0); + return 0; } @@ -1444,14 +1465,15 @@ settid(proc_t p, struct settid_args *uap, __unused int32_t *retval) 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); @@ -1463,7 +1485,7 @@ settid(proc_t p, struct settid_args *uap, __unused int32_t *retval) /* cannot already be assuming another identity */ if ((uthread->uu_flag & UT_SETUID) != 0) { - return (EPERM); + return EPERM; } /* @@ -1473,11 +1495,12 @@ settid(proc_t p, struct settid_args *uap, __unused int32_t *retval) * 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 */ @@ -1489,7 +1512,7 @@ settid(proc_t p, struct settid_args *uap, __unused int32_t *retval) * XXX it is unclear whether P_SUGID should be st at this point; * XXX in theory, it is being deprecated. */ - return (0); + return 0; } @@ -1515,7 +1538,7 @@ settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *re AUDIT_ARG(value32, uap->assume); if (proc_suser(p) != 0) { - return (EPERM); + return EPERM; } /* @@ -1531,17 +1554,19 @@ settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *re */ 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 @@ -1554,39 +1579,41 @@ settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *re * 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; } @@ -1626,40 +1653,50 @@ settid_with_pid(proc_t p, struct settid_with_pid_args *uap, __unused int32_t *re * 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); /* @@ -1675,17 +1712,16 @@ setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused 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 @@ -1695,14 +1731,13 @@ setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused */ 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_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. */ @@ -1729,7 +1764,7 @@ setgroups1(proc_t p, u_int gidsetsize, user_addr_t gidset, uid_t gmuid, __unused set_security_token(p); } - return (0); + return 0; } @@ -1767,7 +1802,7 @@ initgroups(proc_t p, struct initgroups_args *uap, __unused int32_t *retval) { 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); } @@ -1801,13 +1836,13 @@ setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *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 * */ @@ -1815,12 +1850,12 @@ setgroups(proc_t p, struct setgroups_args *uap, __unused int32_t *retval) 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 * */ @@ -1828,7 +1863,7 @@ setsgroups(__unused proc_t p, __unused struct setsgroups_args *uap, __unused int int setwgroups(__unused proc_t p, __unused struct setwgroups_args *uap, __unused int32_t *retval) { - return(ENOTSUP); + return ENOTSUP; } @@ -1843,9 +1878,10 @@ groupmember(gid_t gid, kauth_cred_t cred) { 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; } @@ -1867,15 +1903,17 @@ int 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; } @@ -1905,26 +1943,39 @@ suser(kauth_cred_t cred, u_short *acflag) 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 @@ -1946,35 +1997,28 @@ int 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; } @@ -1986,11 +2030,47 @@ setlogin(proc_t p, struct setlogin_args *uap, __unused int32_t *retval) 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 @@ -1998,15 +2078,17 @@ set_security_token(proc_t p) * 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)) { @@ -2017,43 +2099,42 @@ set_security_token(proc_t p) 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; +} + +void +proc_parent_audit_token(proc_t p, audit_token_t *token_out) +{ + proc_t parent; + kauth_cred_t my_cred; + + proc_list_lock(); + + 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); + + proc_list_unlock(); } @@ -2063,8 +2144,9 @@ int get_audit_token_pid(audit_token_t *audit_token) { /* keep in-sync with set_security_token (above) */ - if (audit_token) + if (audit_token) { return (int)audit_token->val[5]; + } return -1; }