diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index efd3a4135375..48ab7c0b520b 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -344,12 +344,9 @@ sys_getgroups(struct thread *td, struct getgroups_args *uap) if (error != 0) goto out; - if (ngrp > 1) { - ugidset++; - - error = copyout(cred->cr_groups, ugidset, + if (ngrp > 1) + error = copyout(cred->cr_groups, ugidset + 1, (ngrp - 1) * sizeof(*ugidset)); - } out: td->td_retval[0] = ngrp; return (error); @@ -785,14 +782,11 @@ kern_setcred(struct thread *const td, const u_int flags, /* * Change groups. - * - * crsetgroups_internal() changes both the effective and supplementary - * ones. */ - if (flags & SETCREDF_SUPP_GROUPS) { + if (flags & SETCREDF_SUPP_GROUPS) crsetgroups_internal(new_cred, wcred->sc_supp_groups_nb, groups); - } else if (flags & SETCREDF_GID) + if (flags & SETCREDF_GID) change_egid(new_cred, wcred->sc_gid); if (flags & SETCREDF_RGID) change_rgid(new_cred, wcred->sc_rgid); @@ -1253,9 +1247,14 @@ kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups) return (EINVAL); AUDIT_ARG_GROUPSET(groups, ngrp); + /* + * setgroups(0, NULL) is a legitimate way of clearing the groups vector + * on non-BSD systems (which generally do not have the egid in the + * groups[0]). We risk security holes when running non-BSD software if + * we do not do the same. So we allow and treat 0 for 'ngrp' specially + * below (twice). + */ if (ngrp != 0) { - /* We allow and treat 0 specially below. */ - /* * To maintain userland compat for now, we use the first group * as our egid and we'll use the rest as our supplemental @@ -1269,8 +1268,7 @@ kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups) *ngrpp = ngrp; } newcred = crget(); - if (ngrp != 0) - crextend(newcred, ngrp); + crextend(newcred, ngrp); PROC_LOCK(p); oldcred = crcopysafe(p, newcred); @@ -1291,12 +1289,14 @@ kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups) if (error) goto fail; - if (ngrp == 0) { - newcred->cr_ngroups = 0; - } else { + /* + * If some groups were passed, the first one is currently the desired + * egid. This code is to be removed (along with some commented block + * above) when setgroups() is changed to take only supplementary groups. + */ + if (ngrp != 0) newcred->cr_gid = egid; - crsetgroups_internal(newcred, ngrp, groups); - } + crsetgroups_internal(newcred, ngrp, groups); setsugid(p); proc_set_cred(p, newcred); diff --git a/sys/rpc/svc_auth.c b/sys/rpc/svc_auth.c index 92f1ee0f2844..838fa9ed313a 100644 --- a/sys/rpc/svc_auth.c +++ b/sys/rpc/svc_auth.c @@ -39,6 +39,7 @@ */ #include +#include #include #include #include @@ -191,7 +192,7 @@ svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp) return (FALSE); cr = crget(); cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xprt->xp_uid; - crsetgroups(cr, xprt->xp_ngrps, xprt->xp_gidp); + crsetgroups_fallback(cr, xprt->xp_ngrps, xprt->xp_gidp, GID_NOGROUP); cr->cr_rgid = cr->cr_svgid = cr->cr_gid; cr->cr_prison = curthread->td_ucred->cr_prison; prison_hold(cr->cr_prison); @@ -206,7 +207,7 @@ svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp) return (FALSE); cr = crget(); cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xcr->cr_uid; - crsetgroups(cr, xcr->cr_ngroups, xcr->cr_groups); + crsetgroups_fallback(cr, xcr->cr_ngroups, xcr->cr_groups, GID_NOGROUP); cr->cr_rgid = cr->cr_svgid = cr->cr_gid; cr->cr_prison = curthread->td_ucred->cr_prison; prison_hold(cr->cr_prison);