From owner-svn-src-projects@FreeBSD.ORG Thu May 28 21:41:02 2009 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 03E591065673; Thu, 28 May 2009 21:41:02 +0000 (UTC) (envelope-from brooks@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id CDBD38FC1F; Thu, 28 May 2009 21:41:01 +0000 (UTC) (envelope-from brooks@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n4SLf1FK050658; Thu, 28 May 2009 21:41:01 GMT (envelope-from brooks@svn.freebsd.org) Received: (from brooks@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n4SLf1mo050648; Thu, 28 May 2009 21:41:01 GMT (envelope-from brooks@svn.freebsd.org) Message-Id: <200905282141.n4SLf1mo050648@svn.freebsd.org> From: Brooks Davis Date: Thu, 28 May 2009 21:41:01 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r192998 - in projects/ngroups: lib/libkvm sys/compat/linux sys/i386/ibcs2 sys/kern sys/nfsserver sys/sys X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 May 2009 21:41:02 -0000 Author: brooks Date: Thu May 28 21:41:01 2009 New Revision: 192998 URL: http://svn.freebsd.org/changeset/base/192998 Log: More work toward increasing NGROUPS_MAX and/or allowing kern.ngroups to be increased at boot time. * Replace the embedded cr_groups[NGROUPS] member of struct cred with a pointer to malloc'd storage and a cr_agroups value which tracks the number of allocated group slots. When more space is required crextend() is used to add more space. The new crcopysafe() function calls crextend as needed when saving a copy of a credential from a process before modification. * Introduce a new #define, XU_NGROUPS which is always 16 and is used to set the array size in struct xucred and will be used other places where the 16 group limit needs to be preserved. * Replace the embedded ki_groups[KI_NGROUPS] entry in struct kinfo_proc with a pointer and adapt libkvm accordingly. Submitted by: Isilon Systems (Matthew Fleming) Modified: projects/ngroups/lib/libkvm/kvm_proc.c projects/ngroups/sys/compat/linux/linux_misc.c projects/ngroups/sys/compat/linux/linux_uid16.c projects/ngroups/sys/i386/ibcs2/ibcs2_misc.c projects/ngroups/sys/kern/kern_exec.c projects/ngroups/sys/kern/kern_proc.c projects/ngroups/sys/kern/kern_prot.c projects/ngroups/sys/nfsserver/nfs_srvsock.c projects/ngroups/sys/sys/ucred.h projects/ngroups/sys/sys/user.h Modified: projects/ngroups/lib/libkvm/kvm_proc.c ============================================================================== --- projects/ngroups/lib/libkvm/kvm_proc.c Thu May 28 21:37:40 2009 (r192997) +++ projects/ngroups/lib/libkvm/kvm_proc.c Thu May 28 21:41:01 2009 (r192998) @@ -146,9 +146,7 @@ kvm_proclist(kd, what, arg, p, bp, maxcn kp->ki_rgid = ucred.cr_rgid; kp->ki_svgid = ucred.cr_svgid; kp->ki_ngroups = ucred.cr_ngroups; - bcopy(ucred.cr_groups, kp->ki_groups, - (NGROUPS < KI_NGROUPS ? NGROUPS : KI_NGROUPS) * - sizeof(gid_t)); + kp->ki_groups = ucred.cr_groups; kp->ki_uid = ucred.cr_uid; if (ucred.cr_prison != NULL) { if (KREAD(kd, (u_long)ucred.cr_prison, &pr)) { Modified: projects/ngroups/sys/compat/linux/linux_misc.c ============================================================================== --- projects/ngroups/sys/compat/linux/linux_misc.c Thu May 28 21:37:40 2009 (r192997) +++ projects/ngroups/sys/compat/linux/linux_misc.c Thu May 28 21:41:01 2009 (r192998) @@ -1124,7 +1124,7 @@ int linux_setgroups(struct thread *td, struct linux_setgroups_args *args) { struct ucred *newcred, *oldcred; - l_gid_t linux_gidset[NGROUPS]; + l_gid_t *linux_gidset; gid_t *bsd_gidset; int ngrp, error; struct proc *p; @@ -1132,13 +1132,14 @@ linux_setgroups(struct thread *td, struc ngrp = args->gidsetsize; if (ngrp < 0 || ngrp >= NGROUPS) return (EINVAL); + linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK); error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t)); if (error) - return (error); + goto out; newcred = crget(); p = td->td_proc; PROC_LOCK(p); - oldcred = p->p_ucred; + oldcred = crcopysafe(p, newcred); /* * cr_groups[0] holds egid. Setting the whole set from @@ -1149,10 +1150,9 @@ linux_setgroups(struct thread *td, struc if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0) { PROC_UNLOCK(p); crfree(newcred); - return (error); + goto out; } - crcopy(newcred, oldcred); if (ngrp > 0) { newcred->cr_ngroups = ngrp + 1; @@ -1169,14 +1169,17 @@ linux_setgroups(struct thread *td, struc p->p_ucred = newcred; PROC_UNLOCK(p); crfree(oldcred); - return (0); + error = 0; +out: + free(linux_gidset, M_TEMP); + return (error); } int linux_getgroups(struct thread *td, struct linux_getgroups_args *args) { struct ucred *cred; - l_gid_t linux_gidset[NGROUPS]; + l_gid_t *linux_gidset; gid_t *bsd_gidset; int bsd_gidsetsz, ngrp, error; @@ -1199,13 +1202,16 @@ linux_getgroups(struct thread *td, struc return (EINVAL); ngrp = 0; + linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), + M_TEMP, M_WAITOK); while (ngrp < bsd_gidsetsz) { linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; ngrp++; } - if ((error = copyout(linux_gidset, args->grouplist, - ngrp * sizeof(l_gid_t)))) + error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t)); + free(linux_gidset, M_TEMP); + if (error) return (error); td->td_retval[0] = ngrp; Modified: projects/ngroups/sys/compat/linux/linux_uid16.c ============================================================================== --- projects/ngroups/sys/compat/linux/linux_uid16.c Thu May 28 21:37:40 2009 (r192997) +++ projects/ngroups/sys/compat/linux/linux_uid16.c Thu May 28 21:41:01 2009 (r192998) @@ -98,7 +98,7 @@ int linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args) { struct ucred *newcred, *oldcred; - l_gid16_t linux_gidset[NGROUPS]; + l_gid16_t *linux_gidset; gid_t *bsd_gidset; int ngrp, error; struct proc *p; @@ -111,13 +111,14 @@ linux_setgroups16(struct thread *td, str ngrp = args->gidsetsize; if (ngrp < 0 || ngrp >= NGROUPS) return (EINVAL); + linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK); error = copyin(args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t)); if (error) return (error); newcred = crget(); p = td->td_proc; PROC_LOCK(p); - oldcred = p->p_ucred; + oldcred = crcopysafe(p, newcred); /* * cr_groups[0] holds egid. Setting the whole set from @@ -128,10 +129,9 @@ linux_setgroups16(struct thread *td, str if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0) { PROC_UNLOCK(p); crfree(newcred); - return (error); + goto out; } - crcopy(newcred, oldcred); if (ngrp > 0) { newcred->cr_ngroups = ngrp + 1; @@ -149,14 +149,17 @@ linux_setgroups16(struct thread *td, str p->p_ucred = newcred; PROC_UNLOCK(p); crfree(oldcred); - return (0); + error = 0; +out: + free(linux_gidset, M_TEMP); + return (error); } int linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args) { struct ucred *cred; - l_gid16_t linux_gidset[NGROUPS]; + l_gid16_t *linux_gidset; gid_t *bsd_gidset; int bsd_gidsetsz, ngrp, error; @@ -184,12 +187,15 @@ linux_getgroups16(struct thread *td, str return (EINVAL); ngrp = 0; + linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), + M_TEMP, M_WAITOK); while (ngrp < bsd_gidsetsz) { linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; ngrp++; } error = copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t)); + free(linux_gidset, M_TEMP); if (error) return (error); Modified: projects/ngroups/sys/i386/ibcs2/ibcs2_misc.c ============================================================================== --- projects/ngroups/sys/i386/ibcs2/ibcs2_misc.c Thu May 28 21:37:40 2009 (r192997) +++ projects/ngroups/sys/i386/ibcs2/ibcs2_misc.c Thu May 28 21:41:01 2009 (r192998) @@ -659,24 +659,29 @@ ibcs2_getgroups(td, uap) struct thread *td; struct ibcs2_getgroups_args *uap; { - ibcs2_gid_t iset[NGROUPS_MAX]; - gid_t gp[NGROUPS_MAX]; + ibcs2_gid_t *iset; + gid_t *gp; u_int i, ngrp; int error; if (uap->gidsetsize < 0) return (EINVAL); ngrp = MIN(uap->gidsetsize, NGROUPS_MAX); + gp = malloc(ngrp * sizeof(*gp), M_TEMP, M_WAITOK); error = kern_getgroups(td, &ngrp, gp); if (error) - return (error); + goto out; if (uap->gidsetsize > 0) { + iset = malloc(ngrp * sizeof(*iset), M_TEMP, M_WAITOK); for (i = 0; i < ngrp; i++) iset[i] = (ibcs2_gid_t)gp[i]; error = copyout(iset, uap->gidset, ngrp * sizeof(ibcs2_gid_t)); + free(iset, M_TEMP); } if (error == 0) td->td_retval[0] = ngrp; +out: + free(gp, M_TEMP); return (error); } @@ -685,21 +690,31 @@ ibcs2_setgroups(td, uap) struct thread *td; struct ibcs2_setgroups_args *uap; { - ibcs2_gid_t iset[NGROUPS_MAX]; - gid_t gp[NGROUPS_MAX]; + ibcs2_gid_t *iset; + gid_t *gp; int error, i; if (uap->gidsetsize < 0 || uap->gidsetsize > NGROUPS_MAX) return (EINVAL); - if (uap->gidsetsize && uap->gidset) { + if (uap->gidsetsize && uap->gidset == NULL) + return (EINVAL); + gp = malloc(uap->gidsetsize * sizeof(*gp), M_TEMP, M_WAITOK); + if (uap->gidsetsize) { + iset = malloc(uap->gidsetsize * sizeof(*iset), M_TEMP, M_WAITOK); error = copyin(uap->gidset, iset, sizeof(ibcs2_gid_t) * uap->gidsetsize); - if (error) - return (error); + if (error) { + free(iset, M_TEMP); + goto out; + } for (i = 0; i < uap->gidsetsize; i++) gp[i] = (gid_t)iset[i]; } - return (kern_setgroups(td, uap->gidsetsize, gp)); + + error = kern_setgroups(td, uap->gidsetsize, gp); +out: + free(gp, M_TEMP); + return (error); } int Modified: projects/ngroups/sys/kern/kern_exec.c ============================================================================== --- projects/ngroups/sys/kern/kern_exec.c Thu May 28 21:37:40 2009 (r192997) +++ projects/ngroups/sys/kern/kern_exec.c Thu May 28 21:41:01 2009 (r192998) @@ -580,6 +580,7 @@ interpret: * reset. */ PROC_LOCK(p); + oldcred = crcopysafe(p, newcred); if (sigacts_shared(p->p_sigacts)) { oldsigacts = p->p_sigacts; PROC_UNLOCK(p); @@ -630,7 +631,6 @@ interpret: * XXXMAC: For the time being, use NOSUID to also prohibit * transitions on the file system. */ - oldcred = p->p_ucred; credential_changing = 0; credential_changing |= (attr.va_mode & S_ISUID) && oldcred->cr_uid != attr.va_uid; @@ -684,7 +684,6 @@ interpret: /* * Set the new credentials. */ - crcopy(newcred, oldcred); if (attr.va_mode & S_ISUID) change_euid(newcred, euip); if (attr.va_mode & S_ISGID) @@ -724,7 +723,6 @@ interpret: */ if (oldcred->cr_svuid != oldcred->cr_uid || oldcred->cr_svgid != oldcred->cr_gid) { - crcopy(newcred, oldcred); change_svuid(newcred, newcred->cr_uid); change_svgid(newcred, newcred->cr_gid); p->p_ucred = newcred; Modified: projects/ngroups/sys/kern/kern_proc.c ============================================================================== --- projects/ngroups/sys/kern/kern_proc.c Thu May 28 21:37:40 2009 (r192997) +++ projects/ngroups/sys/kern/kern_proc.c Thu May 28 21:41:01 2009 (r192998) @@ -730,10 +730,8 @@ fill_kinfo_proc_only(struct proc *p, str kp->ki_uid = cred->cr_uid; kp->ki_ruid = cred->cr_ruid; kp->ki_svuid = cred->cr_svuid; - /* XXX bde doesn't like KI_NGROUPS */ - kp->ki_ngroups = min(cred->cr_ngroups, KI_NGROUPS); - bcopy(cred->cr_groups, kp->ki_groups, - kp->ki_ngroups * sizeof(gid_t)); + kp->ki_ngroups = cred->cr_ngroups; + kp->ki_groups = cred->cr_groups; kp->ki_rgid = cred->cr_rgid; kp->ki_svgid = cred->cr_svgid; /* If jailed(cred), emulate the old P_JAILED flag. */ Modified: projects/ngroups/sys/kern/kern_prot.c ============================================================================== --- projects/ngroups/sys/kern/kern_prot.c Thu May 28 21:37:40 2009 (r192997) +++ projects/ngroups/sys/kern/kern_prot.c Thu May 28 21:41:01 2009 (r192998) @@ -276,18 +276,21 @@ struct getgroups_args { int getgroups(struct thread *td, register struct getgroups_args *uap) { - gid_t groups[NGROUPS]; + gid_t *groups; u_int ngrp; int error; ngrp = MIN(uap->gidsetsize, NGROUPS); + groups = malloc(ngrp * sizeof(*groups), M_TEMP, M_WAITOK); error = kern_getgroups(td, &ngrp, groups); if (error) - return (error); + goto out; if (uap->gidsetsize > 0) error = copyout(groups, uap->gidset, ngrp * sizeof(gid_t)); if (error == 0) td->td_retval[0] = ngrp; +out: + free(groups, M_TEMP); return (error); } @@ -486,7 +489,10 @@ setuid(struct thread *td, struct setuid_ newcred = crget(); uip = uifind(uid); PROC_LOCK(p); - oldcred = p->p_ucred; + /* + * Copy credentials so other references do not see our changes. + */ + oldcred = crcopysafe(p, newcred); #ifdef MAC error = mac_cred_check_setuid(oldcred, uid); @@ -521,10 +527,6 @@ setuid(struct thread *td, struct setuid_ (error = priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)) != 0) goto fail; - /* - * Copy credentials so other references do not see our changes. - */ - crcopy(newcred, oldcred); #ifdef _POSIX_SAVED_IDS /* * Do we have "appropriate privileges" (are we root or uid == euid) @@ -598,7 +600,10 @@ seteuid(struct thread *td, struct seteui newcred = crget(); euip = uifind(euid); PROC_LOCK(p); - oldcred = p->p_ucred; + /* + * Copy credentials so other references do not see our changes. + */ + oldcred = crcopysafe(p, newcred); #ifdef MAC error = mac_cred_check_seteuid(oldcred, euid); @@ -612,8 +617,7 @@ seteuid(struct thread *td, struct seteui goto fail; /* - * Everything's okay, do it. Copy credentials so other references do - * not see our changes. + * Everything's okay, do it. */ crcopy(newcred, oldcred); if (oldcred->cr_uid != euid) { @@ -651,7 +655,7 @@ setgid(struct thread *td, struct setgid_ AUDIT_ARG(gid, gid); newcred = crget(); PROC_LOCK(p); - oldcred = p->p_ucred; + oldcred = crcopysafe(p, newcred); #ifdef MAC error = mac_cred_check_setgid(oldcred, gid); @@ -680,7 +684,6 @@ setgid(struct thread *td, struct setgid_ (error = priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) != 0) goto fail; - crcopy(newcred, oldcred); #ifdef _POSIX_SAVED_IDS /* * Do we have "appropriate privileges" (are we root or gid == egid) @@ -750,7 +753,7 @@ setegid(struct thread *td, struct setegi AUDIT_ARG(egid, egid); newcred = crget(); PROC_LOCK(p); - oldcred = p->p_ucred; + oldcred = crcopysafe(p, newcred); #ifdef MAC error = mac_cred_check_setegid(oldcred, egid); @@ -763,7 +766,6 @@ setegid(struct thread *td, struct setegi (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) != 0) goto fail; - crcopy(newcred, oldcred); if (oldcred->cr_groups[0] != egid) { change_egid(newcred, egid); setsugid(p); @@ -789,15 +791,19 @@ struct setgroups_args { int setgroups(struct thread *td, struct setgroups_args *uap) { - gid_t groups[NGROUPS]; + gid_t *groups = NULL; int error; if (uap->gidsetsize > NGROUPS) return (EINVAL); + groups = malloc(uap->gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK); error = copyin(uap->gidset, groups, uap->gidsetsize * sizeof(gid_t)); if (error) - return (error); - return (kern_setgroups(td, uap->gidsetsize, groups)); + goto out; + error = kern_setgroups(td, uap->gidsetsize, groups); +out: + free(groups, M_TEMP); + return (error); } int @@ -811,8 +817,9 @@ kern_setgroups(struct thread *td, u_int return (EINVAL); AUDIT_ARG(groupset, groups, ngrp); newcred = crget(); + crextend(newcred, ngrp); PROC_LOCK(p); - oldcred = p->p_ucred; + oldcred = crcopysafe(p, newcred); #ifdef MAC error = mac_cred_check_setgroups(oldcred, ngrp, groups); @@ -824,11 +831,6 @@ kern_setgroups(struct thread *td, u_int if (error) goto fail; - /* - * XXX A little bit lazy here. We could test if anything has - * changed before crcopy() and setting P_SUGID. - */ - crcopy(newcred, oldcred); if (ngrp < 1) { /* * setgroups(0, NULL) is a legitimate way of clearing the @@ -877,7 +879,7 @@ setreuid(register struct thread *td, str euip = uifind(euid); ruip = uifind(ruid); PROC_LOCK(p); - oldcred = p->p_ucred; + oldcred = crcopysafe(p, newcred); #ifdef MAC error = mac_cred_check_setreuid(oldcred, ruid, euid); @@ -892,7 +894,6 @@ setreuid(register struct thread *td, str (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID, 0)) != 0) goto fail; - crcopy(newcred, oldcred); if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { change_euid(newcred, euip); setsugid(p); @@ -942,7 +943,7 @@ setregid(register struct thread *td, str AUDIT_ARG(rgid, rgid); newcred = crget(); PROC_LOCK(p); - oldcred = p->p_ucred; + oldcred = crcopysafe(p, newcred); #ifdef MAC error = mac_cred_check_setregid(oldcred, rgid, egid); @@ -957,7 +958,6 @@ setregid(register struct thread *td, str (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) != 0) goto fail; - crcopy(newcred, oldcred); if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { change_egid(newcred, egid); setsugid(p); @@ -1013,7 +1013,7 @@ setresuid(register struct thread *td, st euip = uifind(euid); ruip = uifind(ruid); PROC_LOCK(p); - oldcred = p->p_ucred; + oldcred = crcopysafe(p, newcred); #ifdef MAC error = mac_cred_check_setresuid(oldcred, ruid, euid, suid); @@ -1033,7 +1033,6 @@ setresuid(register struct thread *td, st (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID, 0)) != 0) goto fail; - crcopy(newcred, oldcred); if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { change_euid(newcred, euip); setsugid(p); @@ -1090,7 +1089,7 @@ setresgid(register struct thread *td, st AUDIT_ARG(sgid, sgid); newcred = crget(); PROC_LOCK(p); - oldcred = p->p_ucred; + oldcred = crcopysafe(p, newcred); #ifdef MAC error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid); @@ -1110,7 +1109,6 @@ setresgid(register struct thread *td, st (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) != 0) goto fail; - crcopy(newcred, oldcred); if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { change_egid(newcred, egid); setsugid(p); @@ -1786,6 +1784,7 @@ crget(void) #ifdef MAC mac_cred_init(cr); #endif + crextend(cr, XU_NGROUPS); return (cr); } @@ -1830,6 +1829,7 @@ crfree(struct ucred *cr) #ifdef MAC mac_cred_destroy(cr); #endif + free(cr->cr_groups, M_CRED); free(cr, M_CRED); } } @@ -1855,6 +1855,9 @@ crcopy(struct ucred *dest, struct ucred bcopy(&src->cr_startcopy, &dest->cr_startcopy, (unsigned)((caddr_t)&src->cr_endcopy - (caddr_t)&src->cr_startcopy)); + crextend(dest, src->cr_agroups); + memcpy(dest->cr_groups, src->cr_groups, + src->cr_ngroups * sizeof(gid_t)); uihold(dest->cr_uidinfo); uihold(dest->cr_ruidinfo); if (jailed(dest)) @@ -1886,12 +1889,16 @@ crdup(struct ucred *cr) void cru2x(struct ucred *cr, struct xucred *xcr) { + int ngroups; bzero(xcr, sizeof(*xcr)); xcr->cr_version = XUCRED_VERSION; xcr->cr_uid = cr->cr_uid; - xcr->cr_ngroups = cr->cr_ngroups; - bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups)); + + ngroups = min(cr->cr_ngroups, XU_NGROUPS); + xcr->cr_ngroups = ngroups; + bcopy(cr->cr_groups, xcr->cr_groups, + ngroups * sizeof(cr->cr_groups[0])); } /* @@ -1913,6 +1920,59 @@ cred_update_thread(struct thread *td) crfree(cred); } +struct ucred * +crcopysafe(struct proc *p, struct ucred *cr) +{ + struct ucred *oldcred; + int groups; + + PROC_LOCK_ASSERT(p, MA_OWNED); + + oldcred = p->p_ucred; + while (cr->cr_agroups < oldcred->cr_agroups) { + groups = oldcred->cr_agroups; + PROC_UNLOCK(p); + crextend(cr, groups); + PROC_LOCK(p); + oldcred = p->p_ucred; + } + crcopy(cr, oldcred); + + return (oldcred); +} + +/* + * Extend the passed in credential to hold n items. + */ +void +crextend(struct ucred *cr, int n) +{ + int cnt; + + /* Truncate? */ + if (n <= cr->cr_agroups) + return; + + /* + * We extend by 2 each time since we're using a power of two + * allocator. + */ + if (cr->cr_agroups) + cnt = cr->cr_agroups * 2; + else + cnt = MINALLOCSIZE / sizeof(gid_t); + + while (cnt < n) + cnt *= 2; + + /* Free the old array. */ + if (cr->cr_groups) + free(cr->cr_groups, M_CRED); + + cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO); + cr->cr_agroups = cnt; +} + /* * Get login name, if available. */ Modified: projects/ngroups/sys/nfsserver/nfs_srvsock.c ============================================================================== --- projects/ngroups/sys/nfsserver/nfs_srvsock.c Thu May 28 21:37:40 2009 (r192997) +++ projects/ngroups/sys/nfsserver/nfs_srvsock.c Thu May 28 21:41:01 2009 (r192998) @@ -371,11 +371,11 @@ nfs_getreq(struct nfsrv_descript *nd, st } tl = nfsm_dissect_nonblock(u_int32_t *, (len + 2) * NFSX_UNSIGNED); for (i = 1; i <= len; i++) - if (i < NGROUPS) + if (i < XU_NGROUPS) nd->nd_cr->cr_groups[i] = fxdr_unsigned(gid_t, *tl++); else tl++; - nd->nd_cr->cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1); + nd->nd_cr->cr_ngroups = (len >= XU_NGROUPS) ? XU_NGROUPS : (len + 1); if (nd->nd_cr->cr_ngroups > 1) nfsrvw_sort(nd->nd_cr->cr_groups, nd->nd_cr->cr_ngroups); len = fxdr_unsigned(int, *++tl); Modified: projects/ngroups/sys/sys/ucred.h ============================================================================== --- projects/ngroups/sys/sys/ucred.h Thu May 28 21:37:40 2009 (r192997) +++ projects/ngroups/sys/sys/ucred.h Thu May 28 21:41:01 2009 (r192998) @@ -49,7 +49,6 @@ struct ucred { uid_t cr_ruid; /* real user id */ uid_t cr_svuid; /* saved user id */ short cr_ngroups; /* number of groups */ - gid_t cr_groups[NGROUPS]; /* groups */ gid_t cr_rgid; /* real group id */ gid_t cr_svgid; /* saved group id */ struct uidinfo *cr_uidinfo; /* per euid resource consumption */ @@ -60,11 +59,15 @@ struct ucred { #define cr_endcopy cr_label struct label *cr_label; /* MAC label */ struct auditinfo_addr cr_audit; /* Audit properties. */ + gid_t *cr_groups; /* groups */ + short cr_agroups; /* Available groups */ }; #define NOCRED ((struct ucred *)0) /* no credential available */ #define FSCRED ((struct ucred *)-1) /* filesystem credential */ #endif /* _KERNEL || _WANT_UCRED */ +#define XU_NGROUPS 16 + /* * This is the external representation of struct ucred. */ @@ -72,7 +75,7 @@ struct xucred { u_int cr_version; /* structure layout version */ uid_t cr_uid; /* effective user id */ short cr_ngroups; /* number of groups */ - gid_t cr_groups[NGROUPS]; /* groups */ + gid_t cr_groups[XU_NGROUPS]; /* groups */ void *_cr_unused1; /* compatibility with old ucred */ }; #define XUCRED_VERSION 0 @@ -81,6 +84,7 @@ struct xucred { #define cr_gid cr_groups[0] #ifdef _KERNEL +struct proc; struct thread; void change_egid(struct ucred *newcred, gid_t egid); @@ -90,6 +94,7 @@ void change_ruid(struct ucred *newcred, void change_svgid(struct ucred *newcred, gid_t svgid); void change_svuid(struct ucred *newcred, uid_t svuid); void crcopy(struct ucred *dest, struct ucred *src); +struct ucred *crcopysafe(struct proc *, struct ucred *); struct ucred *crdup(struct ucred *cr); void cred_update_thread(struct thread *td); void crfree(struct ucred *cr); @@ -97,6 +102,7 @@ struct ucred *crget(void); struct ucred *crhold(struct ucred *cr); int crshared(struct ucred *cr); void cru2x(struct ucred *cr, struct xucred *xcr); +void crextend(struct ucred *cr, int n); int groupmember(gid_t gid, struct ucred *cred); #endif /* _KERNEL */ Modified: projects/ngroups/sys/sys/user.h ============================================================================== --- projects/ngroups/sys/sys/user.h Thu May 28 21:37:40 2009 (r192997) +++ projects/ngroups/sys/sys/user.h Thu May 28 21:41:01 2009 (r192998) @@ -85,7 +85,7 @@ */ #define KI_NSPARE_INT 10 #define KI_NSPARE_LONG 12 -#define KI_NSPARE_PTR 7 +#define KI_NSPARE_PTR 6 #ifdef __amd64__ #define KINFO_PROC_SIZE 1088 @@ -117,7 +117,6 @@ #define OCOMMLEN 16 /* size of returned thread name */ #define COMMLEN 19 /* size of returned ki_comm name */ #define KI_EMULNAMELEN 16 /* size of returned ki_emul */ -#define KI_NGROUPS 16 /* number of groups in ki_groups */ #define LOGNAMELEN 17 /* size of returned ki_login */ struct kinfo_proc { @@ -151,7 +150,7 @@ struct kinfo_proc { gid_t ki_svgid; /* Saved effective group id */ short ki_ngroups; /* number of groups */ short ki_spare_short2; /* unused (just here for alignment) */ - gid_t ki_groups[KI_NGROUPS]; /* groups */ + uint32_t __was_ki_groups[16]; /* unused; left for bin compat */ vm_size_t ki_size; /* virtual size */ segsz_t ki_rssize; /* current resident set size in pages */ segsz_t ki_swrss; /* resident set size before last swap */ @@ -200,6 +199,7 @@ struct kinfo_proc { struct pcb *ki_pcb; /* kernel virtual addr of pcb */ void *ki_kstack; /* kernel virtual addr of stack */ void *ki_udata; /* User convenience pointer */ + gid_t *ki_groups; /* groups */ /* * When adding new variables, take space for pointers from the * front of ki_spareptrs, and longs from the end of ki_sparelongs.