Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 17 Jun 2009 19:05:31 -0500
From:      Brooks Davis <brooks@freebsd.org>
To:        freebsd-hackers@freebsd.org, freebsd-current@freebsd.org
Subject:   Re: CFT: final patches for NGROUPS>>16
Message-ID:  <20090618000531.GA46033@lor.one-eyed-alien.net>
In-Reply-To: <20090618000407.GA43514@lor.one-eyed-alien.net>
References:  <20090618000407.GA43514@lor.one-eyed-alien.net>

next in thread | previous in thread | raw e-mail | index | archive | help

--O5XBE6gyVG5Rl6Rj
Content-Type: multipart/mixed; boundary="YZ5djTAD1cGYuMQK"
Content-Disposition: inline


--YZ5djTAD1cGYuMQK
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

As usual, I forgot the attachments.  Here they are.

-- Brooks

On Wed, Jun 17, 2009 at 07:04:07PM -0500, Brooks Davis wrote:
> Please find attached three patches which result in raising NGROUPS to
> 1024, making programs in the base system immune to changing values of
> NGROUPS, and pave the way for NGROUPS to be boot time configurable.
>=20
> The first two patches (ngroups-catman.diff and ngroups-posix.diff)
> are userland cleanups.  The third (ngroups-main.diff) is the core of
> the change and primairly in the kernel.  It is strongly based on work
> contributed by Isilon Systems.  The proposed commit messages appear to
> the bottom of this message.
>=20
> I've been running the basic code on my FreeBSD laptop for a while and
> I've tested basic NFS mounts, but more areas need testing before this
> hits a release.  Key things to hit include:
>  - NFS mount and export
>  - IPFW uid, gid, and jail rules
>  - portalfs (ideally portalfs should be extended to not truncate groups)
>=20
> In practice, expect appliations to not care about this change unless
> they are run with more than 16 groups.  If that happens, calls to
> getgroups() will fail if they use statically sized buffers recompilation
> should fix them.
>=20
> Please test, review, etc.  I'd like to get this in before code freeze if
> at all possible.
>=20
> -- Brooks
>=20
> ngroups-catman.diff:
>=20
>   When checking if we can write to a file, use access() instead of a
>   manual permission check based on stat output.  Also, get rid of the
>   executability check since it is not used.
>=20
>   MFC after:	2 weeks
>=20
> ngroups-posix.diff
>=20
>   In preparation for raising NGROUPS and NGROUPS_MAX, change base
>   system callers of getgroups(), getgrouplist(), and setgroups() to
>   allocate buffers dynamically.  Specifically, allocate a buffer of size
>   sysconf(_SC_NGROUPS_MAX)+1 (+2 in a few cases to allow for overflow).
>=20
>   This (or similar gymnastics) is required for the code to actually follow
>   the POSIX.1-2008 specification where {NGROUPS_MAX} may differ at runtime
>   and where getgroups may return {NGROUPS_MAX}+1 results on systems like
>   FreeBSD which include the primary group.
>=20
>   In id(1), don't pointlessly add the primary group to the list of all
>   groups, it is always the first result from getgroups().  In principle
>   the old code was more portable, but this was only done in one of the two
>   places where getgroups() was called to the overall effect was pointless.
>=20
>   Document the actual POSIX requirements in the getgroups(2) and
>   setgroups(2) manpages.  We do not yet support a dynamic NGROUPS, but we
>   may in the future.
>=20
>   MFC after:	2 weeks
>=20
> ngroups-main.diff:
>=20
>   Rework the credential code to support larger values of NGROUPS and
>   NGROUPS_MAX, eliminate ABI dependencies on them, and raise the to 1024
>   and 1023 respectively.  (Previously they were equal, but under a close
>   reading of POSIX, NGROUPS_MAX was defined to be too large by 1 since it
>   is the number of supplemental groups, not total number of groups.)
>=20
>   The bulk of the change consists of converting the struct ucred member
>   cr_groups from a static array to a pointer.  Do the equivalent in
>   kinfo_proc.
>=20
>   Introduce new interfaces crcopysafe() and crsetgroups() for duplicating
>   a process credential before modifying it and for setting group lists
>   respectively.  Both interfaces take care for the details of allocating
>   groups array. crsetgroups() takes care of truncating the group list
>   to the current maximum (NGROUPS) if necessary.  In the future,
>   crsetgroups() may be responsible for insuring invariants such as sorting
>   the supplemental groups to allow groupmember() to be implemented as a
>   binary search.
>=20
>   Because we can not change struct xucred without breaking application
>   ABIs, we leave it alone and introduce a new XU_NGROUPS value which is
>   always 16 and is to be used or NGRPS as appropriate for things such as
>   NFS which need to use no more than 16 groups.  When feasible, truncate
>   the group list rather than generating an error.
>=20
>   Minor changes:
>     - Reduce the number of hand rolled versions of groupmember().
>     - Do not assign to both cr_gid and cr_groups[0].
>     - Modify ipfw to cache ucreds instead of part of their contents since
>       they are immutable once referenced by more than one entity.
>=20
>   Submitted by:	Isilon Systems
>   X-MFC after:	never



--YZ5djTAD1cGYuMQK
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="ngroups-catman.diff"
Content-Transfer-Encoding: quoted-printable

diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.bin/catman/catman.c ./usr.bin/c=
atman/catman.c
--- /usr/fsvn/head/usr.bin/catman/catman.c	2009-01-22 10:04:12.000000000 -0=
600
+++ ./usr.bin/catman/catman.c	2009-05-08 15:47:47.000000000 -0500
@@ -57,7 +57,6 @@
 #define TEST_FILE	0x04
 #define TEST_READABLE	0x08
 #define TEST_WRITABLE	0x10
-#define TEST_EXECUTABLE	0x20
=20
 static int verbose;		/* -v flag: be verbose with warnings */
 static int pretend;		/* -n, -p flags: print out what would be done
@@ -92,9 +91,6 @@
 #define	GZCAT_CMD	"z"
 enum Ziptype {NONE, BZIP, GZIP};
=20
-static uid_t uid;
-static gid_t gids[NGROUPS_MAX];
-static int ngids;
 static int starting_dir;
 static char tmp_file[MAXPATHLEN];
 struct stat test_st;
@@ -320,23 +316,10 @@
 		result |=3D TEST_DIR;
 	else if (S_ISREG(test_st.st_mode))
 		result |=3D TEST_FILE;
-	if (test_st.st_uid =3D=3D uid) {
-		test_st.st_mode >>=3D 6;
-	} else {
-		int i;
-		for (i =3D 0; i < ngids; i++) {
-			if (test_st.st_gid =3D=3D gids[i]) {
-				test_st.st_mode >>=3D 3;
-				break;
-			}
-		}
-	}
-	if (test_st.st_mode & S_IROTH)
+	if (access(name, R_OK))
 		result |=3D TEST_READABLE;
-	if (test_st.st_mode & S_IWOTH)
+	if (access(name, W_OK))
 		result |=3D TEST_WRITABLE;
-	if (test_st.st_mode & S_IXOTH)
-		result |=3D TEST_EXECUTABLE;
 	return result;
 }
=20
@@ -759,14 +742,6 @@
 {
 	int opt;
=20
-	if ((uid =3D getuid()) =3D=3D 0) {
-		fprintf(stderr, "don't run %s as root, use:\n   echo", argv[0]);
-		for (optind =3D 0; optind < argc; optind++) {
-			fprintf(stderr, " %s", argv[optind]);
-		}
-		fprintf(stderr, " | nice -5 su -m man\n");
-		exit(1);
-	}
 	while ((opt =3D getopt(argc, argv, "vnfLrh")) !=3D -1) {
 		switch (opt) {
 		case 'f':
@@ -789,7 +764,6 @@
 			/* NOTREACHED */
 		}
 	}
-	ngids =3D getgroups(NGROUPS_MAX, gids);
 	if ((starting_dir =3D open(".", 0)) < 0) {
 		err(1, ".");
 	}

--YZ5djTAD1cGYuMQK
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="ngroups-posix.diff"
Content-Transfer-Encoding: quoted-printable

diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/lib/libc/gen/initgroups.3 ./lib/lib=
c/gen/initgroups.3
--- /usr/fsvn/head/lib/libc/gen/initgroups.3	2009-01-22 10:05:45.000000000 =
-0600
+++ ./lib/libc/gen/initgroups.3	2009-06-09 09:17:36.000000000 -0500
@@ -65,6 +65,13 @@
 .Va errno
 for any of the errors specified for the library function
 .Xr setgroups 2 .
+It may also return:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+The
+.Fn initgroups
+function was unable to allocate temporary storage.
+.El
 .Sh SEE ALSO
 .Xr setgroups 2 ,
 .Xr getgrouplist 3
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/lib/libc/gen/initgroups.c ./lib/lib=
c/gen/initgroups.c
--- /usr/fsvn/head/lib/libc/gen/initgroups.c	2009-01-22 10:05:45.000000000 =
-0600
+++ ./lib/libc/gen/initgroups.c	2009-06-17 14:00:59.000000000 -0500
@@ -35,10 +35,12 @@
=20
 #include <sys/param.h>
=20
-#include <stdio.h>
 #include "namespace.h"
 #include <err.h>
 #include "un-namespace.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
=20
 int
@@ -46,14 +48,21 @@
 	const char *uname;
 	gid_t agroup;
 {
-	int ngroups;
+	int ngroups, ret;
+	long ngroups_max;
+	gid_t *groups;
+
 	/*
-	 * Provide space for one group more than NGROUPS to allow
+	 * Provide space for one group more than possible to allow
 	 * setgroups to fail and set errno.
 	 */
-	gid_t groups[NGROUPS + 1];
+	ngroups_max =3D sysconf(_SC_NGROUPS_MAX) + 2;
+	if ((groups =3D malloc(sizeof(*groups) * ngroups_max)) =3D=3D NULL)
+		return (ENOMEM);
=20
-	ngroups =3D NGROUPS + 1;
+	ngroups =3D (int)ngroups_max;
 	getgrouplist(uname, agroup, groups, &ngroups);
-	return (setgroups(ngroups, groups));
+	ret =3D setgroups(ngroups, groups);
+	free(groups);
+	return (ret);
 }
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/lib/libc/rpc/auth_unix.c ./lib/libc=
/rpc/auth_unix.c
--- /usr/fsvn/head/lib/libc/rpc/auth_unix.c	2009-01-22 10:05:43.000000000 -=
0600
+++ ./lib/libc/rpc/auth_unix.c	2009-06-17 14:00:59.000000000 -0500
@@ -185,23 +185,29 @@
 AUTH *
 authunix_create_default()
 {
-	int len;
+	int ngids;
+	long ngids_max;
 	char machname[MAXHOSTNAMELEN + 1];
 	uid_t uid;
 	gid_t gid;
-	gid_t gids[NGROUPS_MAX];
+	gid_t *gids;
+
+	ngids_max =3D sysconf(_SC_NGROUPS_MAX) + 1;
+	gids =3D malloc(sizeof(gid_t) * ngids_max);
+	if (gids =3D=3D NULL)
+		return (NULL);
=20
 	if (gethostname(machname, sizeof machname) =3D=3D -1)
 		abort();
 	machname[sizeof(machname) - 1] =3D 0;
 	uid =3D geteuid();
 	gid =3D getegid();
-	if ((len =3D getgroups(NGROUPS_MAX, gids)) < 0)
+	if ((ngids =3D getgroups(ngids_max, gids)) < 0)
 		abort();
-	if (len > NGRPS)
-		len =3D NGRPS;
+	if (ngids > NGRPS)
+		ngids =3D NGRPS;
 	/* XXX: interface problem; those should all have been unsigned */
-	return (authunix_create(machname, (int)uid, (int)gid, len,
+	return (authunix_create(machname, (int)uid, (int)gid, ngids,
 	    (int *)gids));
 }
=20
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/lib/libc/sys/getgroups.2 ./lib/libc=
/sys/getgroups.2
--- /usr/fsvn/head/lib/libc/sys/getgroups.2	2009-01-22 10:05:48.000000000 -=
0600
+++ ./lib/libc/sys/getgroups.2	2009-06-16 13:56:17.000000000 -0500
@@ -58,10 +58,7 @@
 system call
 returns the actual number of groups returned in
 .Fa gidset .
-No more than
-.Dv NGROUPS_MAX
-will ever
-be returned.
+At least one and as many as {NGROUPS_MAX}+1 values may be returned.
 If
 .Fa gidsetlen
 is zero,
@@ -92,6 +89,11 @@
 .Sh SEE ALSO
 .Xr setgroups 2 ,
 .Xr initgroups 3
+.Sh STANDARDS
+The
+.Fn getgroups
+system call conforms to
+.St -p1003.1-2008 .
 .Sh HISTORY
 The
 .Fn getgroups
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/lib/libc/sys/setgroups.2 ./lib/libc=
/sys/setgroups.2
--- /usr/fsvn/head/lib/libc/sys/setgroups.2	2009-01-22 10:05:48.000000000 -=
0600
+++ ./lib/libc/sys/setgroups.2	2009-06-16 13:56:17.000000000 -0500
@@ -53,9 +53,7 @@
 argument
 indicates the number of entries in the array and must be no
 more than
-.Dv NGROUPS ,
-as defined in
-.In sys/param.h .
+.Dv {NGROUPS_MAX}+1 .
 .Pp
 Only the super-user may set a new group list.
 .Sh RETURN VALUES
@@ -71,7 +69,7 @@
 The number specified in the
 .Fa ngroups
 argument is larger than the
-.Dv NGROUPS
+.Dv {NGROUPS_MAX}+1
 limit.
 .It Bq Er EFAULT
 The address specified for
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.bin/id/id.c ./usr.bin/id/id.c
--- /usr/fsvn/head/usr.bin/id/id.c	2009-01-22 10:04:13.000000000 -0600
+++ ./usr.bin/id/id.c	2009-06-17 14:00:59.000000000 -0500
@@ -258,7 +258,8 @@
 	gid_t gid, egid, lastgid;
 	uid_t uid, euid;
 	int cnt, ngroups;
-	gid_t groups[NGROUPS + 1];
+	long ngroups_max;
+	gid_t *groups;
 	const char *fmt;
=20
 	if (pw !=3D NULL) {
@@ -270,12 +271,16 @@
 		gid =3D getgid();
 	}
=20
+	ngroups_max =3D sysconf(_SC_NGROUPS_MAX) + 1;
+	if ((groups =3D malloc(sizeof(gid_t) * ngroups_max)) =3D=3D NULL)
+		err(1, "malloc");
+
 	if (use_ggl && pw !=3D NULL) {
-		ngroups =3D NGROUPS + 1;
+		ngroups =3D ngroups_max;
 		getgrouplist(pw->pw_name, gid, groups, &ngroups);
 	}
 	else {
-		ngroups =3D getgroups(NGROUPS + 1, groups);
+		ngroups =3D getgroups(ngroups_max, groups);
 	}
=20
 	if (pw !=3D NULL)
@@ -306,6 +311,7 @@
 		lastgid =3D gid;
 	}
 	printf("\n");
+	free(groups);
 }
=20
 #ifdef USE_BSM_AUDIT
@@ -361,15 +367,19 @@
 {
 	struct group *gr;
 	int cnt, id, lastid, ngroups;
-	gid_t groups[NGROUPS + 1];
+	long ngroups_max;
+	gid_t *groups;
 	const char *fmt;
=20
+	ngroups_max =3D sysconf(_SC_NGROUPS_MAX) + 1;
+	if ((groups =3D malloc(sizeof(gid_t) * (ngroups_max))) =3D=3D NULL)
+		err(1, "malloc");
+
 	if (pw) {
-		ngroups =3D NGROUPS + 1;
+		ngroups =3D ngroups_max;
 		(void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
 	} else {
-		groups[0] =3D getgid();
-		ngroups =3D getgroups(NGROUPS, groups + 1) + 1;
+		ngroups =3D getgroups(ngroups_max, groups);
 	}
 	fmt =3D nflag ? "%s" : "%u";
 	for (lastid =3D -1, cnt =3D 0; cnt < ngroups; ++cnt) {
@@ -389,6 +399,7 @@
 		lastid =3D id;
 	}
 	(void)printf("\n");
+	free(groups);
 }
=20
 void
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.bin/newgrp/newgrp.c ./usr.bin/n=
ewgrp/newgrp.c
--- /usr/fsvn/head/usr.bin/newgrp/newgrp.c	2009-01-22 10:04:11.000000000 -0=
600
+++ ./usr.bin/newgrp/newgrp.c	2009-06-17 14:00:59.000000000 -0500
@@ -146,8 +146,8 @@
 static void
 addgroup(const char *grpname)
 {
-	gid_t grps[NGROUPS_MAX];
-	long lgid;
+	gid_t *grps;
+	long lgid, ngrps_max;
 	int dbmember, i, ngrps;
 	gid_t egid;
 	struct group *grp;
@@ -185,7 +185,10 @@
 		}
 	}
=20
-	if ((ngrps =3D getgroups(NGROUPS_MAX, (gid_t *)grps)) < 0) {
+	ngrps_max =3D sysconf(_SC_NGROUPS_MAX) + 1;
+	if ((grps =3D malloc(sizeof(gid_t) * ngrps_max)) =3D=3D NULL)
+		err(1, "malloc");
+	if ((ngrps =3D getgroups(ngrps_max, (gid_t *)grps)) < 0) {
 		warn("getgroups");
 		return;
 	}
@@ -217,7 +220,7 @@
=20
 	/* Add old effective gid to supp. list if it does not exist. */
 	if (egid !=3D grp->gr_gid && !inarray(egid, grps, ngrps)) {
-		if (ngrps =3D=3D NGROUPS_MAX)
+		if (ngrps =3D=3D ngrps_max)
 			warnx("too many groups");
 		else {
 			grps[ngrps++] =3D egid;
@@ -231,6 +234,7 @@
 		}
 	}
=20
+	free(grps);
 }
=20
 static int
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.bin/quota/quota.c ./usr.bin/quo=
ta/quota.c
--- /usr/fsvn/head/usr.bin/quota/quota.c	2009-01-22 10:04:12.000000000 -0600
+++ ./usr.bin/quota/quota.c	2009-06-17 14:00:59.000000000 -0500
@@ -117,7 +117,8 @@
 main(int argc, char *argv[])
 {
 	int ngroups;=20
-	gid_t mygid, gidset[NGROUPS];
+	long ngroups_max;
+	gid_t mygid, *gidset;
 	int i, ch, gflag =3D 0, uflag =3D 0, errflag =3D 0;
=20
 	while ((ch =3D getopt(argc, argv, "f:ghlrquv")) !=3D -1) {
@@ -159,13 +160,18 @@
 			errflag +=3D showuid(getuid());
 		if (gflag) {
 			mygid =3D getgid();
-			ngroups =3D getgroups(NGROUPS, gidset);
+			ngroups_max =3D sysconf(_SC_NGROUPS_MAX) + 1;
+			if ((gidset =3D malloc(sizeof(gid_t) * ngroups_max))
+			    =3D=3D NULL)
+				err(1, "malloc");
+			ngroups =3D getgroups(ngroups_max, gidset);
 			if (ngroups < 0)
 				err(1, "getgroups");
 			errflag +=3D showgid(mygid);
 			for (i =3D 0; i < ngroups; i++)
 				if (gidset[i] !=3D mygid)
 					errflag +=3D showgid(gidset[i]);
+			free(gidset);
 		}
 		return(errflag);
 	}
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.sbin/chown/chown.c ./usr.sbin/c=
hown/chown.c
--- /usr/fsvn/head/usr.sbin/chown/chown.c	2009-01-22 10:05:31.000000000 -06=
00
+++ ./usr.sbin/chown/chown.c	2009-06-17 14:00:59.000000000 -0500
@@ -269,7 +269,8 @@
 {
 	static uid_t euid =3D -1;
 	static int ngroups =3D -1;
-	gid_t groups[NGROUPS_MAX];
+	static long ngroups_max;
+	gid_t *groups;
=20
 	/* Check for chown without being root. */
 	if (errno !=3D EPERM || (uid !=3D (uid_t)-1 &&
@@ -281,7 +282,10 @@
 	/* Check group membership; kernel just returns EPERM. */
 	if (gid !=3D (gid_t)-1 && ngroups =3D=3D -1 &&
 	    euid =3D=3D (uid_t)-1 && (euid =3D geteuid()) !=3D 0) {
-		ngroups =3D getgroups(NGROUPS_MAX, groups);
+		ngroups_max =3D sysconf(_SC_NGROUPS_MAX) + 1;
+		if ((groups =3D malloc(sizeof(gid_t) * ngroups_max)) =3D=3D NULL)
+			err(1, "malloc");
+		ngroups =3D getgroups(ngroups_max, groups);
 		while (--ngroups >=3D 0 && gid !=3D groups[ngroups]);
 		if (ngroups < 0) {
 			warnx("you are not a member of group %s", gname);
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.sbin/chroot/chroot.c ./usr.sbin=
/chroot/chroot.c
--- /usr/fsvn/head/usr.sbin/chroot/chroot.c	2009-01-22 10:05:34.000000000 -=
0600
+++ ./usr.sbin/chroot/chroot.c	2009-06-17 14:00:59.000000000 -0500
@@ -69,9 +69,10 @@
 	struct passwd	*pw;
 	char		*endp, *p;
 	const char	*shell;
-	gid_t		gid, gidlist[NGROUPS_MAX];
+	gid_t		gid, *gidlist;
 	uid_t		uid;
 	int		ch, gids;
+	long		ngroups_max;
=20
 	gid =3D 0;
 	uid =3D 0;
@@ -117,8 +118,11 @@
 		}
 	}
=20
+	ngroups_max =3D sysconf(_SC_NGROUPS_MAX) + 1;
+	if ((gidlist =3D malloc(sizeof(gid_t) * ngroups_max)) =3D=3D NULL)
+		err(1, "malloc");
 	for (gids =3D 0;
-	    (p =3D strsep(&grouplist, ",")) !=3D NULL && gids < NGROUPS_MAX; ) {
+	    (p =3D strsep(&grouplist, ",")) !=3D NULL && gids < ngroups_max; ) {
 		if (*p =3D=3D '\0')
 			continue;
=20
@@ -135,7 +139,7 @@
 		}
 		gids++;
 	}
-	if (p !=3D NULL && gids =3D=3D NGROUPS_MAX)
+	if (p !=3D NULL && gids =3D=3D ngroups_max)
 		errx(1, "too many supplementary groups provided");
=20
 	if (user !=3D NULL) {
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.sbin/jail/jail.c ./usr.sbin/jai=
l/jail.c
--- /usr/fsvn/head/usr.sbin/jail/jail.c	2009-06-12 00:52:16.000000000 -0500
+++ ./usr.sbin/jail/jail.c	2009-06-17 14:00:59.000000000 -0500
@@ -104,7 +104,7 @@
 	lcap =3D login_getpwclass(pwd);					\
 	if (lcap =3D=3D NULL)						\
 		err(1, "getpwclass: %s", username);			\
-	ngroups =3D NGROUPS;						\
+	ngroups =3D ngroups_max;						\
 	if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) !=3D 0)	\
 		err(1, "getgrouplist: %s", username);			\
 } while (0)
@@ -115,10 +115,11 @@
 	login_cap_t *lcap =3D NULL;
 	struct iovec rparams[2];
 	struct passwd *pwd =3D NULL;
-	gid_t groups[NGROUPS];
+	gid_t *groups;
 	size_t sysvallen;
 	int ch, cmdarg, i, jail_set_flags, jid, ngroups, sysval;
 	int hflag, iflag, Jflag, lflag, rflag, uflag, Uflag;
+	long ngroups_max;
 	unsigned pi;
 	char *ep, *jailname, *securelevel, *username, *JidFile;
 	char errmsg[ERRMSG_SIZE], enforce_statfs[4];
@@ -132,6 +133,10 @@
 	jailname =3D securelevel =3D username =3D JidFile =3D cleanenv =3D NULL;
 	fp =3D NULL;
=20
+	ngroups_max =3D sysconf(_SC_NGROUPS_MAX) + 1;=09
+	if ((groups =3D malloc(sizeof(gid_t) * ngroups_max)) =3D=3D NULL)
+		err(1, "malloc");
+
 	while ((ch =3D getopt(argc, argv, "cdhilmn:r:s:u:U:J:")) !=3D -1) {
 		switch (ch) {
 		case 'd':
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.sbin/jexec/jexec.c ./usr.sbin/j=
exec/jexec.c
--- /usr/fsvn/head/usr.sbin/jexec/jexec.c	2009-05-29 12:48:00.000000000 -05=
00
+++ ./usr.sbin/jexec/jexec.c	2009-06-17 14:00:59.000000000 -0500
@@ -59,7 +59,7 @@
 	lcap =3D login_getpwclass(pwd);					\
 	if (lcap =3D=3D NULL)						\
 		err(1, "getpwclass: %s", username);			\
-	ngroups =3D NGROUPS;						\
+	ngroups =3D ngroups_max;						\
 	if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) !=3D 0)	\
 		err(1, "getgrouplist: %s", username);			\
 } while (0)
@@ -71,12 +71,17 @@
 	int jid;
 	login_cap_t *lcap =3D NULL;
 	struct passwd *pwd =3D NULL;
-	gid_t groups[NGROUPS];
+	gid_t *groups =3D NULL;
 	int ch, ngroups, uflag, Uflag;
+	long ngroups_max;
 	char *ep, *username;
 	ch =3D uflag =3D Uflag =3D 0;
 	username =3D NULL;
=20
+	ngroups_max =3D sysconf(_SC_NGROUPS_MAX) + 1;
+	if ((groups =3D malloc(sizeof(gid_t) * ngroups_max)) =3D=3D NULL)
+		err(1, "malloc");
+
 	while ((ch =3D getopt(argc, argv, "nu:U:")) !=3D -1) {
 		switch (ch) {
 		case 'n':
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.sbin/lpr/lpc/lpc.c ./usr.sbin/l=
pr/lpc/lpc.c
--- /usr/fsvn/head/usr.sbin/lpr/lpc/lpc.c	2009-01-22 10:05:32.000000000 -06=
00
+++ ./usr.sbin/lpr/lpc/lpc.c	2009-06-17 14:00:59.000000000 -0500
@@ -356,7 +356,8 @@
 {
 	static struct group *gptr=3DNULL;
 	static int ngroups =3D 0;
-	static gid_t groups[NGROUPS];
+	static long ngroups_max;
+	static gid_t *groups;
 	register gid_t gid;
 	register int i;
=20
@@ -365,7 +366,10 @@
 			warnx("warning: unknown group '%s'", grname);
 			return(0);
 		}
-		ngroups =3D getgroups(NGROUPS, groups);
+		ngroups_max =3D sysconf(_SC_NGROUPS_MAX);
+		if ((groups =3D malloc(sizeof(gid_t) * ngroups_max)) =3D=3D NULL)
+			err(1, "malloc");
+		ngroups =3D getgroups(ngroups_max, groups);
 		if (ngroups < 0)
 			err(1, "getgroups");
 	}

--YZ5djTAD1cGYuMQK
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="ngroups-main.diff"
Content-Transfer-Encoding: quoted-printable

diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/lib/libc/rpc/netname.c ./lib/libc/r=
pc/netname.c
--- /usr/fsvn/head/lib/libc/rpc/netname.c	2009-01-22 10:05:44.000000000 -06=
00
+++ ./lib/libc/rpc/netname.c	2009-05-14 01:48:22.000000000 -0500
@@ -61,9 +61,6 @@
 #ifndef MAXHOSTNAMELEN
 #define MAXHOSTNAMELEN 256
 #endif
-#ifndef NGROUPS
-#define NGROUPS 16
-#endif
=20
 #define TYPE_BIT(type)  (sizeof (type) * CHAR_BIT)
=20
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/lib/libc/rpc/netnamer.c ./lib/libc/=
rpc/netnamer.c
--- /usr/fsvn/head/lib/libc/rpc/netnamer.c	2009-01-22 10:05:44.000000000 -0=
600
+++ ./lib/libc/rpc/netnamer.c	2009-05-13 22:51:38.000000000 -0500
@@ -66,10 +66,6 @@
 static int getnetid( char *, char * );
 static int _getgroups( char *, gid_t * );
=20
-#ifndef NGROUPS
-#define NGROUPS 16
-#endif
-
 /*
  * Convert network-name into unix credential
  */
@@ -104,7 +100,7 @@
 			return (0);
 		}
 		*gidp =3D (gid_t) atol(p);
-		for (gidlen =3D 0; gidlen < NGROUPS; gidlen++) {
+		for (gidlen =3D 0; gidlen < NGRPS; gidlen++) {
 			p =3D strsep(&res, "\n,");
 			if (p =3D=3D NULL)
 				break;
@@ -157,7 +153,7 @@
 static int
 _getgroups(uname, groups)
 	char           *uname;
-	gid_t          groups[NGROUPS];
+	gid_t          groups[NGRPS];
 {
 	gid_t           ngroups =3D 0;
 	struct group *grp;
@@ -169,7 +165,7 @@
 	while ((grp =3D getgrent())) {
 		for (i =3D 0; grp->gr_mem[i]; i++)
 			if (!strcmp(grp->gr_mem[i], uname)) {
-				if (ngroups =3D=3D NGROUPS) {
+				if (ngroups =3D=3D NGRPS) {
 #ifdef DEBUG
 					fprintf(stderr,
 				"initgroups: %s is in too many groups\n", uname);
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/lib/libkvm/kvm_proc.c ./lib/libkvm/=
kvm_proc.c
--- /usr/fsvn/head/lib/libkvm/kvm_proc.c	2009-06-16 15:54:14.000000000 -0500
+++ ./lib/libkvm/kvm_proc.c	2009-05-28 16:40:33.000000000 -0500
@@ -146,8 +146,7 @@
 			kp->ki_rgid =3D ucred.cr_rgid;
 			kp->ki_svgid =3D ucred.cr_svgid;
 			kp->ki_ngroups =3D ucred.cr_ngroups;
-			bcopy(ucred.cr_groups, kp->ki_groups,
-			    NGROUPS * sizeof(gid_t));
+			kp->ki_groups =3D ucred.cr_groups;
 			kp->ki_uid =3D ucred.cr_uid;
 			if (ucred.cr_prison !=3D NULL) {
 				if (KREAD(kd, (u_long)ucred.cr_prison, &pr)) {
Files /usr/fsvn/head/share/examples/kld/firmware/fwimage/firmware.img and .=
/share/examples/kld/firmware/fwimage/firmware.img differ
Only in /usr/fsvn/head/sys: .glimpse_exclude
Only in /usr/fsvn/head/sys: .glimpse_filenames
Only in /usr/fsvn/head/sys: .glimpse_filenames_index
Only in /usr/fsvn/head/sys: .glimpse_filetimes
Only in /usr/fsvn/head/sys: .glimpse_index
Only in /usr/fsvn/head/sys: .glimpse_messages
Only in /usr/fsvn/head/sys: .glimpse_partitions
Only in /usr/fsvn/head/sys: .glimpse_statistics
Only in /usr/fsvn/head/sys: .glimpse_turbo
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/compat/linux/linux_misc.c ./sys=
/compat/linux/linux_misc.c
--- /usr/fsvn/head/sys/compat/linux/linux_misc.c	2009-06-16 15:54:53.000000=
000 -0500
+++ ./sys/compat/linux/linux_misc.c	2009-06-16 13:56:19.000000000 -0500
@@ -1132,7 +1132,7 @@
 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;
@@ -1140,13 +1140,14 @@
 	ngrp =3D args->gidsetsize;
 	if (ngrp < 0 || ngrp >=3D NGROUPS)
 		return (EINVAL);
+	linux_gidset =3D malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK);
 	error =3D copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t));
 	if (error)
-		return (error);
+		goto out;
 	newcred =3D crget();
 	p =3D td->td_proc;
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	oldcred =3D crcopysafe(p, newcred);
=20
 	/*
 	 * cr_groups[0] holds egid. Setting the whole set from
@@ -1157,10 +1158,9 @@
 	if ((error =3D priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) !=3D 0) {
 		PROC_UNLOCK(p);
 		crfree(newcred);
-		return (error);
+		goto out;
 	}
=20
-	crcopy(newcred, oldcred);
 	if (ngrp > 0) {
 		newcred->cr_ngroups =3D ngrp + 1;
=20
@@ -1177,14 +1177,17 @@
 	p->p_ucred =3D newcred;
 	PROC_UNLOCK(p);
 	crfree(oldcred);
-	return (0);
+	error =3D 0;
+out:
+	free(linux_gidset, M_TEMP);
+	return (error);
 }
=20
 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;
=20
@@ -1207,13 +1210,16 @@
 		return (EINVAL);
=20
 	ngrp =3D 0;
+	linux_gidset =3D malloc(bsd_gidsetsz * sizeof(*linux_gidset),
+	    M_TEMP, M_WAITOK);
 	while (ngrp < bsd_gidsetsz) {
 		linux_gidset[ngrp] =3D bsd_gidset[ngrp + 1];
 		ngrp++;
 	}
=20
-	if ((error =3D copyout(linux_gidset, args->grouplist,
-	    ngrp * sizeof(l_gid_t))))
+	error =3D copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t));
+	free(linux_gidset, M_TEMP);
+	if (error)
 		return (error);
=20
 	td->td_retval[0] =3D ngrp;
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/compat/linux/linux_uid16.c ./sy=
s/compat/linux/linux_uid16.c
--- /usr/fsvn/head/sys/compat/linux/linux_uid16.c	2009-06-16 15:54:53.00000=
0000 -0500
+++ ./sys/compat/linux/linux_uid16.c	2009-05-28 16:40:33.000000000 -0500
@@ -98,7 +98,7 @@
 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 @@
 	ngrp =3D args->gidsetsize;
 	if (ngrp < 0 || ngrp >=3D NGROUPS)
 		return (EINVAL);
+	linux_gidset =3D malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK);
 	error =3D copyin(args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t));
 	if (error)
 		return (error);
 	newcred =3D crget();
 	p =3D td->td_proc;
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	oldcred =3D crcopysafe(p, newcred);
=20
 	/*
 	 * cr_groups[0] holds egid. Setting the whole set from
@@ -128,10 +129,9 @@
 	if ((error =3D priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) !=3D 0) {
 		PROC_UNLOCK(p);
 		crfree(newcred);
-		return (error);
+		goto out;
 	}
=20
-	crcopy(newcred, oldcred);
 	if (ngrp > 0) {
 		newcred->cr_ngroups =3D ngrp + 1;
=20
@@ -149,14 +149,17 @@
 	p->p_ucred =3D newcred;
 	PROC_UNLOCK(p);
 	crfree(oldcred);
-	return (0);
+	error =3D 0;
+out:
+	free(linux_gidset, M_TEMP);
+	return (error);
 }
=20
 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;
=20
@@ -184,12 +187,15 @@
 		return (EINVAL);
=20
 	ngrp =3D 0;
+	linux_gidset =3D malloc(bsd_gidsetsz * sizeof(*linux_gidset),
+	    M_TEMP, M_WAITOK);
 	while (ngrp < bsd_gidsetsz) {
 		linux_gidset[ngrp] =3D bsd_gidset[ngrp + 1];
 		ngrp++;
 	}
=20
 	error =3D copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t));
+	free(linux_gidset, M_TEMP);
 	if (error)
 		return (error);
=20
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/fs/nfs/nfs_commonport.c ./sys/f=
s/nfs/nfs_commonport.c
--- /usr/fsvn/head/sys/fs/nfs/nfs_commonport.c	2009-05-29 12:48:03.00000000=
0 -0500
+++ ./sys/fs/nfs/nfs_commonport.c	2009-06-09 08:49:37.000000000 -0500
@@ -220,14 +220,9 @@
 void
 newnfs_copycred(struct nfscred *nfscr, struct ucred *cr)
 {
-	int ngroups, i;
=20
 	cr->cr_uid =3D nfscr->nfsc_uid;
-	ngroups =3D (nfscr->nfsc_ngroups < NGROUPS) ?
-	    nfscr->nfsc_ngroups : NGROUPS;
-	for (i =3D 0; i < ngroups; i++)
-		cr->cr_groups[i] =3D nfscr->nfsc_groups[i];
-	cr->cr_ngroups =3D ngroups;
+	crsetgroups(cr, nfscr->nfsc_ngroups, nfscr->nfsc_groups);
 }
=20
 /*
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/fs/nfsclient/nfs_clport.c ./sys=
/fs/nfsclient/nfs_clport.c
--- /usr/fsvn/head/sys/fs/nfsclient/nfs_clport.c	2009-05-29 12:48:03.000000=
000 -0500
+++ ./sys/fs/nfsclient/nfs_clport.c	2009-06-05 15:33:54.000000000 -0500
@@ -976,14 +976,12 @@
 void
 newnfs_copyincred(struct ucred *cr, struct nfscred *nfscr)
 {
-	int ngroups, i;
+	int i;
=20
 	nfscr->nfsc_uid =3D cr->cr_uid;
-	ngroups =3D (cr->cr_ngroups > NGROUPS) ? NGROUPS :
-	    cr->cr_ngroups;
-	for (i =3D 0; i < ngroups; i++)
+	nfscr->nfsc_ngroups =3D MIN(cr->cr_ngroups, XU_NGROUPS);
+	for (i =3D 0; i < nfscr->nfsc_ngroups; i++)
 		nfscr->nfsc_groups[i] =3D cr->cr_groups[i];
-	nfscr->nfsc_ngroups =3D ngroups;
 }
=20
=20
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/fs/nfsserver/nfs_nfsdport.c ./s=
ys/fs/nfsserver/nfs_nfsdport.c
--- /usr/fsvn/head/sys/fs/nfsserver/nfs_nfsdport.c	2009-06-05 15:33:50.0000=
00000 -0500
+++ ./sys/fs/nfsserver/nfs_nfsdport.c	2009-06-05 16:02:29.000000000 -0500
@@ -2360,7 +2360,6 @@
 nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp,
     struct ucred *credanon)
 {
-	int i;
 	int error =3D 0;
=20
 	/*
@@ -2403,9 +2402,8 @@
 	     (nd->nd_flag & ND_AUTHNONE))) {
 		nd->nd_cred->cr_uid =3D credanon->cr_uid;
 		nd->nd_cred->cr_gid =3D credanon->cr_gid;
-		for (i =3D 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
-			nd->nd_cred->cr_groups[i] =3D credanon->cr_groups[i];
-		nd->nd_cred->cr_ngroups =3D i;
+		crsetgroups(nd->nd_cred, credanon->cr_ngroups,
+		    credanon->cr_groups);
 	}
 	return (0);
 }
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/fs/nfsserver/nfs_nfsdstate.c ./=
sys/fs/nfsserver/nfs_nfsdstate.c
--- /usr/fsvn/head/sys/fs/nfsserver/nfs_nfsdstate.c	2009-06-16 13:55:57.000=
000000 -0500
+++ ./sys/fs/nfsserver/nfs_nfsdstate.c	2009-06-16 13:56:18.000000000 -0500
@@ -3577,7 +3577,6 @@
 	nd->nd_repstat =3D 0;
 	cred->cr_uid =3D clp->lc_uid;
 	cred->cr_gid =3D clp->lc_gid;
-	cred->cr_groups[0] =3D clp->lc_gid;
 	callback =3D clp->lc_callback;
 	NFSUNLOCKSTATE();
 	cred->cr_ngroups =3D 1;
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/fs/portalfs/portal.h ./sys/fs/p=
ortalfs/portal.h
--- /usr/fsvn/head/sys/fs/portalfs/portal.h	2009-01-22 10:06:01.000000000 -=
0600
+++ ./sys/fs/portalfs/portal.h	2009-06-05 15:33:54.000000000 -0500
@@ -43,7 +43,7 @@
 	int		pcr_flag;		/* File open mode */
 	uid_t		pcr_uid;		/* From ucred */
 	short		pcr_ngroups;		/* From ucred */
-	gid_t		pcr_groups[NGROUPS];	/* From ucred */
+	gid_t		pcr_groups[XU_NGROUPS];	/* From ucred */
 };
=20
 #ifdef _KERNEL
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/fs/portalfs/portal_vnops.c ./sy=
s/fs/portalfs/portal_vnops.c
--- /usr/fsvn/head/sys/fs/portalfs/portal_vnops.c	2009-01-22 10:06:01.00000=
0000 -0600
+++ ./sys/fs/portalfs/portal_vnops.c	2009-06-05 15:33:54.000000000 -0500
@@ -311,8 +311,9 @@
=20
 	pcred.pcr_flag =3D ap->a_mode;
 	pcred.pcr_uid =3D ap->a_cred->cr_uid;
-	pcred.pcr_ngroups =3D ap->a_cred->cr_ngroups;
-	bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
+	pcred.pcr_ngroups =3D MIN(ap->a_cred->cr_ngroups, XU_NGROUPS);
+	bcopy(ap->a_cred->cr_groups, pcred.pcr_groups,
+	    pcred.pcr_ngroups * sizeof(gid_t));
 	aiov[0].iov_base =3D (caddr_t) &pcred;
 	aiov[0].iov_len =3D sizeof(pcred);
 	aiov[1].iov_base =3D pt->pt_arg;
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/fs/unionfs/union_vnops.c ./sys/=
fs/unionfs/union_vnops.c
--- /usr/fsvn/head/sys/fs/unionfs/union_vnops.c	2009-04-12 15:26:52.0000000=
00 -0500
+++ ./sys/fs/unionfs/union_vnops.c	2009-06-05 15:33:54.000000000 -0500
@@ -638,7 +638,6 @@
 	uid_t		uid;	/* upper side vnode's uid */
 	gid_t		gid;	/* upper side vnode's gid */
 	u_short		vmode;	/* upper side vnode's mode */
-	gid_t          *gp;
 	u_short		mask;
=20
 	mask =3D 0;
@@ -659,17 +658,14 @@
=20
 	/* check group */
 	count =3D 0;
-	gp =3D cred->cr_groups;
-	for (; count < cred->cr_ngroups; count++, gp++) {
-		if (gid =3D=3D *gp) {
-			if (accmode & VEXEC)
-				mask |=3D S_IXGRP;
-			if (accmode & VREAD)
-				mask |=3D S_IRGRP;
-			if (accmode & VWRITE)
-				mask |=3D S_IWGRP;
-			return ((vmode & mask) =3D=3D mask ? 0 : EACCES);
-		}
+	if (groupmember(gid, cred)) {
+		if (accmode & VEXEC)
+			mask |=3D S_IXGRP;
+		if (accmode & VREAD)
+			mask |=3D S_IRGRP;
+		if (accmode & VWRITE)
+			mask |=3D S_IWGRP;
+		return ((vmode & mask) =3D=3D mask ? 0 : EACCES);
 	}
=20
 	/* check other */
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/i386/ibcs2/ibcs2_misc.c ./sys/i=
386/ibcs2/ibcs2_misc.c
--- /usr/fsvn/head/sys/i386/ibcs2/ibcs2_misc.c	2009-06-16 15:54:53.00000000=
0 -0500
+++ ./sys/i386/ibcs2/ibcs2_misc.c	2009-06-05 16:02:31.000000000 -0500
@@ -657,24 +657,29 @@
 	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;
=20
 	if (uap->gidsetsize < 0)
 		return (EINVAL);
 	ngrp =3D MIN(uap->gidsetsize, NGROUPS_MAX);
+	gp =3D malloc(ngrp * sizeof(*gp), M_TEMP, M_WAITOK);
 	error =3D kern_getgroups(td, &ngrp, gp);
 	if (error)
-		return (error);
+		goto out;
 	if (uap->gidsetsize > 0) {
+		iset =3D malloc(ngrp * sizeof(*iset), M_TEMP, M_WAITOK);
 		for (i =3D 0; i < ngrp; i++)
 			iset[i] =3D (ibcs2_gid_t)gp[i];
 		error =3D copyout(iset, uap->gidset, ngrp * sizeof(ibcs2_gid_t));
+		free(iset, M_TEMP);
 	}
 	if (error =3D=3D 0)
 		td->td_retval[0] =3D ngrp;
+out:
+	free(gp, M_TEMP);
 	return (error);
 }
=20
@@ -683,21 +688,31 @@
 	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;
=20
 	if (uap->gidsetsize < 0 || uap->gidsetsize > NGROUPS_MAX)
 		return (EINVAL);
-	if (uap->gidsetsize && uap->gidset) {
+	if (uap->gidsetsize && uap->gidset =3D=3D NULL)
+		return (EINVAL);
+	gp =3D malloc(uap->gidsetsize * sizeof(*gp), M_TEMP, M_WAITOK);
+	if (uap->gidsetsize) {
+		iset =3D malloc(uap->gidsetsize * sizeof(*iset), M_TEMP, M_WAITOK);
 		error =3D copyin(uap->gidset, iset, sizeof(ibcs2_gid_t) *
 		    uap->gidsetsize);
-		if (error)
-			return (error);
+		if (error) {
+			free(iset, M_TEMP);
+			goto out;
+		}
 		for (i =3D 0; i < uap->gidsetsize; i++)
 			gp[i] =3D (gid_t)iset[i];
 	}
-	return (kern_setgroups(td, uap->gidsetsize, gp));
+
+	error =3D kern_setgroups(td, uap->gidsetsize, gp);
+out:
+	free(gp, M_TEMP);
+	return (error);
 }
=20
 int
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/kern/kern_exec.c ./sys/kern/ker=
n_exec.c
--- /usr/fsvn/head/sys/kern/kern_exec.c	2009-06-16 15:54:34.000000000 -0500
+++ ./sys/kern/kern_exec.c	2009-06-12 01:13:11.000000000 -0500
@@ -579,6 +579,7 @@
 	 * reset.
 	 */
 	PROC_LOCK(p);
+	oldcred =3D crcopysafe(p, newcred);
 	if (sigacts_shared(p->p_sigacts)) {
 		oldsigacts =3D p->p_sigacts;
 		PROC_UNLOCK(p);
@@ -629,7 +630,6 @@
 	 * XXXMAC: For the time being, use NOSUID to also prohibit
 	 * transitions on the file system.
 	 */
-	oldcred =3D p->p_ucred;
 	credential_changing =3D 0;
 	credential_changing |=3D (attr.va_mode & S_ISUID) && oldcred->cr_uid !=3D
 	    attr.va_uid;
@@ -683,7 +683,6 @@
 		/*
 		 * Set the new credentials.
 		 */
-		crcopy(newcred, oldcred);
 		if (attr.va_mode & S_ISUID)
 			change_euid(newcred, euip);
 		if (attr.va_mode & S_ISGID)
@@ -723,7 +722,6 @@
 		 */
 		if (oldcred->cr_svuid !=3D oldcred->cr_uid ||
 		    oldcred->cr_svgid !=3D oldcred->cr_gid) {
-			crcopy(newcred, oldcred);
 			change_svuid(newcred, newcred->cr_uid);
 			change_svgid(newcred, newcred->cr_gid);
 			p->p_ucred =3D newcred;
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/kern/kern_proc.c ./sys/kern/ker=
n_proc.c
--- /usr/fsvn/head/sys/kern/kern_proc.c	2009-06-16 15:54:34.000000000 -0500
+++ ./sys/kern/kern_proc.c	2009-06-05 16:02:28.000000000 -0500
@@ -730,10 +730,8 @@
 		kp->ki_uid =3D cred->cr_uid;
 		kp->ki_ruid =3D cred->cr_ruid;
 		kp->ki_svuid =3D cred->cr_svuid;
-		/* XXX bde doesn't like KI_NGROUPS */
-		kp->ki_ngroups =3D min(cred->cr_ngroups, KI_NGROUPS);
-		bcopy(cred->cr_groups, kp->ki_groups,
-		    kp->ki_ngroups * sizeof(gid_t));
+		kp->ki_ngroups =3D cred->cr_ngroups;
+		kp->ki_groups =3D cred->cr_groups;
 		kp->ki_rgid =3D cred->cr_rgid;
 		kp->ki_svgid =3D cred->cr_svgid;
 		kp->ki_cr_flags =3D cred->cr_flags;
--- /usr/fsvn/head/sys/kern/kern_prot.c	2009-06-16 15:54:34.000000000 -0500
+++ ./sys/kern/kern_prot.c	2009-06-17 18:24:56.000000000 -0500
@@ -82,6 +82,10 @@
=20
 SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy"=
);
=20
+static void crextend(struct ucred *cr, int n);
+static void crsetgroups_locked(struct ucred *cr, int ngrp,
+    gid_t *groups);
+
 #ifndef _SYS_SYSPROTO_H_
 struct getpid_args {
 	int	dummy;
@@ -276,18 +280,21 @@
 int
 getgroups(struct thread *td, register struct getgroups_args *uap)
 {
-	gid_t groups[NGROUPS];
+	gid_t *groups;
 	u_int ngrp;
 	int error;
=20
 	ngrp =3D MIN(uap->gidsetsize, NGROUPS);
+	groups =3D malloc(ngrp * sizeof(*groups), M_TEMP, M_WAITOK);
 	error =3D kern_getgroups(td, &ngrp, groups);
 	if (error)
-		return (error);
+		goto out;
 	if (uap->gidsetsize > 0)
 		error =3D copyout(groups, uap->gidset, ngrp * sizeof(gid_t));
 	if (error =3D=3D 0)
 		td->td_retval[0] =3D ngrp;
+out:
+	free(groups, M_TEMP);
 	return (error);
 }
=20
@@ -486,7 +493,10 @@
 	newcred =3D crget();
 	uip =3D uifind(uid);
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	/*
+	 * Copy credentials so other references do not see our changes.
+	 */
+	oldcred =3D crcopysafe(p, newcred);
=20
 #ifdef MAC
 	error =3D mac_cred_check_setuid(oldcred, uid);
@@ -521,10 +531,6 @@
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)) !=3D 0)
 		goto fail;
=20
-	/*
-	 * 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 =3D=3D euid)
@@ -598,7 +604,10 @@
 	newcred =3D crget();
 	euip =3D uifind(euid);
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	/*
+	 * Copy credentials so other references do not see our changes.
+	 */
+	oldcred =3D crcopysafe(p, newcred);
=20
 #ifdef MAC
 	error =3D mac_cred_check_seteuid(oldcred, euid);
@@ -612,8 +621,7 @@
 		goto fail;
=20
 	/*
-	 * 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 !=3D euid) {
@@ -651,7 +659,7 @@
 	AUDIT_ARG(gid, gid);
 	newcred =3D crget();
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	oldcred =3D crcopysafe(p, newcred);
=20
 #ifdef MAC
 	error =3D mac_cred_check_setgid(oldcred, gid);
@@ -680,7 +688,6 @@
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) !=3D 0)
 		goto fail;
=20
-	crcopy(newcred, oldcred);
 #ifdef _POSIX_SAVED_IDS
 	/*
 	 * Do we have "appropriate privileges" (are we root or gid =3D=3D egid)
@@ -750,7 +757,7 @@
 	AUDIT_ARG(egid, egid);
 	newcred =3D crget();
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	oldcred =3D crcopysafe(p, newcred);
=20
 #ifdef MAC
 	error =3D mac_cred_check_setegid(oldcred, egid);
@@ -763,7 +770,6 @@
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) !=3D 0)
 		goto fail;
=20
-	crcopy(newcred, oldcred);
 	if (oldcred->cr_groups[0] !=3D egid) {
 		change_egid(newcred, egid);
 		setsugid(p);
@@ -789,15 +795,19 @@
 int
 setgroups(struct thread *td, struct setgroups_args *uap)
 {
-	gid_t groups[NGROUPS];
+	gid_t *groups =3D NULL;
 	int error;
=20
 	if (uap->gidsetsize > NGROUPS)
 		return (EINVAL);
+	groups =3D malloc(uap->gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK);
 	error =3D copyin(uap->gidset, groups, uap->gidsetsize * sizeof(gid_t));
 	if (error)
-		return (error);
-	return (kern_setgroups(td, uap->gidsetsize, groups));
+		goto out;
+	error =3D kern_setgroups(td, uap->gidsetsize, groups);
+out:
+	free(groups, M_TEMP);
+	return (error);
 }
=20
 int
@@ -811,8 +821,9 @@
 		return (EINVAL);
 	AUDIT_ARG(groupset, groups, ngrp);
 	newcred =3D crget();
+	crextend(newcred, ngrp);
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	oldcred =3D crcopysafe(p, newcred);
=20
 #ifdef MAC
 	error =3D mac_cred_check_setgroups(oldcred, ngrp, groups);
@@ -824,11 +835,6 @@
 	if (error)
 		goto fail;
=20
-	/*
-	 * 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
@@ -838,8 +844,7 @@
 		 */
 		newcred->cr_ngroups =3D 1;
 	} else {
-		bcopy(groups, newcred->cr_groups, ngrp * sizeof(gid_t));
-		newcred->cr_ngroups =3D ngrp;
+		crsetgroups_locked(newcred, ngrp, groups);
 	}
 	setsugid(p);
 	p->p_ucred =3D newcred;
@@ -877,7 +882,7 @@
 	euip =3D uifind(euid);
 	ruip =3D uifind(ruid);
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	oldcred =3D crcopysafe(p, newcred);
=20
 #ifdef MAC
 	error =3D mac_cred_check_setreuid(oldcred, ruid, euid);
@@ -892,7 +897,6 @@
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETREUID, 0)) !=3D 0)
 		goto fail;
=20
-	crcopy(newcred, oldcred);
 	if (euid !=3D (uid_t)-1 && oldcred->cr_uid !=3D euid) {
 		change_euid(newcred, euip);
 		setsugid(p);
@@ -942,7 +946,7 @@
 	AUDIT_ARG(rgid, rgid);
 	newcred =3D crget();
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	oldcred =3D crcopysafe(p, newcred);
=20
 #ifdef MAC
 	error =3D mac_cred_check_setregid(oldcred, rgid, egid);
@@ -957,7 +961,6 @@
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) !=3D 0)
 		goto fail;
=20
-	crcopy(newcred, oldcred);
 	if (egid !=3D (gid_t)-1 && oldcred->cr_groups[0] !=3D egid) {
 		change_egid(newcred, egid);
 		setsugid(p);
@@ -1013,7 +1016,7 @@
 	euip =3D uifind(euid);
 	ruip =3D uifind(ruid);
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	oldcred =3D crcopysafe(p, newcred);
=20
 #ifdef MAC
 	error =3D mac_cred_check_setresuid(oldcred, ruid, euid, suid);
@@ -1033,7 +1036,6 @@
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETRESUID, 0)) !=3D 0)
 		goto fail;
=20
-	crcopy(newcred, oldcred);
 	if (euid !=3D (uid_t)-1 && oldcred->cr_uid !=3D euid) {
 		change_euid(newcred, euip);
 		setsugid(p);
@@ -1090,7 +1092,7 @@
 	AUDIT_ARG(sgid, sgid);
 	newcred =3D crget();
 	PROC_LOCK(p);
-	oldcred =3D p->p_ucred;
+	oldcred =3D crcopysafe(p, newcred);
=20
 #ifdef MAC
 	error =3D mac_cred_check_setresgid(oldcred, rgid, egid, sgid);
@@ -1110,7 +1112,6 @@
 	    (error =3D priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) !=3D 0)
 		goto fail;
=20
-	crcopy(newcred, oldcred);
 	if (egid !=3D (gid_t)-1 && oldcred->cr_groups[0] !=3D egid) {
 		change_egid(newcred, egid);
 		setsugid(p);
@@ -1780,6 +1781,7 @@
 #ifdef MAC
 	mac_cred_init(cr);
 #endif
+	crextend(cr, XU_NGROUPS);
 	return (cr);
 }
=20
@@ -1829,6 +1831,7 @@
 #ifdef MAC
 		mac_cred_destroy(cr);
 #endif
+		free(cr->cr_groups, M_CRED);
 		free(cr, M_CRED);
 	}
 }
@@ -1854,6 +1857,7 @@
 	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
 	    (unsigned)((caddr_t)&src->cr_endcopy -
 		(caddr_t)&src->cr_startcopy));
+	crsetgroups(dest, src->cr_ngroups, src->cr_groups);
 	uihold(dest->cr_uidinfo);
 	uihold(dest->cr_ruidinfo);
 	prison_hold(dest->cr_prison);
@@ -1888,12 +1892,16 @@
 void
 cru2x(struct ucred *cr, struct xucred *xcr)
 {
+	int ngroups;
=20
 	bzero(xcr, sizeof(*xcr));
 	xcr->cr_version =3D XUCRED_VERSION;
 	xcr->cr_uid =3D cr->cr_uid;
-	xcr->cr_ngroups =3D cr->cr_ngroups;
-	bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups));
+
+	ngroups =3D MIN(cr->cr_ngroups, XU_NGROUPS);
+	xcr->cr_ngroups =3D ngroups;
+	bcopy(cr->cr_groups, xcr->cr_groups,
+	    ngroups * sizeof(*cr->cr_groups));
 }
=20
 /*
@@ -1915,6 +1923,97 @@
 		crfree(cred);
 }
=20
+struct ucred *
+crcopysafe(struct proc *p, struct ucred *cr)
+{
+	struct ucred *oldcred;
+	int groups;
+
+	PROC_LOCK_ASSERT(p, MA_OWNED);
+
+	oldcred =3D p->p_ucred;
+	while (cr->cr_agroups < oldcred->cr_agroups) {
+		groups =3D oldcred->cr_agroups;
+		PROC_UNLOCK(p);
+		crextend(cr, groups);
+		PROC_LOCK(p);
+		oldcred =3D p->p_ucred;
+	}
+	crcopy(cr, oldcred);
+
+	return (oldcred);
+}
+
+/*
+ * Extend the passed in credential to hold n items.
+ */
+static void
+crextend(struct ucred *cr, int n)
+{
+	int cnt;
+
+	/* Truncate? */
+	if (n <=3D cr->cr_agroups)
+		return;
+
+	/*
+	 * We extend by 2 each time since we're using a power of two
+	 * allocator until we need enough groups to fill a page.
+	 * Once we're allocating multiple pages, only allocate as many
+	 * as we actually need.  The case of processes needing a
+	 * non-power of two number of pages seems more likely than
+	 * a real world process that adds thousands of groups one at a
+	 * time.
+	 */
+	if ( n < PAGE_SIZE / sizeof(gid_t) ) {
+		if (cr->cr_agroups =3D=3D 0)
+			cnt =3D MINALLOCSIZE / sizeof(gid_t);
+		else
+			cnt =3D cr->cr_agroups * 2;
+
+		while (cnt < n)
+			cnt *=3D 2;
+	} else
+		cnt =3D roundup2(n, PAGE_SIZE / sizeof(gid_t));
+
+	/* Free the old array. */
+	if (cr->cr_groups)
+		free(cr->cr_groups, M_CRED);
+
+	cr->cr_groups =3D malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO);
+	cr->cr_agroups =3D cnt;
+}
+
+/*
+ * Copy groups in to a credential, preserving any necessicary invariants
+ * (i.e. sorting in the future).  crextend() must have been called
+ * before hand to ensure sufficient space is available.  If=20
+ */
+static void
+crsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups)
+{
+=09
+	KASSERT(cr->cr_agroups >=3D ngrp, ("cr_ngroups is too small"));
+
+	bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
+	cr->cr_ngroups =3D ngrp;
+}
+
+/*
+ * Copy groups in to a credential after expanding it if required.
+ * Truncate the list to NGROUPS if it is too large.
+ */
+void
+crsetgroups(struct ucred *cr, int ngrp, gid_t *groups)
+{
+
+	if (ngrp > NGROUPS)
+		ngrp =3D NGROUPS;
+
+	crextend(cr, ngrp);
+	crsetgroups_locked(cr, ngrp, groups);
+}
+
 /*
  * Get login name, if available.
  */
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/kern/vfs_export.c ./sys/kern/vf=
s_export.c
--- /usr/fsvn/head/sys/kern/vfs_export.c	2009-05-29 12:48:02.000000000 -0500
+++ ./sys/kern/vfs_export.c	2009-06-05 15:33:54.000000000 -0500
@@ -120,9 +120,8 @@
 		np->netc_exflags =3D argp->ex_flags;
 		np->netc_anon =3D crget();
 		np->netc_anon->cr_uid =3D argp->ex_anon.cr_uid;
-		np->netc_anon->cr_ngroups =3D argp->ex_anon.cr_ngroups;
-		bcopy(argp->ex_anon.cr_groups, np->netc_anon->cr_groups,
-		    sizeof(np->netc_anon->cr_groups));
+		crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups,
+		    argp->ex_anon.cr_groups);
 		np->netc_numsecflavors =3D argp->ex_numsecflavors;
 		bcopy(argp->ex_secflavors, np->netc_secflavors,
 		    sizeof(np->netc_secflavors));
@@ -205,9 +204,8 @@
 	np->netc_exflags =3D argp->ex_flags;
 	np->netc_anon =3D crget();
 	np->netc_anon->cr_uid =3D argp->ex_anon.cr_uid;
-	np->netc_anon->cr_ngroups =3D argp->ex_anon.cr_ngroups;
-	bcopy(argp->ex_anon.cr_groups, np->netc_anon->cr_groups,
-	    sizeof(np->netc_anon->cr_groups));
+	crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups,
+	    np->netc_anon->cr_groups);
 	np->netc_numsecflavors =3D argp->ex_numsecflavors;
 	bcopy(argp->ex_secflavors, np->netc_secflavors,
 	    sizeof(np->netc_secflavors));
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/netinet/ipfw/ip_fw2.c ./sys/net=
inet/ipfw/ip_fw2.c
--- /usr/fsvn/head/sys/netinet/ipfw/ip_fw2.c	2009-06-12 00:52:26.000000000 =
-0500
+++ ./sys/netinet/ipfw/ip_fw2.c	2009-06-17 13:42:23.000000000 -0500
@@ -135,19 +135,6 @@
 struct ip_fw *ip_fw_default_rule;
=20
 /*
- * Data structure to cache our ucred related
- * information. This structure only gets used if
- * the user specified UID/GID based constraints in
- * a firewall rule.
- */
-struct ip_fw_ugid {
-	gid_t		fw_groups[NGROUPS];
-	int		fw_ngroups;
-	uid_t		fw_uid;
-	int		fw_prid;
-};
-
-/*
  * list of rules for layer 3
  */
 #ifdef VIMAGE_GLOBALS
@@ -2009,22 +1996,10 @@
 	return (0);
 }
=20
-static void
-fill_ugid_cache(struct inpcb *inp, struct ip_fw_ugid *ugp)
-{
-	struct ucred *cr;
-
-	cr =3D inp->inp_cred;
-	ugp->fw_prid =3D jailed(cr) ? cr->cr_prison->pr_id : -1;
-	ugp->fw_uid =3D cr->cr_uid;
-	ugp->fw_ngroups =3D cr->cr_ngroups;
-	bcopy(cr->cr_groups, ugp->fw_groups, sizeof(ugp->fw_groups));
-}
-
 static int
 check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
     struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,
-    u_int16_t src_port, struct ip_fw_ugid *ugp, int *ugid_lookupp,
+    u_int16_t src_port, struct ucred **uc, int *ugid_lookupp,
     struct inpcb *inp)
 {
 	INIT_VNET_INET(curvnet);
@@ -2032,7 +2007,6 @@
 	int wildcard;
 	struct inpcb *pcb;
 	int match;
-	gid_t *gp;
=20
 	/*
 	 * Check to see if the UDP or TCP stack supplied us with
@@ -2042,7 +2016,7 @@
 	if (inp && *ugid_lookupp =3D=3D 0) {
 		INP_LOCK_ASSERT(inp);
 		if (inp->inp_socket !=3D NULL) {
-			fill_ugid_cache(inp, ugp);
+			*uc =3D crhold(inp->inp_cred);
 			*ugid_lookupp =3D 1;
 		} else
 			*ugid_lookupp =3D -1;
@@ -2075,7 +2049,7 @@
 				dst_ip, htons(dst_port),
 				wildcard, NULL);
 		if (pcb !=3D NULL) {
-			fill_ugid_cache(pcb, ugp);
+			*uc =3D crhold(inp->inp_cred);
 			*ugid_lookupp =3D 1;
 		}
 		INP_INFO_RUNLOCK(pi);
@@ -2091,16 +2065,11 @@
 		}
 	}=20
 	if (insn->o.opcode =3D=3D O_UID)
-		match =3D (ugp->fw_uid =3D=3D (uid_t)insn->d[0]);
-	else if (insn->o.opcode =3D=3D O_GID) {
-		for (gp =3D ugp->fw_groups;
-			gp < &ugp->fw_groups[ugp->fw_ngroups]; gp++)
-			if (*gp =3D=3D (gid_t)insn->d[0]) {
-				match =3D 1;
-				break;
-			}
-	} else if (insn->o.opcode =3D=3D O_JAIL)
-		match =3D (ugp->fw_prid =3D=3D (int)insn->d[0]);
+		match =3D ((*uc)->cr_uid =3D=3D (uid_t)insn->d[0]);
+	else if (insn->o.opcode =3D=3D O_GID)
+		match =3D groupmember((gid_t)insn->d[0], *uc);
+	else if (insn->o.opcode =3D=3D O_JAIL)
+		match =3D ((*uc)->cr_prison->pr_id =3D=3D (int)insn->d[0]);
 	return match;
 }
=20
@@ -2178,8 +2147,8 @@
 	 * these types of constraints, as well as decrease contention
 	 * on pcb related locks.
 	 */
-	struct ip_fw_ugid fw_ugid_cache;
-	int ugid_lookup =3D 0;
+	struct ucred *ucred_cache =3D NULL;
+	int ucred_lookup =3D 0;
=20
 	/*
 	 * divinput_flags	If non-zero, set to the IP_FW_DIVERT_*_FLAG
@@ -2641,8 +2610,8 @@
 						    (ipfw_insn_u32 *)cmd,
 						    proto, oif,
 						    dst_ip, dst_port,
-						    src_ip, src_port, &fw_ugid_cache,
-						    &ugid_lookup, args->inp);
+						    src_ip, src_port, &ucred_cache,
+						    &ucred_lookup, args->inp);
 				break;
=20
 			case O_RECV:
@@ -3270,6 +3239,8 @@
 					/* XXX statistic */
 					/* drop packet */
 					IPFW_RUNLOCK(chain);
+					if (ucred_cache !=3D NULL)
+						crfree(ucred_cache);
 					return (IP_FW_DENY);
 				}
 				dt =3D (struct divert_tag *)(mtag+1);
@@ -3475,6 +3446,8 @@
 	}		/* end of outer for, scan rules */
 	printf("ipfw: ouch!, skip past end of rules, denying packet\n");
 	IPFW_RUNLOCK(chain);
+	if (ucred_cache !=3D NULL)
+		crfree(ucred_cache);
 	return (IP_FW_DENY);
=20
 done:
@@ -3483,6 +3456,8 @@
 	f->bcnt +=3D pktlen;
 	f->timestamp =3D time_uptime;
 	IPFW_RUNLOCK(chain);
+	if (ucred_cache !=3D NULL)
+		crfree(ucred_cache);
 	return (retval);
=20
 pullup_failed:
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/nfsserver/nfs_srvsock.c ./sys/n=
fsserver/nfs_srvsock.c
--- /usr/fsvn/head/sys/nfsserver/nfs_srvsock.c	2009-06-16 15:54:40.00000000=
0 -0500
+++ ./sys/nfsserver/nfs_srvsock.c	2009-06-09 08:49:37.000000000 -0500
@@ -370,11 +370,11 @@
 		}
 		tl =3D nfsm_dissect_nonblock(u_int32_t *, (len + 2) * NFSX_UNSIGNED);
 		for (i =3D 1; i <=3D len; i++)
-		    if (i < NGROUPS)
+		    if (i < XU_NGROUPS)
 			nd->nd_cr->cr_groups[i] =3D fxdr_unsigned(gid_t, *tl++);
 		    else
 			tl++;
-		nd->nd_cr->cr_ngroups =3D (len >=3D NGROUPS) ? NGROUPS : (len + 1);
+		nd->nd_cr->cr_ngroups =3D MIN(XU_NGROUPS, len + 1);
 		if (nd->nd_cr->cr_ngroups > 1)
 		    nfsrvw_sort(nd->nd_cr->cr_groups, nd->nd_cr->cr_ngroups);
 		len =3D fxdr_unsigned(int, *++tl);
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/nfsserver/nfs_srvsubs.c ./sys/n=
fsserver/nfs_srvsubs.c
--- /usr/fsvn/head/sys/nfsserver/nfs_srvsubs.c	2009-05-29 12:48:04.00000000=
0 -0500
+++ ./sys/nfsserver/nfs_srvsubs.c	2009-06-05 15:33:54.000000000 -0500
@@ -1181,9 +1181,7 @@
 	cred =3D nfsd->nd_cr;
 	if (cred->cr_uid =3D=3D 0 || (exflags & MNT_EXPORTANON)) {
 		cred->cr_uid =3D credanon->cr_uid;
-		for (i =3D 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
-			cred->cr_groups[i] =3D credanon->cr_groups[i];
-		cred->cr_ngroups =3D i;
+		crsetgroups(cred, credanon->cr_ngroups, credanon->cr_groups);
 	}
 	if (exflags & MNT_EXRDONLY)
 		*rdonlyp =3D 1;
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c=
 ./sys/rpc/rpcsec_gss/svc_rpcsec_gss.c
--- /usr/fsvn/head/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c	2009-06-16 13:55:57.=
000000000 -0500
+++ ./sys/rpc/rpcsec_gss/svc_rpcsec_gss.c	2009-06-16 13:56:18.000000000 -05=
00
@@ -449,11 +449,7 @@
 	cr =3D client->cl_cred =3D crget();
 	cr->cr_uid =3D cr->cr_ruid =3D cr->cr_svuid =3D uc->uid;
 	cr->cr_rgid =3D cr->cr_svgid =3D uc->gid;
-	cr->cr_ngroups =3D uc->gidlen;
-	if (cr->cr_ngroups > NGROUPS)
-		cr->cr_ngroups =3D NGROUPS;
-	for (i =3D 0; i < cr->cr_ngroups; i++)
-		cr->cr_groups[i] =3D uc->gidlist[i];
+	crsetgroups(cr, uc->gidlen, uc->gidlist);
 	*crp =3D crhold(cr);
=20
 	return (TRUE);
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/rpc/svc_auth.c ./sys/rpc/svc_au=
th.c
--- /usr/fsvn/head/sys/rpc/svc_auth.c	2009-06-12 00:52:17.000000000 -0500
+++ ./sys/rpc/svc_auth.c	2009-06-12 01:13:12.000000000 -0500
@@ -166,7 +166,7 @@
 svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp)
 {
 	struct ucred *cr =3D NULL;
-	int flavor, i;
+	int flavor;
 	struct xucred *xcr;
=20
 	flavor =3D rqst->rq_cred.oa_flavor;
@@ -178,9 +178,7 @@
 		xcr =3D (struct xucred *) rqst->rq_clntcred;
 		cr =3D crget();
 		cr->cr_uid =3D cr->cr_ruid =3D cr->cr_svuid =3D xcr->cr_uid;
-		cr->cr_ngroups =3D xcr->cr_ngroups;
-		for (i =3D 0; i < xcr->cr_ngroups; i++)
-			cr->cr_groups[i] =3D xcr->cr_groups[i];
+		crsetgroups(cr, xcr->cr_ngroups, xcr->cr_groups);
 		cr->cr_rgid =3D cr->cr_svgid =3D cr->cr_groups[0];
 		cr->cr_prison =3D &prison0;
 		prison_hold(cr->cr_prison);
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/rpc/svc_auth_unix.c ./sys/rpc/s=
vc_auth_unix.c
--- /usr/fsvn/head/sys/rpc/svc_auth_unix.c	2009-01-22 10:05:57.000000000 -0=
600
+++ ./sys/rpc/svc_auth_unix.c	2009-06-09 08:49:37.000000000 -0500
@@ -95,13 +95,13 @@
 			goto done;
 		}
 		for (i =3D 0; i < gid_len; i++) {
-			if (i + 1 < NGROUPS)
+			if (i + 1 < XU_NGROUPS)
 				xcr->cr_groups[i + 1] =3D IXDR_GET_INT32(buf);
 			else
 				buf++;
 		}
-		if (gid_len + 1 > NGROUPS)
-			xcr->cr_ngroups =3D NGROUPS;
+		if (gid_len + 1 > XU_NGROUPS)
+			xcr->cr_ngroups =3D XU_NGROUPS;
 		else
 			xcr->cr_ngroups =3D gid_len + 1;
=20
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/sys/param.h ./sys/sys/param.h
--- /usr/fsvn/head/sys/sys/param.h	2009-06-16 13:55:59.000000000 -0500
+++ ./sys/sys/param.h	2009-06-16 13:56:20.000000000 -0500
@@ -77,7 +77,7 @@
 #define	MAXLOGNAME	17		/* max login name length (incl. NUL) */
 #define	MAXUPRC		CHILD_MAX	/* max simultaneous processes */
 #define	NCARGS		ARG_MAX		/* max bytes for an exec function */
-#define	NGROUPS		NGROUPS_MAX	/* max number groups */
+#define	NGROUPS		NGROUPS_MAX+1	/* max number groups */
 #define	NOFILE		OPEN_MAX	/* max open files per process */
 #define	NOGROUP		65535		/* marker for empty group set member */
 #define MAXHOSTNAMELEN	256		/* max hostname size */
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/sys/syslimits.h ./sys/sys/sysli=
mits.h
--- /usr/fsvn/head/sys/sys/syslimits.h	2009-01-22 10:06:22.000000000 -0600
+++ ./sys/sys/syslimits.h	2009-06-08 23:57:36.000000000 -0500
@@ -54,7 +54,9 @@
 #define	MAX_CANON		  255	/* max bytes in term canon input line */
 #define	MAX_INPUT		  255	/* max bytes in terminal input */
 #define	NAME_MAX		  255	/* max bytes in a file name */
-#define	NGROUPS_MAX		   16	/* max supplemental group id's */
+#ifndef NGROUPS_MAX
+#define	NGROUPS_MAX	 	 1023	/* max supplemental group id's */
+#endif
 #ifndef OPEN_MAX
 #define	OPEN_MAX		   64	/* max open files per process */
 #endif
--- /usr/fsvn/head/sys/sys/ucred.h	2009-06-16 15:54:53.000000000 -0500
+++ ./sys/sys/ucred.h	2009-06-17 18:23:49.000000000 -0500
@@ -48,8 +48,7 @@
 	uid_t	cr_uid;			/* effective user id */
 	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 */
+	int	cr_ngroups;		/* number of groups */
 	gid_t	cr_rgid;		/* real group id */
 	gid_t	cr_svgid;		/* saved group id */
 	struct uidinfo	*cr_uidinfo;	/* per euid resource consumption */
@@ -61,11 +60,15 @@
 #define	cr_endcopy	cr_label
 	struct label	*cr_label;	/* MAC label */
 	struct auditinfo_addr	cr_audit;	/* Audit properties. */
+	gid_t	*cr_groups;		/* groups */
+	int	cr_agroups;		/* Available groups */
 };
 #define	NOCRED	((struct ucred *)0)	/* no credential available */
 #define	FSCRED	((struct ucred *)-1)	/* filesystem credential */
 #endif /* _KERNEL || _WANT_UCRED */
=20
+#define	XU_NGROUPS	16
+
 /*
  * This is the external representation of struct ucred.
  */
@@ -73,7 +76,7 @@
 	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
@@ -82,6 +85,7 @@
 #define	cr_gid cr_groups[0]
=20
 #ifdef _KERNEL
+struct proc;
 struct thread;
=20
 void	change_egid(struct ucred *newcred, gid_t egid);
@@ -91,6 +95,7 @@
 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 *p, struct ucred *cr);
 struct ucred	*crdup(struct ucred *cr);
 void	cred_update_thread(struct thread *td);
 void	crfree(struct ucred *cr);
@@ -98,6 +103,7 @@
 struct ucred	*crhold(struct ucred *cr);
 int	crshared(struct ucred *cr);
 void	cru2x(struct ucred *cr, struct xucred *xcr);
+void	crsetgroups(struct ucred *cr, int n, gid_t *groups);
 int	groupmember(gid_t gid, struct ucred *cred);
 #endif /* _KERNEL */
=20
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/sys/user.h ./sys/sys/user.h
--- /usr/fsvn/head/sys/sys/user.h	2009-06-16 15:54:53.000000000 -0500
+++ ./sys/sys/user.h	2009-06-05 16:02:34.000000000 -0500
@@ -85,7 +85,7 @@
  */
 #define	KI_NSPARE_INT	9
 #define	KI_NSPARE_LONG	12
-#define	KI_NSPARE_PTR	7
+#define	KI_NSPARE_PTR	6
=20
 #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 */
=20
 struct kinfo_proc {
@@ -151,7 +150,7 @@
 	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 */
@@ -201,6 +200,7 @@
 	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.
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/sys/ufs/ufs/ufs_vnops.c ./sys/ufs/u=
fs/ufs_vnops.c
--- /usr/fsvn/head/sys/ufs/ufs/ufs_vnops.c	2009-06-16 13:55:57.000000000 -0=
500
+++ ./sys/ufs/ufs/ufs_vnops.c	2009-06-16 13:56:20.000000000 -0500
@@ -2266,6 +2266,7 @@
 	{
 #ifdef QUOTA
 		struct ucred ucred, *ucp;
+		gid_t ucred_group;
 		ucp =3D cnp->cn_cred;
 #endif
 		/*
@@ -2292,6 +2293,7 @@
 			refcount_init(&ucred.cr_ref, 1);
 			ucred.cr_uid =3D ip->i_uid;
 			ucred.cr_ngroups =3D 1;
+			ucred.cr_groups =3D &ucred_group;
 			ucred.cr_groups[0] =3D pdir->i_gid;
 			ucp =3D &ucred;
 #endif
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.sbin/mount_portalfs/portald.h .=
/usr.sbin/mount_portalfs/portald.h
--- /usr/fsvn/head/usr.sbin/mount_portalfs/portald.h	2009-01-22 10:05:31.00=
0000000 -0600
+++ ./usr.sbin/mount_portalfs/portald.h	2009-06-17 13:41:26.000000000 -0500
@@ -36,6 +36,7 @@
  */
=20
 #include <sys/cdefs.h>
+#include <sys/ucred.h>
 #include <fs/portalfs/portal.h>
=20
 /*
diff -ru --exclude=3D.svn --exclude=3Dcompile --exclude=3Dcardbus.c --ignor=
e-matching=3D'$FreeBSD:' /usr/fsvn/head/usr.sbin/mountd/mountd.c ./usr.sbin=
/mountd/mountd.c
--- /usr/fsvn/head/usr.sbin/mountd/mountd.c	2009-06-16 15:54:05.000000000 -=
0500
+++ ./usr.sbin/mountd/mountd.c	2009-06-17 15:25:33.000000000 -0500
@@ -2644,7 +2644,7 @@
 	char *names;
 	struct passwd *pw;
 	struct group *gr;
-	gid_t groups[NGROUPS + 1];
+	gid_t groups[XU_NGROUPS + 1];
 	int ngroups;
=20
 	cr->cr_version =3D XUCRED_VERSION;
@@ -2672,7 +2672,7 @@
 			return;
 		}
 		cr->cr_uid =3D pw->pw_uid;
-		ngroups =3D NGROUPS + 1;
+		ngroups =3D XU_NGROUPS + 1;
 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
 			syslog(LOG_ERR, "too many groups");
 		/*
@@ -2697,7 +2697,7 @@
 		return;
 	}
 	cr->cr_ngroups =3D 0;
-	while (names !=3D NULL && *names !=3D '\0' && cr->cr_ngroups < NGROUPS) {
+	while (names !=3D NULL && *names !=3D '\0' && cr->cr_ngroups < XU_NGROUPS=
) {
 		name =3D strsep(&names, ":");
 		if (isdigit(*name) || *name =3D=3D '-') {
 			cr->cr_groups[cr->cr_ngroups++] =3D atoi(name);
@@ -2709,7 +2709,7 @@
 			cr->cr_groups[cr->cr_ngroups++] =3D gr->gr_gid;
 		}
 	}
-	if (names !=3D NULL && *names !=3D '\0' && cr->cr_ngroups =3D=3D NGROUPS)
+	if (names !=3D NULL && *names !=3D '\0' && cr->cr_ngroups =3D=3D XU_NGROU=
PS)
 		syslog(LOG_ERR, "too many groups");
 }
=20

--YZ5djTAD1cGYuMQK--

--O5XBE6gyVG5Rl6Rj
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (FreeBSD)

iD8DBQFKOYTKXY6L6fI4GtQRAoiYAJ9BzCBNbP/75Un8IE0lnANi+vLzcACgvb3y
Qn1aK6Ca1A8ZeOXWFkULVJo=
=wA9V
-----END PGP SIGNATURE-----

--O5XBE6gyVG5Rl6Rj--



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