diff options
Diffstat (limited to 'usr/src/uts/common/syscall')
| -rw-r--r-- | usr/src/uts/common/syscall/gid.c | 33 | ||||
| -rw-r--r-- | usr/src/uts/common/syscall/groups.c | 9 | ||||
| -rw-r--r-- | usr/src/uts/common/syscall/ppriv.c | 59 | ||||
| -rw-r--r-- | usr/src/uts/common/syscall/uid.c | 59 |
4 files changed, 124 insertions, 36 deletions
diff --git a/usr/src/uts/common/syscall/gid.c b/usr/src/uts/common/syscall/gid.c index fbf90d3d3e..ecad0add3f 100644 --- a/usr/src/uts/common/syscall/gid.c +++ b/usr/src/uts/common/syscall/gid.c @@ -64,21 +64,35 @@ setgid(gid_t gid) /* * Need to pre-allocate the new cred structure before grabbing - * the p_crlock mutex. + * the p_crlock mutex. We cannot hold the mutex across the + * secpolicy functions. */ newcr = cralloc_ksid(); p = ttoproc(curthread); mutex_enter(&p->p_crlock); +retry: cr = p->p_cred; + crhold(cr); + mutex_exit(&p->p_crlock); + if ((gid == cr->cr_rgid || gid == cr->cr_sgid) && secpolicy_allow_setid(cr, -1, B_TRUE) != 0) { + mutex_enter(&p->p_crlock); + crfree(cr); + if (cr != p->p_cred) + goto retry; error = 0; crcopy_to(cr, newcr); p->p_cred = newcr; newcr->cr_gid = gid; crsetsid(newcr, ksp, KSID_GROUP); + mutex_exit(&p->p_crlock); } else if ((error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) { + mutex_enter(&p->p_crlock); + crfree(cr); + if (cr != p->p_cred) + goto retry; /* * A privileged process that makes itself look like a * set-gid process must be marked to produce no core dump. @@ -93,15 +107,15 @@ setgid(gid_t gid) newcr->cr_rgid = gid; newcr->cr_sgid = gid; crsetsid(newcr, ksp, KSID_GROUP); + mutex_exit(&p->p_crlock); } else { crfree(newcr); + crfree(cr); if (ksp != NULL) ksid_rele(ksp); } - mutex_exit(&p->p_crlock); - if (error == 0) { if (do_nocd) { mutex_enter(&p->p_lock); @@ -153,9 +167,16 @@ setegid(gid_t gid) newcr = cralloc_ksid(); p = ttoproc(curthread); mutex_enter(&p->p_crlock); - cr = p->p_cred; +retry: + crhold(cr = p->p_cred); + mutex_exit(&p->p_crlock); + if (gid == cr->cr_rgid || gid == cr->cr_gid || gid == cr->cr_sgid || (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) { + mutex_enter(&p->p_crlock); + crfree(cr); + if (cr != p->p_cred) + goto retry; /* * A privileged process that makes itself look like a * set-gid process must be marked to produce no core dump. @@ -167,14 +188,14 @@ setegid(gid_t gid) p->p_cred = newcr; newcr->cr_gid = gid; crsetsid(newcr, ksp, KSID_GROUP); + mutex_exit(&p->p_crlock); } else { crfree(newcr); + crfree(cr); if (ksp != NULL) ksid_rele(ksp); } - mutex_exit(&p->p_crlock); - if (error == 0) { if (do_nocd) { mutex_enter(&p->p_lock); diff --git a/usr/src/uts/common/syscall/groups.c b/usr/src/uts/common/syscall/groups.c index 8273171d0c..3a46812f8a 100644 --- a/usr/src/uts/common/syscall/groups.c +++ b/usr/src/uts/common/syscall/groups.c @@ -89,17 +89,24 @@ setgroups(int gidsetsize, gid_t *gidset) newcr = cralloc_ksid(); p = ttoproc(curthread); mutex_enter(&p->p_crlock); +retry: cr = p->p_cred; + crhold(cr); + mutex_exit(&p->p_crlock); if ((error = secpolicy_allow_setid(cr, -1, B_FALSE)) != 0) { - mutex_exit(&p->p_crlock); if (groups != NULL) kmem_free(groups, n * sizeof (gid_t)); if (ksl != NULL) ksidlist_rele(ksl); crfree(newcr); + crfree(cr); return (set_errno(error)); } + mutex_enter(&p->p_crlock); + crfree(cr); + if (cr != p->p_cred) + goto retry; crdup_to(cr, newcr); crsetsidlist(newcr, ksl); diff --git a/usr/src/uts/common/syscall/ppriv.c b/usr/src/uts/common/syscall/ppriv.c index 11804ffbdd..bbb75b6dd6 100644 --- a/usr/src/uts/common/syscall/ppriv.c +++ b/usr/src/uts/common/syscall/ppriv.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -31,6 +31,7 @@ #include <sys/systm.h> #include <sys/cred_impl.h> #include <sys/errno.h> +#include <sys/klpd.h> #include <sys/proc.h> #include <sys/priv_impl.h> #include <sys/policy.h> @@ -58,7 +59,7 @@ setppriv(priv_op_t op, priv_ptype_t type, priv_set_t *in_pset) priv_set_t pset, *target; cred_t *cr, *pcr; proc_t *p; - boolean_t donocd; + boolean_t donocd = B_FALSE; if (!PRIV_VALIDSET(type) || !PRIV_VALIDOP(op)) return (set_errno(EINVAL)); @@ -70,6 +71,7 @@ setppriv(priv_op_t op, priv_ptype_t type, priv_set_t *in_pset) cr = cralloc(); mutex_enter(&p->p_crlock); +retry: pcr = p->p_cred; if (audit_active) @@ -86,14 +88,26 @@ setppriv(priv_op_t op, priv_ptype_t type, priv_set_t *in_pset) * other sets can but only as long as they remain subsets * of P. Only immediately after exec holds that P <= L. */ - if (((type == PRIV_LIMIT && - !priv_issubset(&pset, &CR_LPRIV(pcr))) || - !priv_issubset(&pset, &CR_OPPRIV(pcr))) && - !priv_issubset(&pset, priv_getset(pcr, type))) { - mutex_exit(&p->p_crlock); + if (type == PRIV_LIMIT && + !priv_issubset(&pset, &CR_LPRIV(pcr))) { crfree(cr); return (set_errno(EPERM)); } + if (!priv_issubset(&pset, &CR_OPPRIV(pcr)) && + !priv_issubset(&pset, priv_getset(pcr, type))) { + mutex_exit(&p->p_crlock); + /* Policy override should not grow beyond L either */ + if (type != PRIV_INHERITABLE || + !priv_issubset(&pset, &CR_LPRIV(pcr)) || + secpolicy_require_privs(CRED(), &pset) != 0) { + crfree(cr); + return (set_errno(EPERM)); + } + mutex_enter(&p->p_crlock); + if (pcr != p->p_cred) + goto retry; + donocd = B_TRUE; + } break; case PRIV_OFF: @@ -157,8 +171,6 @@ setppriv(priv_op_t op, priv_ptype_t type, priv_set_t *in_pset) priv_inverse(&diff); priv_intersect(&CR_OPPRIV(pcr), &diff); donocd = !priv_issubset(&diff, &CR_IPRIV(cr)); - } else { - donocd = B_FALSE; } p->p_cred = cr; @@ -225,7 +237,7 @@ setpflags(uint_t flag, uint_t val, cred_t *tcr) if (val > 1 || (flag != PRIV_DEBUG && flag != PRIV_AWARE && flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT && - flag != __PROC_PROTECT)) { + flag != __PROC_PROTECT && flag != PRIV_XPOLICY)) { return (EINVAL); } @@ -305,6 +317,13 @@ setpflags(uint_t flag, uint_t val, cred_t *tcr) CR_FLAGS(cr) = newflags; } + /* + * Unsetting the flag has as side effect getting rid of + * the per-credential policy. + */ + if (flag == PRIV_XPOLICY && val == 0) + crsetcrklpd(cr, NULL); + if (use_curcred) { p->p_cred = cr; mutex_exit(&p->p_crlock); @@ -321,7 +340,8 @@ uint_t getpflags(uint_t flag, const cred_t *cr) { if (flag != PRIV_DEBUG && flag != PRIV_AWARE && - flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT) + flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT && + flag != PRIV_XPOLICY) return ((uint_t)-1); return ((CR_FLAGS(cr) & flag) != 0); @@ -331,7 +351,8 @@ getpflags(uint_t flag, const cred_t *cr) * Privilege system call entry point */ int -privsys(int code, priv_op_t op, priv_ptype_t type, void *buf, size_t bufsize) +privsys(int code, priv_op_t op, priv_ptype_t type, void *buf, size_t bufsize, + int itype) { int retv; extern int issetugid(void); @@ -355,15 +376,23 @@ privsys(int code, priv_op_t op, priv_ptype_t type, void *buf, size_t bufsize) return (retv == -1 ? set_errno(EINVAL) : retv); case PRIVSYS_ISSETUGID: return (issetugid()); + case PRIVSYS_KLPD_REG: + if (bufsize < sizeof (priv_set_t)) + return (set_errno(ENOMEM)); + return ((int)klpd_reg((int)op, (idtype_t)itype, (id_t)type, + buf)); + case PRIVSYS_KLPD_UNREG: + return ((int)klpd_unreg((int)op, (idtype_t)itype, (id_t)type)); } return (set_errno(EINVAL)); } #ifdef _SYSCALL32_IMPL int -privsys32(int code, priv_op_t op, priv_ptype_t type, caddr32_t *buf, - size32_t bufsize) +privsys32(int code, priv_op_t op, priv_ptype_t type, caddr32_t buf, + size32_t bufsize, int itype) { - return (privsys(code, op, type, (void *)buf, (size_t)bufsize)); + return (privsys(code, op, type, (void *)(uintptr_t)buf, + (size_t)bufsize, itype)); } #endif diff --git a/usr/src/uts/common/syscall/uid.c b/usr/src/uts/common/syscall/uid.c index 9973b17e43..967ebaf462 100644 --- a/usr/src/uts/common/syscall/uid.c +++ b/usr/src/uts/common/syscall/uid.c @@ -68,7 +68,9 @@ setuid(uid_t uid) } /* * Need to pre-allocate the new cred structure before grabbing - * the p_crlock mutex. + * the p_crlock mutex. We can't hold on to the p_crlock for most + * if this though, now that we allow kernel upcalls from the + * policy routines. */ newcr = cralloc_ksid(); @@ -76,16 +78,28 @@ setuid(uid_t uid) retry: mutex_enter(&p->p_crlock); +retry_locked: cr = p->p_cred; + crhold(cr); + mutex_exit(&p->p_crlock); if ((uid == cr->cr_ruid || uid == cr->cr_suid) && secpolicy_allow_setid(cr, uid, B_TRUE) != 0) { + mutex_enter(&p->p_crlock); + crfree(cr); + if (cr != p->p_cred) + goto retry_locked; error = 0; crcopy_to(cr, newcr); p->p_cred = newcr; newcr->cr_uid = uid; crsetsid(newcr, ksp, KSID_USER); + mutex_exit(&p->p_crlock); } else if ((error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) { + mutex_enter(&p->p_crlock); + crfree(cr); + if (cr != p->p_cred) + goto retry_locked; if (!uidchge && uid != cr->cr_ruid) { /* * The ruid of the process is going to change. In order @@ -123,14 +137,14 @@ retry: newcr->cr_uid = uid; crsetsid(newcr, ksp, KSID_USER); ASSERT(uid != oldruid ? uidchge : 1); + mutex_exit(&p->p_crlock); } else { crfree(newcr); + crfree(cr); if (ksp != NULL) ksid_rele(ksp); } - mutex_exit(&p->p_crlock); - /* * We decrement the number of processes associated with the oldruid * to match the increment above, even if the ruid of the process @@ -194,7 +208,9 @@ seteuid(uid_t uid) newcr = cralloc_ksid(); p = ttoproc(curthread); mutex_enter(&p->p_crlock); - cr = p->p_cred; +retry: + crhold(cr = p->p_cred); + mutex_exit(&p->p_crlock); if (uid == cr->cr_ruid || uid == cr->cr_uid || uid == cr->cr_suid || (error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) { @@ -203,6 +219,10 @@ seteuid(uid_t uid) * set-uid process must be marked to produce no core dump, * if the effective uid did changed. */ + mutex_enter(&p->p_crlock); + crfree(cr); + if (cr != p->p_cred) + goto retry; if (cr->cr_uid != uid && error == 0) do_nocd = 1; error = 0; @@ -210,15 +230,7 @@ seteuid(uid_t uid) p->p_cred = newcr; newcr->cr_uid = uid; crsetsid(newcr, ksp, KSID_USER); - } else { - crfree(newcr); - if (ksp != NULL) - ksid_rele(ksp); - } - - mutex_exit(&p->p_crlock); - - if (error == 0) { + mutex_exit(&p->p_crlock); if (do_nocd) { mutex_enter(&p->p_lock); p->p_flag |= SNOCD; @@ -227,6 +239,11 @@ seteuid(uid_t uid) crset(p, newcr); /* broadcast to process threads */ return (0); } + + crfree(newcr); + crfree(cr); + if (ksp != NULL) + ksid_rele(ksp); return (set_errno(error)); } @@ -272,16 +289,30 @@ setreuid(uid_t ruid, uid_t euid) retry: mutex_enter(&p->p_crlock); - cr = p->p_cred; +retry_locked: + crhold(cr = p->p_cred); + mutex_exit(&p->p_crlock); if (ruid != -1 && ruid != cr->cr_ruid && ruid != cr->cr_uid && secpolicy_allow_setid(cr, ruid, B_FALSE) != 0) { + mutex_enter(&p->p_crlock); + crfree(cr); + if (cr != p->p_cred) + goto retry_locked; error = EPERM; } else if (euid != -1 && euid != cr->cr_ruid && euid != cr->cr_uid && euid != cr->cr_suid && secpolicy_allow_setid(cr, euid, B_FALSE)) { + mutex_enter(&p->p_crlock); + crfree(cr); + if (cr != p->p_cred) + goto retry_locked; error = EPERM; } else { + mutex_enter(&p->p_crlock); + crfree(cr); + if (cr != p->p_cred) + goto retry_locked; if (!uidchge && ruid != -1 && cr->cr_ruid != ruid) { /* * The ruid of the process is going to change. In order |
