kern/133867: commit references a PR

dfilter service dfilter at FreeBSD.ORG
Fri Jun 19 17:20:05 UTC 2009


The following reply was made to PR kern/133867; it has been noted by GNATS.

From: dfilter at FreeBSD.ORG (dfilter service)
To: bug-followup at FreeBSD.org
Cc:  
Subject: Re: kern/133867: commit references a PR
Date: Fri, 19 Jun 2009 17:10:53 +0000 (UTC)

 Author: brooks
 Date: Fri Jun 19 17:10:35 2009
 New Revision: 194498
 URL: http://svn.freebsd.org/changeset/base/194498
 
 Log:
   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.)
   
   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.
   
   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.
   
   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.
   
   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.
   
   Submitted by:	Isilon Systems (initial implementation)
   X-MFC after:	never
   PR:		bin/113398 kern/133867
 
 Modified:
   head/UPDATING
   head/lib/libc/rpc/netname.c
   head/lib/libc/rpc/netnamer.c
   head/lib/libkvm/kvm_proc.c
   head/sys/compat/linux/linux_misc.c
   head/sys/compat/linux/linux_uid16.c
   head/sys/fs/nfs/nfs_commonport.c
   head/sys/fs/nfsclient/nfs_clport.c
   head/sys/fs/nfsserver/nfs_nfsdport.c
   head/sys/fs/nfsserver/nfs_nfsdstate.c
   head/sys/fs/portalfs/portal.h
   head/sys/fs/portalfs/portal_vnops.c
   head/sys/fs/unionfs/union_vnops.c
   head/sys/i386/ibcs2/ibcs2_misc.c
   head/sys/kern/kern_exec.c
   head/sys/kern/kern_proc.c
   head/sys/kern/kern_prot.c
   head/sys/kern/vfs_export.c
   head/sys/netinet/ipfw/ip_fw2.c
   head/sys/nfsserver/nfs_srvsock.c
   head/sys/nfsserver/nfs_srvsubs.c
   head/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c
   head/sys/rpc/svc_auth.c
   head/sys/rpc/svc_auth_unix.c
   head/sys/sys/param.h
   head/sys/sys/syslimits.h
   head/sys/sys/ucred.h
   head/sys/sys/user.h
   head/sys/ufs/ufs/ufs_vnops.c
   head/usr.sbin/mount_portalfs/portald.h
   head/usr.sbin/mountd/mountd.c
 
 Modified: head/UPDATING
 ==============================================================================
 --- head/UPDATING	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/UPDATING	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -22,6 +22,23 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 8.
  	to maximize performance.  (To disable malloc debugging, run
  	ln -s aj /etc/malloc.conf.)
  
 +20090619:
 +	NGROUPS_MAX and NGROUPS have been increased from 16 to 1023
 +	and 1024 respectively.  As long as no more than 16 groups per
 +	process are used, no changes should be visible.  When more
 +	than 16 groups are used, old binaries may fail if they call
 +	getgroups() or getgrouplist() with statically sized storage.
 +	Recompiling will work around this, but applications should be
 +	modified to use dynamically allocated storage for group arrays
 +	as POSIX.1-2008 does not cap an implementation's number of
 +	supported groups at NGROUPS_MAX+1 as previous versions did.
 +
 +	NFS and portalfs mounts may also be affected as the list of
 +	groups is truncated to 16.  Users of NFS who use more than 16
 +	groups, should take care that negative group permissions are not
 +	used on the exported file systems as they will not be reliable
 +	unless a GSSAPI based authentication method is used.
 +
  20090616:
  	The compiling option ADAPTIVE_LOCKMGRS has been introduced.
  	This option compiles in the support for adaptive spinning for lockmgrs
 
 Modified: head/lib/libc/rpc/netname.c
 ==============================================================================
 --- head/lib/libc/rpc/netname.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/lib/libc/rpc/netname.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -61,9 +61,6 @@ __FBSDID("$FreeBSD$");
  #ifndef MAXHOSTNAMELEN
  #define MAXHOSTNAMELEN 256
  #endif
 -#ifndef NGROUPS
 -#define NGROUPS 16
 -#endif
  
  #define TYPE_BIT(type)  (sizeof (type) * CHAR_BIT)
  
 
 Modified: head/lib/libc/rpc/netnamer.c
 ==============================================================================
 --- head/lib/libc/rpc/netnamer.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/lib/libc/rpc/netnamer.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -66,10 +66,6 @@ static char    *NETIDFILE = "/etc/netid"
  static int getnetid( char *, char * );
  static int _getgroups( char *, gid_t * );
  
 -#ifndef NGROUPS
 -#define NGROUPS 16
 -#endif
 -
  /*
   * Convert network-name into unix credential
   */
 @@ -104,7 +100,7 @@ netname2user(netname, uidp, gidp, gidlen
  			return (0);
  		}
  		*gidp = (gid_t) atol(p);
 -		for (gidlen = 0; gidlen < NGROUPS; gidlen++) {
 +		for (gidlen = 0; gidlen < NGRPS; gidlen++) {
  			p = strsep(&res, "\n,");
  			if (p == NULL)
  				break;
 @@ -157,7 +153,7 @@ netname2user(netname, uidp, gidp, gidlen
  static int
  _getgroups(uname, groups)
  	char           *uname;
 -	gid_t          groups[NGROUPS];
 +	gid_t          groups[NGRPS];
  {
  	gid_t           ngroups = 0;
  	struct group *grp;
 @@ -169,7 +165,7 @@ _getgroups(uname, groups)
  	while ((grp = getgrent())) {
  		for (i = 0; grp->gr_mem[i]; i++)
  			if (!strcmp(grp->gr_mem[i], uname)) {
 -				if (ngroups == NGROUPS) {
 +				if (ngroups == NGRPS) {
  #ifdef DEBUG
  					fprintf(stderr,
  				"initgroups: %s is in too many groups\n", uname);
 
 Modified: head/lib/libkvm/kvm_proc.c
 ==============================================================================
 --- head/lib/libkvm/kvm_proc.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/lib/libkvm/kvm_proc.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -146,8 +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 * 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: head/sys/compat/linux/linux_misc.c
 ==============================================================================
 --- head/sys/compat/linux/linux_misc.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/compat/linux/linux_misc.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -1132,7 +1132,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;
 @@ -1140,13 +1140,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
 @@ -1157,10 +1158,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;
  
 @@ -1177,14 +1177,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;
  
 @@ -1207,13 +1210,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: head/sys/compat/linux/linux_uid16.c
 ==============================================================================
 --- head/sys/compat/linux/linux_uid16.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/compat/linux/linux_uid16.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -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: head/sys/fs/nfs/nfs_commonport.c
 ==============================================================================
 --- head/sys/fs/nfs/nfs_commonport.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/fs/nfs/nfs_commonport.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -220,14 +220,9 @@ nfsrv_lookupfilename(struct nameidata *n
  void
  newnfs_copycred(struct nfscred *nfscr, struct ucred *cr)
  {
 -	int ngroups, i;
  
  	cr->cr_uid = nfscr->nfsc_uid;
 -	ngroups = (nfscr->nfsc_ngroups < NGROUPS) ?
 -	    nfscr->nfsc_ngroups : NGROUPS;
 -	for (i = 0; i < ngroups; i++)
 -		cr->cr_groups[i] = nfscr->nfsc_groups[i];
 -	cr->cr_ngroups = ngroups;
 +	crsetgroups(cr, nfscr->nfsc_ngroups, nfscr->nfsc_groups);
  }
  
  /*
 
 Modified: head/sys/fs/nfsclient/nfs_clport.c
 ==============================================================================
 --- head/sys/fs/nfsclient/nfs_clport.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/fs/nfsclient/nfs_clport.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -976,14 +976,12 @@ nfscl_getmyip(struct nfsmount *nmp, int 
  void
  newnfs_copyincred(struct ucred *cr, struct nfscred *nfscr)
  {
 -	int ngroups, i;
 +	int i;
  
  	nfscr->nfsc_uid = cr->cr_uid;
 -	ngroups = (cr->cr_ngroups > NGROUPS) ? NGROUPS :
 -	    cr->cr_ngroups;
 -	for (i = 0; i < ngroups; i++)
 +	nfscr->nfsc_ngroups = MIN(cr->cr_ngroups, XU_NGROUPS);
 +	for (i = 0; i < nfscr->nfsc_ngroups; i++)
  		nfscr->nfsc_groups[i] = cr->cr_groups[i];
 -	nfscr->nfsc_ngroups = ngroups;
  }
  
  
 
 Modified: head/sys/fs/nfsserver/nfs_nfsdport.c
 ==============================================================================
 --- head/sys/fs/nfsserver/nfs_nfsdport.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/fs/nfsserver/nfs_nfsdport.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -2360,7 +2360,6 @@ int
  nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp,
      struct ucred *credanon)
  {
 -	int i;
  	int error = 0;
  
  	/*
 @@ -2403,9 +2402,8 @@ nfsd_excred(struct nfsrv_descript *nd, s
  	     (nd->nd_flag & ND_AUTHNONE))) {
  		nd->nd_cred->cr_uid = credanon->cr_uid;
  		nd->nd_cred->cr_gid = credanon->cr_gid;
 -		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
 -			nd->nd_cred->cr_groups[i] = credanon->cr_groups[i];
 -		nd->nd_cred->cr_ngroups = i;
 +		crsetgroups(nd->nd_cred, credanon->cr_ngroups,
 +		    credanon->cr_groups);
  	}
  	return (0);
  }
 
 Modified: head/sys/fs/nfsserver/nfs_nfsdstate.c
 ==============================================================================
 --- head/sys/fs/nfsserver/nfs_nfsdstate.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/fs/nfsserver/nfs_nfsdstate.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -3577,7 +3577,6 @@ nfsrv_docallback(struct nfsclient *clp, 
  	nd->nd_repstat = 0;
  	cred->cr_uid = clp->lc_uid;
  	cred->cr_gid = clp->lc_gid;
 -	cred->cr_groups[0] = clp->lc_gid;
  	callback = clp->lc_callback;
  	NFSUNLOCKSTATE();
  	cred->cr_ngroups = 1;
 
 Modified: head/sys/fs/portalfs/portal.h
 ==============================================================================
 --- head/sys/fs/portalfs/portal.h	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/fs/portalfs/portal.h	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -43,7 +43,7 @@ struct portal_cred {
  	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 */
  };
  
  #ifdef _KERNEL
 
 Modified: head/sys/fs/portalfs/portal_vnops.c
 ==============================================================================
 --- head/sys/fs/portalfs/portal_vnops.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/fs/portalfs/portal_vnops.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -311,8 +311,9 @@ portal_open(ap)
  
  	pcred.pcr_flag = ap->a_mode;
  	pcred.pcr_uid = ap->a_cred->cr_uid;
 -	pcred.pcr_ngroups = ap->a_cred->cr_ngroups;
 -	bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
 +	pcred.pcr_ngroups = 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 = (caddr_t) &pcred;
  	aiov[0].iov_len = sizeof(pcred);
  	aiov[1].iov_base = pt->pt_arg;
 
 Modified: head/sys/fs/unionfs/union_vnops.c
 ==============================================================================
 --- head/sys/fs/unionfs/union_vnops.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/fs/unionfs/union_vnops.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -638,7 +638,6 @@ unionfs_check_corrected_access(accmode_t
  	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;
  
  	mask = 0;
 @@ -659,17 +658,14 @@ unionfs_check_corrected_access(accmode_t
  
  	/* check group */
  	count = 0;
 -	gp = cred->cr_groups;
 -	for (; count < cred->cr_ngroups; count++, gp++) {
 -		if (gid == *gp) {
 -			if (accmode & VEXEC)
 -				mask |= S_IXGRP;
 -			if (accmode & VREAD)
 -				mask |= S_IRGRP;
 -			if (accmode & VWRITE)
 -				mask |= S_IWGRP;
 -			return ((vmode & mask) == mask ? 0 : EACCES);
 -		}
 +	if (groupmember(gid, cred)) {
 +		if (accmode & VEXEC)
 +			mask |= S_IXGRP;
 +		if (accmode & VREAD)
 +			mask |= S_IRGRP;
 +		if (accmode & VWRITE)
 +			mask |= S_IWGRP;
 +		return ((vmode & mask) == mask ? 0 : EACCES);
  	}
  
  	/* check other */
 
 Modified: head/sys/i386/ibcs2/ibcs2_misc.c
 ==============================================================================
 --- head/sys/i386/ibcs2/ibcs2_misc.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/i386/ibcs2/ibcs2_misc.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -657,24 +657,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);
  }
  
 @@ -683,21 +688,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: head/sys/kern/kern_exec.c
 ==============================================================================
 --- head/sys/kern/kern_exec.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/kern/kern_exec.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -579,6 +579,7 @@ interpret:
  	 * reset.
  	 */
  	PROC_LOCK(p);
 +	oldcred = crcopysafe(p, newcred);
  	if (sigacts_shared(p->p_sigacts)) {
  		oldsigacts = p->p_sigacts;
  		PROC_UNLOCK(p);
 @@ -629,7 +630,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;
 @@ -683,7 +683,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)
 @@ -723,7 +722,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: head/sys/kern/kern_proc.c
 ==============================================================================
 --- head/sys/kern/kern_proc.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/kern/kern_proc.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -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;
  		kp->ki_cr_flags = cred->cr_flags;
 
 Modified: head/sys/kern/kern_prot.c
 ==============================================================================
 --- head/sys/kern/kern_prot.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/kern/kern_prot.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -82,6 +82,11 @@ static MALLOC_DEFINE(M_CRED, "cred", "cr
  
  SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy");
  
 +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 +281,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 +494,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 +532,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 +605,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 +622,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 +660,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 +689,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 +758,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 +771,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 +796,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 +822,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 +836,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
 @@ -838,8 +845,7 @@ kern_setgroups(struct thread *td, u_int 
  		 */
  		newcred->cr_ngroups = 1;
  	} else {
 -		bcopy(groups, newcred->cr_groups, ngrp * sizeof(gid_t));
 -		newcred->cr_ngroups = ngrp;
 +		crsetgroups_locked(newcred, ngrp, groups);
  	}
  	setsugid(p);
  	p->p_ucred = newcred;
 @@ -877,7 +883,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 +898,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 +947,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 +962,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 +1017,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 +1037,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 +1093,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 +1113,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);
 @@ -1780,6 +1782,7 @@ crget(void)
  #ifdef MAC
  	mac_cred_init(cr);
  #endif
 +	crextend(cr, XU_NGROUPS);
  	return (cr);
  }
  
 @@ -1829,6 +1832,7 @@ crfree(struct ucred *cr)
  #ifdef MAC
  		mac_cred_destroy(cr);
  #endif
 +		free(cr->cr_groups, M_CRED);
  		free(cr, M_CRED);
  	}
  }
 @@ -1854,6 +1858,7 @@ crcopy(struct ucred *dest, struct ucred 
  	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 +1893,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));
  }
  
  /*
 @@ -1915,6 +1924,97 @@ 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.
 + */
 +static 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 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 == 0)
 +			cnt = MINALLOCSIZE / sizeof(gid_t);
 +		else
 +			cnt = cr->cr_agroups * 2;
 +
 +		while (cnt < n)
 +			cnt *= 2;
 +	} else
 +		cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t));
 +
 +	/* 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;
 +}
 +
 +/*
 + * 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 
 + */
 +static void
 +crsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups)
 +{
 +	
 +	KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small"));
 +
 +	bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
 +	cr->cr_ngroups = 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 = NGROUPS;
 +
 +	crextend(cr, ngrp);
 +	crsetgroups_locked(cr, ngrp, groups);
 +}
 +
  /*
   * Get login name, if available.
   */
 
 Modified: head/sys/kern/vfs_export.c
 ==============================================================================
 --- head/sys/kern/vfs_export.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/kern/vfs_export.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -120,9 +120,8 @@ vfs_hang_addrlist(struct mount *mp, stru
  		np->netc_exflags = argp->ex_flags;
  		np->netc_anon = crget();
  		np->netc_anon->cr_uid = argp->ex_anon.cr_uid;
 -		np->netc_anon->cr_ngroups = 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 = argp->ex_numsecflavors;
  		bcopy(argp->ex_secflavors, np->netc_secflavors,
  		    sizeof(np->netc_secflavors));
 @@ -205,9 +204,8 @@ vfs_hang_addrlist(struct mount *mp, stru
  	np->netc_exflags = argp->ex_flags;
  	np->netc_anon = crget();
  	np->netc_anon->cr_uid = argp->ex_anon.cr_uid;
 -	np->netc_anon->cr_ngroups = 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 = argp->ex_numsecflavors;
  	bcopy(argp->ex_secflavors, np->netc_secflavors,
  	    sizeof(np->netc_secflavors));
 
 Modified: head/sys/netinet/ipfw/ip_fw2.c
 ==============================================================================
 --- head/sys/netinet/ipfw/ip_fw2.c	Fri Jun 19 17:07:38 2009	(r194497)
 +++ head/sys/netinet/ipfw/ip_fw2.c	Fri Jun 19 17:10:35 2009	(r194498)
 @@ -135,19 +135,6 @@ static uma_zone_t ipfw_dyn_rule_zone;
  struct ip_fw *ip_fw_default_rule;
  
  /*
 - * 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 @@ dump_table(struct ip_fw_chain *ch, ipfw_
  	return (0);
  }
  
 -static void
 -fill_ugid_cache(struct inpcb *inp, struct ip_fw_ugid *ugp)
 -{
 -	struct ucred *cr;
 -
 -	cr = inp->inp_cred;
 -	ugp->fw_prid = jailed(cr) ? cr->cr_prison->pr_id : -1;
 -	ugp->fw_uid = cr->cr_uid;
 -	ugp->fw_ngroups = 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 @@ check_uidgid(ipfw_insn_u32 *insn, int pr
  	int wildcard;
  	struct inpcb *pcb;
  	int match;
 -	gid_t *gp;
  
  	/*
  	 * Check to see if the UDP or TCP stack supplied us with
 @@ -2042,7 +2016,7 @@ check_uidgid(ipfw_insn_u32 *insn, int pr
  	if (inp && *ugid_lookupp == 0) {
  		INP_LOCK_ASSERT(inp);
  		if (inp->inp_socket != NULL) {
 -			fill_ugid_cache(inp, ugp);
 +			*uc = crhold(inp->inp_cred);
  			*ugid_lookupp = 1;
  		} else
  			*ugid_lookupp = -1;
 @@ -2075,7 +2049,7 @@ check_uidgid(ipfw_insn_u32 *insn, int pr
  				dst_ip, htons(dst_port),
  				wildcard, NULL);
  		if (pcb != NULL) {
 -			fill_ugid_cache(pcb, ugp);
 +			*uc = crhold(inp->inp_cred);
  			*ugid_lookupp = 1;
  		}
  		INP_INFO_RUNLOCK(pi);
 @@ -2091,16 +2065,11 @@ check_uidgid(ipfw_insn_u32 *insn, int pr
  		}
  	} 
  	if (insn->o.opcode == O_UID)
 -		match = (ugp->fw_uid == (uid_t)insn->d[0]);
 -	else if (insn->o.opcode == O_GID) {
 -		for (gp = ugp->fw_groups;
 -			gp < &ugp->fw_groups[ugp->fw_ngroups]; gp++)
 -			if (*gp == (gid_t)insn->d[0]) {
 -				match = 1;
 -				break;
 -			}
 -	} else if (insn->o.opcode == O_JAIL)
 -		match = (ugp->fw_prid == (int)insn->d[0]);
 +		match = ((*uc)->cr_uid == (uid_t)insn->d[0]);
 +	else if (insn->o.opcode == O_GID)
 +		match = groupmember((gid_t)insn->d[0], *uc);
 +	else if (insn->o.opcode == O_JAIL)
 +		match = ((*uc)->cr_prison->pr_id == (int)insn->d[0]);
  	return match;
  }
  
 @@ -2178,8 +2147,8 @@ ipfw_chk(struct ip_fw_args *args)
 
 *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
 _______________________________________________
 svn-src-all at freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe at freebsd.org"
 


More information about the freebsd-bugs mailing list