summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
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