summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorbrooks <brooks@FreeBSD.org>2009-06-19 17:10:35 +0000
committerbrooks <brooks@FreeBSD.org>2009-06-19 17:10:35 +0000
commitf53c1c309de799bd46cd12223b6f4966838f2e7a (patch)
tree851f3659dd95c07bf7aaf4a54cd53e83c804702d /sys
parent020220234336a0527c3a4eb5fe739a256bd31981 (diff)
downloadFreeBSD-src-f53c1c309de799bd46cd12223b6f4966838f2e7a.zip
FreeBSD-src-f53c1c309de799bd46cd12223b6f4966838f2e7a.tar.gz
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
Diffstat (limited to 'sys')
-rw-r--r--sys/compat/linux/linux_misc.c24
-rw-r--r--sys/compat/linux/linux_uid16.c18
-rw-r--r--sys/fs/nfs/nfs_commonport.c7
-rw-r--r--sys/fs/nfsclient/nfs_clport.c8
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c6
-rw-r--r--sys/fs/nfsserver/nfs_nfsdstate.c1
-rw-r--r--sys/fs/portalfs/portal.h2
-rw-r--r--sys/fs/portalfs/portal_vnops.c5
-rw-r--r--sys/fs/unionfs/union_vnops.c20
-rw-r--r--sys/i386/ibcs2/ibcs2_misc.c33
-rw-r--r--sys/kern/kern_exec.c4
-rw-r--r--sys/kern/kern_proc.c6
-rw-r--r--sys/kern/kern_prot.c170
-rw-r--r--sys/kern/vfs_export.c10
-rw-r--r--sys/netinet/ipfw/ip_fw2.c61
-rw-r--r--sys/nfsserver/nfs_srvsock.c4
-rw-r--r--sys/nfsserver/nfs_srvsubs.c4
-rw-r--r--sys/rpc/rpcsec_gss/svc_rpcsec_gss.c6
-rw-r--r--sys/rpc/svc_auth.c6
-rw-r--r--sys/rpc/svc_auth_unix.c6
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/syslimits.h4
-rw-r--r--sys/sys/ucred.h12
-rw-r--r--sys/sys/user.h6
-rw-r--r--sys/ufs/ufs/ufs_vnops.c2
25 files changed, 256 insertions, 171 deletions
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index 9595fed..267da07 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -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, struct linux_setgroups_args *args)
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, struct linux_setgroups_args *args)
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, struct linux_setgroups_args *args)
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, struct linux_getgroups_args *args)
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;
diff --git a/sys/compat/linux/linux_uid16.c b/sys/compat/linux/linux_uid16.c
index 2685eaa..b49bf78 100644
--- a/sys/compat/linux/linux_uid16.c
+++ b/sys/compat/linux/linux_uid16.c
@@ -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, struct linux_setgroups16_args *args)
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, struct linux_setgroups16_args *args)
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, struct linux_setgroups16_args *args)
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, struct linux_getgroups16_args *args)
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);
diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c
index 0369113..bf982aa 100644
--- a/sys/fs/nfs/nfs_commonport.c
+++ b/sys/fs/nfs/nfs_commonport.c
@@ -220,14 +220,9 @@ nfsrv_lookupfilename(struct nameidata *ndp, char *fname, NFSPROC_T *p)
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);
}
/*
diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c
index 3b5e367..5b747c7 100644
--- a/sys/fs/nfsclient/nfs_clport.c
+++ b/sys/fs/nfsclient/nfs_clport.c
@@ -976,14 +976,12 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
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;
}
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 730a750..8f5cc94 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -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, struct nfsexstuff *exp,
(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);
}
diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c
index 077ce2a..7794278 100644
--- a/sys/fs/nfsserver/nfs_nfsdstate.c
+++ b/sys/fs/nfsserver/nfs_nfsdstate.c
@@ -3577,7 +3577,6 @@ nfsrv_docallback(struct nfsclient *clp, int procnum,
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;
diff --git a/sys/fs/portalfs/portal.h b/sys/fs/portalfs/portal.h
index 6606ccc..1fd2d99 100644
--- a/sys/fs/portalfs/portal.h
+++ b/sys/fs/portalfs/portal.h
@@ -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
diff --git a/sys/fs/portalfs/portal_vnops.c b/sys/fs/portalfs/portal_vnops.c
index 8b49ad3..8d30ebb 100644
--- a/sys/fs/portalfs/portal_vnops.c
+++ b/sys/fs/portalfs/portal_vnops.c
@@ -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;
diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
index 8505cac..11671cb 100644
--- a/sys/fs/unionfs/union_vnops.c
+++ b/sys/fs/unionfs/union_vnops.c
@@ -638,7 +638,6 @@ unionfs_check_corrected_access(accmode_t accmode,
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 accmode,
/* 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 */
diff --git a/sys/i386/ibcs2/ibcs2_misc.c b/sys/i386/ibcs2/ibcs2_misc.c
index 1906fd7..17d8fe7 100644
--- a/sys/i386/ibcs2/ibcs2_misc.c
+++ b/sys/i386/ibcs2/ibcs2_misc.c
@@ -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
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 4e66c95..8e37dba 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -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;
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index 0ee630f..4e2ff7e 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -730,10 +730,8 @@ fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp)
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;
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index 5deff69..17cba9c 100644
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -82,6 +82,11 @@ static MALLOC_DEFINE(M_CRED, "cred", "credentials");
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_args *uap)
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_args *uap)
(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 seteuid_args *uap)
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 seteuid_args *uap)
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_args *uap)
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_args *uap)
(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 setegid_args *uap)
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 setegid_args *uap)
(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 ngrp, gid_t *groups)
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 ngrp, gid_t *groups)
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 ngrp, gid_t *groups)
*/
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, struct setreuid_args *uap)
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, struct setreuid_args *uap)
(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, struct setregid_args *uap)
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, struct setregid_args *uap)
(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, struct setresuid_args *uap)
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, struct setresuid_args *uap)
(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, struct setresgid_args *uap)
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, struct setresgid_args *uap)
(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 *src)
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.
*/
diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c
index 6ac4cc2..ee8a35b 100644
--- a/sys/kern/vfs_export.c
+++ b/sys/kern/vfs_export.c
@@ -120,9 +120,8 @@ vfs_hang_addrlist(struct mount *mp, struct netexport *nep,
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, struct netexport *nep,
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));
diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c
index 51518ff..6f5c956 100644
--- a/sys/netinet/ipfw/ip_fw2.c
+++ b/sys/netinet/ipfw/ip_fw2.c
@@ -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_table *tbl)
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 proto, struct ifnet *oif,
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 proto, struct ifnet *oif,
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 proto, struct ifnet *oif,
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 proto, struct ifnet *oif,
}
}
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)
* these types of constraints, as well as decrease contention
* on pcb related locks.
*/
- struct ip_fw_ugid fw_ugid_cache;
- int ugid_lookup = 0;
+ struct ucred *ucred_cache = NULL;
+ int ucred_lookup = 0;
/*
* divinput_flags If non-zero, set to the IP_FW_DIVERT_*_FLAG
@@ -2641,8 +2610,8 @@ check_body:
(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;
case O_RECV:
@@ -3270,6 +3239,8 @@ check_body:
/* XXX statistic */
/* drop packet */
IPFW_RUNLOCK(chain);
+ if (ucred_cache != NULL)
+ crfree(ucred_cache);
return (IP_FW_DENY);
}
dt = (struct divert_tag *)(mtag+1);
@@ -3475,6 +3446,8 @@ next_rule:; /* try next rule */
} /* end of outer for, scan rules */
printf("ipfw: ouch!, skip past end of rules, denying packet\n");
IPFW_RUNLOCK(chain);
+ if (ucred_cache != NULL)
+ crfree(ucred_cache);
return (IP_FW_DENY);
done:
@@ -3483,6 +3456,8 @@ done:
f->bcnt += pktlen;
f->timestamp = time_uptime;
IPFW_RUNLOCK(chain);
+ if (ucred_cache != NULL)
+ crfree(ucred_cache);
return (retval);
pullup_failed:
diff --git a/sys/nfsserver/nfs_srvsock.c b/sys/nfsserver/nfs_srvsock.c
index 13679ef..0bb4128 100644
--- a/sys/nfsserver/nfs_srvsock.c
+++ b/sys/nfsserver/nfs_srvsock.c
@@ -370,11 +370,11 @@ nfs_getreq(struct nfsrv_descript *nd, struct nfsd *nfsd, int has_header)
}
tl = nfsm_dissect_nonblock(u_int32_t *, (len + 2) * NFSX_UNSIGNED);
for (i = 1; i <= len; i++)
- if (i < NGROUPS)
+ if (i < XU_NGROUPS)
nd->nd_cr->cr_groups[i] = fxdr_unsigned(gid_t, *tl++);
else
tl++;
- nd->nd_cr->cr_ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1);
+ nd->nd_cr->cr_ngroups = 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 = fxdr_unsigned(int, *++tl);
diff --git a/sys/nfsserver/nfs_srvsubs.c b/sys/nfsserver/nfs_srvsubs.c
index 3f54664..87fda28 100644
--- a/sys/nfsserver/nfs_srvsubs.c
+++ b/sys/nfsserver/nfs_srvsubs.c
@@ -1181,9 +1181,7 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, int *vfslockedp,
cred = nfsd->nd_cr;
if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
cred->cr_uid = credanon->cr_uid;
- for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
- cred->cr_groups[i] = credanon->cr_groups[i];
- cred->cr_ngroups = i;
+ crsetgroups(cred, credanon->cr_ngroups, credanon->cr_groups);
}
if (exflags & MNT_EXRDONLY)
*rdonlyp = 1;
diff --git a/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c b/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c
index 9653c91..13fcce9 100644
--- a/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c
+++ b/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c
@@ -449,11 +449,7 @@ rpc_gss_svc_getcred(struct svc_req *req, struct ucred **crp, int *flavorp)
cr = client->cl_cred = crget();
cr->cr_uid = cr->cr_ruid = cr->cr_svuid = uc->uid;
cr->cr_rgid = cr->cr_svgid = uc->gid;
- cr->cr_ngroups = uc->gidlen;
- if (cr->cr_ngroups > NGROUPS)
- cr->cr_ngroups = NGROUPS;
- for (i = 0; i < cr->cr_ngroups; i++)
- cr->cr_groups[i] = uc->gidlist[i];
+ crsetgroups(cr, uc->gidlen, uc->gidlist);
*crp = crhold(cr);
return (TRUE);
diff --git a/sys/rpc/svc_auth.c b/sys/rpc/svc_auth.c
index 2d2b73d..5d83c8d 100644
--- a/sys/rpc/svc_auth.c
+++ b/sys/rpc/svc_auth.c
@@ -166,7 +166,7 @@ int
svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp)
{
struct ucred *cr = NULL;
- int flavor, i;
+ int flavor;
struct xucred *xcr;
flavor = rqst->rq_cred.oa_flavor;
@@ -178,9 +178,7 @@ svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp)
xcr = (struct xucred *) rqst->rq_clntcred;
cr = crget();
cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xcr->cr_uid;
- cr->cr_ngroups = xcr->cr_ngroups;
- for (i = 0; i < xcr->cr_ngroups; i++)
- cr->cr_groups[i] = xcr->cr_groups[i];
+ crsetgroups(cr, xcr->cr_ngroups, xcr->cr_groups);
cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
cr->cr_prison = &prison0;
prison_hold(cr->cr_prison);
diff --git a/sys/rpc/svc_auth_unix.c b/sys/rpc/svc_auth_unix.c
index 0c11a4a..19ff40a 100644
--- a/sys/rpc/svc_auth_unix.c
+++ b/sys/rpc/svc_auth_unix.c
@@ -95,13 +95,13 @@ _svcauth_unix(struct svc_req *rqst, struct rpc_msg *msg)
goto done;
}
for (i = 0; i < gid_len; i++) {
- if (i + 1 < NGROUPS)
+ if (i + 1 < XU_NGROUPS)
xcr->cr_groups[i + 1] = IXDR_GET_INT32(buf);
else
buf++;
}
- if (gid_len + 1 > NGROUPS)
- xcr->cr_ngroups = NGROUPS;
+ if (gid_len + 1 > XU_NGROUPS)
+ xcr->cr_ngroups = XU_NGROUPS;
else
xcr->cr_ngroups = gid_len + 1;
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 06ddf32..06745f8 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -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 --git a/sys/sys/syslimits.h b/sys/sys/syslimits.h
index 28a5eba..c38648f 100644
--- a/sys/sys/syslimits.h
+++ b/sys/sys/syslimits.h
@@ -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
diff --git a/sys/sys/ucred.h b/sys/sys/ucred.h
index 626b501..c7474b7 100644
--- a/sys/sys/ucred.h
+++ b/sys/sys/ucred.h
@@ -48,8 +48,7 @@ struct ucred {
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 @@ struct ucred {
#define cr_endcopy cr_label
struct label *cr_label; /* MAC label */
struct auditinfo_addr cr_audit; /* Audit properties. */
+ gid_t *cr_groups; /* groups */
+ int cr_agroups; /* Available groups */
};
#define NOCRED ((struct ucred *)0) /* no credential available */
#define FSCRED ((struct ucred *)-1) /* filesystem credential */
#endif /* _KERNEL || _WANT_UCRED */
+#define XU_NGROUPS 16
+
/*
* This is the external representation of struct ucred.
*/
@@ -73,7 +76,7 @@ struct xucred {
u_int cr_version; /* structure layout version */
uid_t cr_uid; /* effective user id */
short cr_ngroups; /* number of groups */
- gid_t cr_groups[NGROUPS]; /* groups */
+ gid_t cr_groups[XU_NGROUPS]; /* groups */
void *_cr_unused1; /* compatibility with old ucred */
};
#define XUCRED_VERSION 0
@@ -82,6 +85,7 @@ struct xucred {
#define cr_gid cr_groups[0]
#ifdef _KERNEL
+struct proc;
struct thread;
void change_egid(struct ucred *newcred, gid_t egid);
@@ -91,6 +95,7 @@ void change_ruid(struct ucred *newcred, struct uidinfo *ruip);
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 *crget(void);
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 */
diff --git a/sys/sys/user.h b/sys/sys/user.h
index ba3dfb0..a9dfceb 100644
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -85,7 +85,7 @@
*/
#define KI_NSPARE_INT 9
#define KI_NSPARE_LONG 12
-#define KI_NSPARE_PTR 7
+#define KI_NSPARE_PTR 6
#ifdef __amd64__
#define KINFO_PROC_SIZE 1088
@@ -117,7 +117,6 @@
#define OCOMMLEN 16 /* size of returned thread name */
#define COMMLEN 19 /* size of returned ki_comm name */
#define KI_EMULNAMELEN 16 /* size of returned ki_emul */
-#define KI_NGROUPS 16 /* number of groups in ki_groups */
#define LOGNAMELEN 17 /* size of returned ki_login */
struct kinfo_proc {
@@ -151,7 +150,7 @@ struct kinfo_proc {
gid_t ki_svgid; /* Saved effective group id */
short ki_ngroups; /* number of groups */
short ki_spare_short2; /* unused (just here for alignment) */
- gid_t ki_groups[KI_NGROUPS]; /* groups */
+ uint32_t __was_ki_groups[16]; /* unused; left for bin compat */
vm_size_t ki_size; /* virtual size */
segsz_t ki_rssize; /* current resident set size in pages */
segsz_t ki_swrss; /* resident set size before last swap */
@@ -201,6 +200,7 @@ struct kinfo_proc {
struct pcb *ki_pcb; /* kernel virtual addr of pcb */
void *ki_kstack; /* kernel virtual addr of stack */
void *ki_udata; /* User convenience pointer */
+ gid_t *ki_groups; /* groups */
/*
* When adding new variables, take space for pointers from the
* front of ki_spareptrs, and longs from the end of ki_sparelongs.
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index 371c462..110262b 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -2266,6 +2266,7 @@ ufs_makeinode(mode, dvp, vpp, cnp)
{
#ifdef QUOTA
struct ucred ucred, *ucp;
+ gid_t ucred_group;
ucp = cnp->cn_cred;
#endif
/*
@@ -2292,6 +2293,7 @@ ufs_makeinode(mode, dvp, vpp, cnp)
refcount_init(&ucred.cr_ref, 1);
ucred.cr_uid = ip->i_uid;
ucred.cr_ngroups = 1;
+ ucred.cr_groups = &ucred_group;
ucred.cr_groups[0] = pdir->i_gid;
ucp = &ucred;
#endif
OpenPOWER on IntegriCloud