1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-27 16:39:08 +00:00

Add kern_setgroups() and kern_getgroups() and use them to implement

ibcs2_[gs]etgroups() rather than using the stackgap.  This also makes
ibcs2_[gs]etgroups() MPSAFE.  Also, it cleans up one bit of weirdness in
the old setgroups() where it allocated an entire credential just so it had
a place to copy the group list into.  Now setgroups just allocates a
NGROUPS_MAX array on the stack that it copies into and then passes to
kern_setgroups().
This commit is contained in:
John Baldwin 2006-07-06 21:32:20 +00:00
parent c79c04f176
commit 3cb83e714d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=160139
4 changed files with 73 additions and 71 deletions

View File

@ -651,35 +651,25 @@ ibcs2_getgroups(td, uap)
struct thread *td; struct thread *td;
struct ibcs2_getgroups_args *uap; struct ibcs2_getgroups_args *uap;
{ {
int error, i; ibcs2_gid_t iset[NGROUPS_MAX];
ibcs2_gid_t *iset = NULL; gid_t gp[NGROUPS_MAX];
struct getgroups_args sa; u_int i, ngrp;
gid_t *gp; int error;
caddr_t sg = stackgap_init();
if (uap->gidsetsize < 0) if (uap->gidsetsize < 0)
return (EINVAL); return (EINVAL);
if (uap->gidsetsize > NGROUPS_MAX) ngrp = MIN(uap->gidsetsize, NGROUPS_MAX);
uap->gidsetsize = NGROUPS_MAX; error = kern_getgroups(td, &ngrp, gp);
sa.gidsetsize = uap->gidsetsize; if (error)
if (uap->gidsetsize) { return (error);
sa.gidset = stackgap_alloc(&sg, NGROUPS_MAX * if (uap->gidsetsize > 0) {
sizeof(gid_t *)); for (i = 0; i < ngrp; i++)
iset = stackgap_alloc(&sg, uap->gidsetsize * iset[i] = (ibcs2_gid_t)gp[i];
sizeof(ibcs2_gid_t)); error = copyout(iset, uap->gidset, ngrp * sizeof(ibcs2_gid_t));
} }
if ((error = getgroups(td, &sa)) != 0) if (error == 0)
return error; td->td_retval[0] = ngrp;
if (uap->gidsetsize == 0) return (error);
return 0;
for (i = 0, gp = sa.gidset; i < td->td_retval[0]; i++)
iset[i] = (ibcs2_gid_t)*gp++;
if (td->td_retval[0] && (error = copyout((caddr_t)iset,
(caddr_t)uap->gidset,
sizeof(ibcs2_gid_t) * td->td_retval[0])))
return error;
return 0;
} }
int int
@ -687,28 +677,21 @@ ibcs2_setgroups(td, uap)
struct thread *td; struct thread *td;
struct ibcs2_setgroups_args *uap; struct ibcs2_setgroups_args *uap;
{ {
ibcs2_gid_t iset[NGROUPS_MAX];
gid_t gp[NGROUPS_MAX];
int error, i; int error, i;
ibcs2_gid_t *iset;
struct setgroups_args sa;
gid_t *gp;
caddr_t sg = stackgap_init();
if (uap->gidsetsize < 0 || uap->gidsetsize > NGROUPS_MAX) if (uap->gidsetsize < 0 || uap->gidsetsize > NGROUPS_MAX)
return (EINVAL); return (EINVAL);
sa.gidsetsize = uap->gidsetsize; if (uap->gidsetsize && uap->gidset) {
sa.gidset = stackgap_alloc(&sg, sa.gidsetsize * error = copyin(uap->gidset, iset, sizeof(ibcs2_gid_t) *
sizeof(gid_t *)); uap->gidsetsize);
iset = stackgap_alloc(&sg, sa.gidsetsize * if (error)
sizeof(ibcs2_gid_t *)); return (error);
if (sa.gidsetsize) { for (i = 0; i < uap->gidsetsize; i++)
if ((error = copyin((caddr_t)uap->gidset, (caddr_t)iset, gp[i] = (gid_t)iset[i];
sizeof(ibcs2_gid_t *) *
uap->gidsetsize)) != 0)
return error;
} }
for (i = 0, gp = sa.gidset; i < sa.gidsetsize; i++) return (kern_setgroups(td, uap->gidsetsize, gp));
*gp++ = (gid_t)iset[i];
return setgroups(td, &sa);
} }
int int

View File

@ -56,9 +56,9 @@
ibcs2_sigset_t *oset); } ibcs2_sigset_t *oset); }
41 AUE_NULL MSTD { int ibcs2_sigpending(ibcs2_sigset_t *mask); } 41 AUE_NULL MSTD { int ibcs2_sigpending(ibcs2_sigset_t *mask); }
42 AUE_NULL MSTD { int ibcs2_sigsuspend(ibcs2_sigset_t *mask); } 42 AUE_NULL MSTD { int ibcs2_sigsuspend(ibcs2_sigset_t *mask); }
43 AUE_GETGROUPS STD { int ibcs2_getgroups(int gidsetsize, \ 43 AUE_GETGROUPS MSTD { int ibcs2_getgroups(int gidsetsize, \
ibcs2_gid_t *gidset); } ibcs2_gid_t *gidset); }
44 AUE_SETGROUPS STD { int ibcs2_setgroups(int gidsetsize, \ 44 AUE_SETGROUPS MSTD { int ibcs2_setgroups(int gidsetsize, \
ibcs2_gid_t *gidset); } ibcs2_gid_t *gidset); }
45 AUE_NULL MSTD { int ibcs2_sysconf(int name); } 45 AUE_NULL MSTD { int ibcs2_sysconf(int name); }
46 AUE_PATHCONF MSTD { int ibcs2_pathconf(char *path, int name); } 46 AUE_PATHCONF MSTD { int ibcs2_pathconf(char *path, int name); }

View File

@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
#include <sys/resourcevar.h> #include <sys/resourcevar.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/socketvar.h> #include <sys/socketvar.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <security/audit/audit.h> #include <security/audit/audit.h>
@ -297,24 +298,38 @@ struct getgroups_args {
int int
getgroups(struct thread *td, register struct getgroups_args *uap) getgroups(struct thread *td, register struct getgroups_args *uap)
{ {
struct ucred *cred; gid_t groups[NGROUPS];
u_int ngrp; u_int ngrp;
int error; int error;
cred = td->td_ucred; ngrp = MIN(uap->gidsetsize, NGROUPS);
if ((ngrp = uap->gidsetsize) == 0) { error = kern_getgroups(td, &ngrp, groups);
td->td_retval[0] = cred->cr_ngroups; if (error)
return (0); return (error);
} if (uap->gidsetsize > 0)
if (ngrp < cred->cr_ngroups) error = copyout(groups, uap->gidset, ngrp * sizeof(gid_t));
return (EINVAL);
ngrp = cred->cr_ngroups;
error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t));
if (error == 0) if (error == 0)
td->td_retval[0] = ngrp; td->td_retval[0] = ngrp;
return (error); return (error);
} }
int
kern_getgroups(struct thread *td, u_int *ngrp, gid_t *groups)
{
struct ucred *cred;
cred = td->td_ucred;
if (*ngrp == 0) {
*ngrp = cred->cr_ngroups;
return (0);
}
if (*ngrp < cred->cr_ngroups)
return (EINVAL);
*ngrp = cred->cr_ngroups;
bcopy(cred->cr_groups, groups, *ngrp * sizeof(gid_t));
return (0);
}
#ifndef _SYS_SYSPROTO_H_ #ifndef _SYS_SYSPROTO_H_
struct setsid_args { struct setsid_args {
int dummy; int dummy;
@ -815,28 +830,33 @@ struct setgroups_args {
int int
setgroups(struct thread *td, struct setgroups_args *uap) setgroups(struct thread *td, struct setgroups_args *uap)
{ {
struct proc *p = td->td_proc; gid_t groups[NGROUPS];
struct ucred *newcred, *tempcred, *oldcred; int error;
u_int ngrp;
if (uap->gidsetsize > NGROUPS)
return (EINVAL);
error = copyin(uap->gidset, groups, uap->gidsetsize * sizeof(gid_t));
if (error)
return (error);
return (kern_setgroups(td, uap->gidsetsize, groups));
}
int
kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups)
{
struct proc *p = td->td_proc;
struct ucred *newcred, *oldcred;
int error; int error;
ngrp = uap->gidsetsize;
if (ngrp > NGROUPS) if (ngrp > NGROUPS)
return (EINVAL); return (EINVAL);
tempcred = crget(); AUDIT_ARG(groupset, groups, ngrp);
error = copyin(uap->gidset, tempcred->cr_groups, ngrp * sizeof(gid_t));
if (error != 0) {
crfree(tempcred);
return (error);
}
AUDIT_ARG(groupset, tempcred->cr_groups, ngrp);
newcred = crget(); newcred = crget();
PROC_LOCK(p); PROC_LOCK(p);
oldcred = p->p_ucred; oldcred = p->p_ucred;
#ifdef MAC #ifdef MAC
error = mac_check_proc_setgroups(p, oldcred, ngrp, error = mac_check_proc_setgroups(p, oldcred, ngrp, groups);
tempcred->cr_groups);
if (error) if (error)
goto fail; goto fail;
#endif #endif
@ -859,21 +879,18 @@ setgroups(struct thread *td, struct setgroups_args *uap)
*/ */
newcred->cr_ngroups = 1; newcred->cr_ngroups = 1;
} else { } else {
bcopy(tempcred->cr_groups, newcred->cr_groups, bcopy(groups, newcred->cr_groups, ngrp * sizeof(gid_t));
ngrp * sizeof(gid_t));
newcred->cr_ngroups = ngrp; newcred->cr_ngroups = ngrp;
} }
setsugid(p); setsugid(p);
p->p_ucred = newcred; p->p_ucred = newcred;
PROC_UNLOCK(p); PROC_UNLOCK(p);
crfree(tempcred);
crfree(oldcred); crfree(oldcred);
return (0); return (0);
fail: fail:
PROC_UNLOCK(p); PROC_UNLOCK(p);
crfree(newcred); crfree(newcred);
crfree(tempcred);
return (error); return (error);
} }

View File

@ -81,6 +81,7 @@ int kern_futimes(struct thread *td, int fd, struct timeval *tptr,
enum uio_seg tptrseg); enum uio_seg tptrseg);
int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize, int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
enum uio_seg bufseg, int flags); enum uio_seg bufseg, int flags);
int kern_getgroups(struct thread *td, u_int *ngrp, gid_t *groups);
int kern_getitimer(struct thread *, u_int, struct itimerval *); int kern_getitimer(struct thread *, u_int, struct itimerval *);
int kern_getrusage(struct thread *td, int who, struct rusage *rup); int kern_getrusage(struct thread *td, int who, struct rusage *rup);
int kern_getsockopt(struct thread *td, int s, int level, int name, int kern_getsockopt(struct thread *td, int s, int level, int name,
@ -132,6 +133,7 @@ int kern_sendfile(struct thread *td, struct sendfile_args *uap,
struct uio *hdr_uio, struct uio *trl_uio, int compat); struct uio *hdr_uio, struct uio *trl_uio, int compat);
int kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags, int kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
struct mbuf *control, enum uio_seg segflg); struct mbuf *control, enum uio_seg segflg);
int kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups);
int kern_setitimer(struct thread *, u_int, struct itimerval *, int kern_setitimer(struct thread *, u_int, struct itimerval *,
struct itimerval *); struct itimerval *);
int kern_setrlimit(struct thread *, u_int, struct rlimit *); int kern_setrlimit(struct thread *, u_int, struct rlimit *);