mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-26 16:18:31 +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:
parent
c79c04f176
commit
3cb83e714d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=160139
@ -651,35 +651,25 @@ ibcs2_getgroups(td, uap)
|
||||
struct thread *td;
|
||||
struct ibcs2_getgroups_args *uap;
|
||||
{
|
||||
int error, i;
|
||||
ibcs2_gid_t *iset = NULL;
|
||||
struct getgroups_args sa;
|
||||
gid_t *gp;
|
||||
caddr_t sg = stackgap_init();
|
||||
ibcs2_gid_t iset[NGROUPS_MAX];
|
||||
gid_t gp[NGROUPS_MAX];
|
||||
u_int i, ngrp;
|
||||
int error;
|
||||
|
||||
if (uap->gidsetsize < 0)
|
||||
return (EINVAL);
|
||||
if (uap->gidsetsize > NGROUPS_MAX)
|
||||
uap->gidsetsize = NGROUPS_MAX;
|
||||
sa.gidsetsize = uap->gidsetsize;
|
||||
if (uap->gidsetsize) {
|
||||
sa.gidset = stackgap_alloc(&sg, NGROUPS_MAX *
|
||||
sizeof(gid_t *));
|
||||
iset = stackgap_alloc(&sg, uap->gidsetsize *
|
||||
sizeof(ibcs2_gid_t));
|
||||
ngrp = MIN(uap->gidsetsize, NGROUPS_MAX);
|
||||
error = kern_getgroups(td, &ngrp, gp);
|
||||
if (error)
|
||||
return (error);
|
||||
if (uap->gidsetsize > 0) {
|
||||
for (i = 0; i < ngrp; i++)
|
||||
iset[i] = (ibcs2_gid_t)gp[i];
|
||||
error = copyout(iset, uap->gidset, ngrp * sizeof(ibcs2_gid_t));
|
||||
}
|
||||
if ((error = getgroups(td, &sa)) != 0)
|
||||
return error;
|
||||
if (uap->gidsetsize == 0)
|
||||
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;
|
||||
if (error == 0)
|
||||
td->td_retval[0] = ngrp;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
@ -687,28 +677,21 @@ ibcs2_setgroups(td, uap)
|
||||
struct thread *td;
|
||||
struct ibcs2_setgroups_args *uap;
|
||||
{
|
||||
ibcs2_gid_t iset[NGROUPS_MAX];
|
||||
gid_t gp[NGROUPS_MAX];
|
||||
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)
|
||||
return (EINVAL);
|
||||
sa.gidsetsize = uap->gidsetsize;
|
||||
sa.gidset = stackgap_alloc(&sg, sa.gidsetsize *
|
||||
sizeof(gid_t *));
|
||||
iset = stackgap_alloc(&sg, sa.gidsetsize *
|
||||
sizeof(ibcs2_gid_t *));
|
||||
if (sa.gidsetsize) {
|
||||
if ((error = copyin((caddr_t)uap->gidset, (caddr_t)iset,
|
||||
sizeof(ibcs2_gid_t *) *
|
||||
uap->gidsetsize)) != 0)
|
||||
return error;
|
||||
if (uap->gidsetsize && uap->gidset) {
|
||||
error = copyin(uap->gidset, iset, sizeof(ibcs2_gid_t) *
|
||||
uap->gidsetsize);
|
||||
if (error)
|
||||
return (error);
|
||||
for (i = 0; i < uap->gidsetsize; i++)
|
||||
gp[i] = (gid_t)iset[i];
|
||||
}
|
||||
for (i = 0, gp = sa.gidset; i < sa.gidsetsize; i++)
|
||||
*gp++ = (gid_t)iset[i];
|
||||
return setgroups(td, &sa);
|
||||
return (kern_setgroups(td, uap->gidsetsize, gp));
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -56,9 +56,9 @@
|
||||
ibcs2_sigset_t *oset); }
|
||||
41 AUE_NULL MSTD { int ibcs2_sigpending(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); }
|
||||
44 AUE_SETGROUPS STD { int ibcs2_setgroups(int gidsetsize, \
|
||||
44 AUE_SETGROUPS MSTD { int ibcs2_setgroups(int gidsetsize, \
|
||||
ibcs2_gid_t *gidset); }
|
||||
45 AUE_NULL MSTD { int ibcs2_sysconf(int name); }
|
||||
46 AUE_PATHCONF MSTD { int ibcs2_pathconf(char *path, int name); }
|
||||
|
@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <security/audit/audit.h>
|
||||
@ -297,24 +298,38 @@ struct getgroups_args {
|
||||
int
|
||||
getgroups(struct thread *td, register struct getgroups_args *uap)
|
||||
{
|
||||
struct ucred *cred;
|
||||
gid_t groups[NGROUPS];
|
||||
u_int ngrp;
|
||||
int error;
|
||||
|
||||
cred = td->td_ucred;
|
||||
if ((ngrp = uap->gidsetsize) == 0) {
|
||||
td->td_retval[0] = cred->cr_ngroups;
|
||||
return (0);
|
||||
}
|
||||
if (ngrp < cred->cr_ngroups)
|
||||
return (EINVAL);
|
||||
ngrp = cred->cr_ngroups;
|
||||
error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t));
|
||||
ngrp = MIN(uap->gidsetsize, NGROUPS);
|
||||
error = kern_getgroups(td, &ngrp, groups);
|
||||
if (error)
|
||||
return (error);
|
||||
if (uap->gidsetsize > 0)
|
||||
error = copyout(groups, uap->gidset, ngrp * sizeof(gid_t));
|
||||
if (error == 0)
|
||||
td->td_retval[0] = ngrp;
|
||||
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_
|
||||
struct setsid_args {
|
||||
int dummy;
|
||||
@ -815,28 +830,33 @@ struct setgroups_args {
|
||||
int
|
||||
setgroups(struct thread *td, struct setgroups_args *uap)
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
struct ucred *newcred, *tempcred, *oldcred;
|
||||
u_int ngrp;
|
||||
gid_t groups[NGROUPS];
|
||||
int error;
|
||||
|
||||
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;
|
||||
|
||||
ngrp = uap->gidsetsize;
|
||||
if (ngrp > NGROUPS)
|
||||
return (EINVAL);
|
||||
tempcred = crget();
|
||||
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);
|
||||
AUDIT_ARG(groupset, groups, ngrp);
|
||||
newcred = crget();
|
||||
PROC_LOCK(p);
|
||||
oldcred = p->p_ucred;
|
||||
|
||||
#ifdef MAC
|
||||
error = mac_check_proc_setgroups(p, oldcred, ngrp,
|
||||
tempcred->cr_groups);
|
||||
error = mac_check_proc_setgroups(p, oldcred, ngrp, groups);
|
||||
if (error)
|
||||
goto fail;
|
||||
#endif
|
||||
@ -859,21 +879,18 @@ setgroups(struct thread *td, struct setgroups_args *uap)
|
||||
*/
|
||||
newcred->cr_ngroups = 1;
|
||||
} else {
|
||||
bcopy(tempcred->cr_groups, newcred->cr_groups,
|
||||
ngrp * sizeof(gid_t));
|
||||
bcopy(groups, newcred->cr_groups, ngrp * sizeof(gid_t));
|
||||
newcred->cr_ngroups = ngrp;
|
||||
}
|
||||
setsugid(p);
|
||||
p->p_ucred = newcred;
|
||||
PROC_UNLOCK(p);
|
||||
crfree(tempcred);
|
||||
crfree(oldcred);
|
||||
return (0);
|
||||
|
||||
fail:
|
||||
PROC_UNLOCK(p);
|
||||
crfree(newcred);
|
||||
crfree(tempcred);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,7 @@ int kern_futimes(struct thread *td, int fd, struct timeval *tptr,
|
||||
enum uio_seg tptrseg);
|
||||
int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
|
||||
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_getrusage(struct thread *td, int who, struct rusage *rup);
|
||||
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);
|
||||
int kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
|
||||
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 *,
|
||||
struct itimerval *);
|
||||
int kern_setrlimit(struct thread *, u_int, struct rlimit *);
|
||||
|
Loading…
Reference in New Issue
Block a user