summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/syscall
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/syscall')
-rw-r--r--usr/src/uts/common/syscall/gid.c33
-rw-r--r--usr/src/uts/common/syscall/groups.c9
-rw-r--r--usr/src/uts/common/syscall/ppriv.c59
-rw-r--r--usr/src/uts/common/syscall/uid.c59
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