Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 May 2009 21:41:01 +0000 (UTC)
From:      Brooks Davis <brooks@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r192998 - in projects/ngroups: lib/libkvm sys/compat/linux sys/i386/ibcs2 sys/kern sys/nfsserver sys/sys
Message-ID:  <200905282141.n4SLf1mo050648@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905282141.n4SLf1mo050648>