mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-28 08:02:54 +00:00
nfs, rpc: Ensure kernel credentials have at least one group
This fixes several bugs where some 'struct ucred' in the kernel, constructed from user input (via nmount(2)) or obtained from other servers (e.g., gssd(8)), could have an unfilled 'cr_groups' field and whose 'cr_groups[0]' (or 'cr_gid', which is an alias) was later accessed, causing an uninitialized access giving random access rights. Use crsetgroups_fallback() to enforce a fallback group when possible. For NFS, the chosen fallback group is that of the NFS server in the current VNET (NFSD_VNET(nfsrv_defaultgid)). There does not seem to be any sensible fallback available in rpc code (sys/rpc/svc_auth.c, svc_getcred()) on AUTH_UNIX (TLS or not), so just fail credential retrieval there. Stock NSS sources, rpc.tlsservd(8) or rpc.tlsclntd(8) provide non-empty group lists, so will not be impacted. Discussed with: rmacklem (by mail) Approved by: markj (mentor) MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D46918
This commit is contained in:
parent
d4e0d4d92e
commit
cfbe7a62dc
@ -75,6 +75,7 @@ NFSD_VNET_DEFINE(struct nfsstatsv1 *, nfsstatsv1_p);
|
||||
|
||||
NFSD_VNET_DECLARE(struct nfssockreq, nfsrv_nfsuserdsock);
|
||||
NFSD_VNET_DECLARE(nfsuserd_state, nfsrv_nfsuserd);
|
||||
NFSD_VNET_DECLARE(gid_t, nfsrv_defaultgid);
|
||||
|
||||
int nfs_pnfsio(task_fn_t *, void *);
|
||||
|
||||
@ -258,7 +259,8 @@ newnfs_copycred(struct nfscred *nfscr, struct ucred *cr)
|
||||
KASSERT(nfscr->nfsc_ngroups >= 0,
|
||||
("newnfs_copycred: negative nfsc_ngroups"));
|
||||
cr->cr_uid = nfscr->nfsc_uid;
|
||||
crsetgroups(cr, nfscr->nfsc_ngroups, nfscr->nfsc_groups);
|
||||
crsetgroups_fallback(cr, nfscr->nfsc_ngroups, nfscr->nfsc_groups,
|
||||
NFSD_VNET(nfsrv_defaultgid));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4051,8 +4051,9 @@ nfssvc_idname(struct nfsd_idargs *nidp)
|
||||
*/
|
||||
cr = crget();
|
||||
cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
|
||||
crsetgroups(cr, nidp->nid_ngroup, grps);
|
||||
cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
|
||||
crsetgroups_fallback(cr, nidp->nid_ngroup, grps,
|
||||
NFSD_VNET(nfsrv_defaultgid));
|
||||
cr->cr_rgid = cr->cr_svgid = cr->cr_gid;
|
||||
cr->cr_prison = curthread->td_ucred->cr_prison;
|
||||
prison_hold(cr->cr_prison);
|
||||
#ifdef MAC
|
||||
|
@ -3311,7 +3311,11 @@ nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp,
|
||||
NFSVNO_EXPORTANON(exp) ||
|
||||
(nd->nd_flag & ND_AUTHNONE) != 0) {
|
||||
nd->nd_cred->cr_uid = credanon->cr_uid;
|
||||
nd->nd_cred->cr_gid = credanon->cr_gid;
|
||||
/*
|
||||
* 'credanon' is already a 'struct ucred' that was built
|
||||
* internally with calls to crsetgroups_fallback(), so
|
||||
* we don't need a fallback here.
|
||||
*/
|
||||
crsetgroups(nd->nd_cred, credanon->cr_ngroups,
|
||||
credanon->cr_groups);
|
||||
} else if ((nd->nd_flag & ND_GSS) == 0) {
|
||||
|
@ -1422,13 +1422,11 @@ static struct ucred *
|
||||
nfsrv_createrootcred(void)
|
||||
{
|
||||
struct ucred *cr;
|
||||
gid_t grp;
|
||||
|
||||
cr = crget();
|
||||
cr->cr_uid = cr->cr_ruid = cr->cr_svuid = UID_ROOT;
|
||||
grp = GID_WHEEL;
|
||||
crsetgroups(cr, 1, &grp);
|
||||
cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
|
||||
crsetgroups_fallback(cr, 0, NULL, GID_WHEEL);
|
||||
cr->cr_rgid = cr->cr_svgid = cr->cr_gid;
|
||||
cr->cr_prison = curthread->td_ucred->cr_prison;
|
||||
prison_hold(cr->cr_prison);
|
||||
#ifdef MAC
|
||||
|
@ -61,6 +61,10 @@
|
||||
#include <rpc/types.h>
|
||||
#include <rpc/auth.h>
|
||||
|
||||
#include <fs/nfs/nfsport.h>
|
||||
|
||||
NFSD_VNET_DECLARE(gid_t, nfsrv_defaultgid);
|
||||
|
||||
static MALLOC_DEFINE(M_NETADDR, "export_host", "Export host address structure");
|
||||
|
||||
#if defined(INET) || defined(INET6)
|
||||
@ -133,8 +137,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_uid;
|
||||
crsetgroups(np->netc_anon, argp->ex_ngroups,
|
||||
argp->ex_groups);
|
||||
crsetgroups_fallback(np->netc_anon, argp->ex_ngroups,
|
||||
argp->ex_groups, NFSD_VNET(nfsrv_defaultgid));
|
||||
np->netc_anon->cr_prison = &prison0;
|
||||
prison_hold(np->netc_anon->cr_prison);
|
||||
np->netc_numsecflavors = argp->ex_numsecflavors;
|
||||
@ -212,8 +216,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_uid;
|
||||
crsetgroups(np->netc_anon, argp->ex_ngroups,
|
||||
argp->ex_groups);
|
||||
crsetgroups_fallback(np->netc_anon, argp->ex_ngroups, argp->ex_groups,
|
||||
NFSD_VNET(nfsrv_defaultgid));
|
||||
np->netc_anon->cr_prison = &prison0;
|
||||
prison_hold(np->netc_anon->cr_prison);
|
||||
np->netc_numsecflavors = argp->ex_numsecflavors;
|
||||
|
@ -537,7 +537,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;
|
||||
crsetgroups(cr, uc->gidlen, uc->gidlist);
|
||||
crsetgroups_fallback(cr, uc->gidlen, uc->gidlist, uc->gid);
|
||||
cr->cr_prison = curthread->td_ucred->cr_prison;
|
||||
prison_hold(cr->cr_prison);
|
||||
*crp = crhold(cr);
|
||||
|
@ -187,10 +187,12 @@ svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp)
|
||||
if ((xprt->xp_tls & (RPCTLS_FLAGS_CERTUSER |
|
||||
RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER &&
|
||||
flavor == AUTH_UNIX) {
|
||||
if (xprt->xp_ngrps <= 0)
|
||||
return (FALSE);
|
||||
cr = crget();
|
||||
cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xprt->xp_uid;
|
||||
crsetgroups(cr, xprt->xp_ngrps, xprt->xp_gidp);
|
||||
cr->cr_rgid = cr->cr_svgid = xprt->xp_gidp[0];
|
||||
cr->cr_rgid = cr->cr_svgid = cr->cr_gid;
|
||||
cr->cr_prison = curthread->td_ucred->cr_prison;
|
||||
prison_hold(cr->cr_prison);
|
||||
*crp = cr;
|
||||
@ -200,10 +202,12 @@ svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp)
|
||||
switch (flavor) {
|
||||
case AUTH_UNIX:
|
||||
xcr = (struct xucred *) rqst->rq_clntcred;
|
||||
if (xcr->cr_ngroups <= 0)
|
||||
return (FALSE);
|
||||
cr = crget();
|
||||
cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xcr->cr_uid;
|
||||
crsetgroups(cr, xcr->cr_ngroups, xcr->cr_groups);
|
||||
cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
|
||||
cr->cr_rgid = cr->cr_svgid = cr->cr_gid;
|
||||
cr->cr_prison = curthread->td_ucred->cr_prison;
|
||||
prison_hold(cr->cr_prison);
|
||||
*crp = cr;
|
||||
|
Loading…
Reference in New Issue
Block a user