svn commit: r194498 - in head: . lib/libc/rpc lib/libkvm
sys/compat/linux sys/fs/nfs sys/fs/nfsclient sys/fs/nfsserver
sys/fs/portalfs sys/fs/unionfs sys/i386/ibcs2 sys/kern
sys/netinet/ipfw sys/nf...
Brooks Davis
brooks at FreeBSD.org
Fri Jun 19 17:10:37 UTC 2009
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 ***
More information about the svn-src-head
mailing list