Do not embed struct ucred into larger netcred parent structures.
Credential might need to hang around longer than its parent and be used outside of mnt_explock scope controlling netcred lifetime. Use separate reference-counted ucred allocated separately instead. While there, extend mnt_explock coverage in vfs_stdexpcheck and clean-up some unused declarations in new NFS code. Reported by: John Hickey PR: kern/133439 Reviewed by: dfr, kib
This commit is contained in:
parent
ec54a3a337
commit
5679fe1957
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=191940
@ -445,16 +445,6 @@ int nfsmsleep(void *, void *, int, const char *, struct timespec *);
|
||||
*/
|
||||
#define VT_NFSV4ROOT "nfsv4root"
|
||||
|
||||
/*
|
||||
* XXX - not in any system .h file, just vfs_export.c
|
||||
* Network address lookup element
|
||||
*/
|
||||
struct netcred {
|
||||
struct radix_node netc_rnodes[2];
|
||||
int netc_exflags;
|
||||
struct ucred netc_anon;
|
||||
};
|
||||
|
||||
/*
|
||||
* Define whatever it takes to do a vn_rdwr().
|
||||
*/
|
||||
|
@ -2565,6 +2565,8 @@ nfsd_fhtovp(struct nfsrv_descript *nd, struct nfsrvfh *nfp,
|
||||
if (nd->nd_repstat)
|
||||
vput(*vpp);
|
||||
}
|
||||
if (credanon != NULL)
|
||||
crfree(credanon);
|
||||
if (nd->nd_repstat) {
|
||||
if (startwrite)
|
||||
vn_finished_write(mp);
|
||||
@ -2597,16 +2599,6 @@ fp_getfvp(struct thread *p, int fd, struct file **fpp, struct vnode **vpp)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Network export information
|
||||
*/
|
||||
struct netexport {
|
||||
struct netcred ne_defexported; /* Default export */
|
||||
struct radix_node_head *ne_rtable[AF_MAX+1]; /* Individual exports */
|
||||
};
|
||||
|
||||
struct netexport nfsv4root_export;
|
||||
|
||||
/*
|
||||
* Called from newnfssvc() to update the exports list. Just call
|
||||
* vfs_export(). This has to be done, since the v4 root fake fs isn't
|
||||
@ -2861,6 +2853,8 @@ nfsvno_v4rootexport(struct nfsrv_descript *nd)
|
||||
return (NFSERR_PROGUNAVAIL);
|
||||
if ((exflags & MNT_EXGSSONLY))
|
||||
nd->nd_flag |= ND_EXGSSONLY;
|
||||
if (credanon != NULL)
|
||||
crfree(credanon);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -870,6 +870,8 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
|
||||
if (!nd->nd_repstat)
|
||||
nd->nd_repstat = nfsd_excred(nd,
|
||||
&nes, credanon);
|
||||
if (credanon != NULL)
|
||||
crfree(credanon);
|
||||
if (!nd->nd_repstat) {
|
||||
if (vpnes.nes_vfslocked)
|
||||
nfsvno_unlockvfs(mp);
|
||||
|
@ -68,7 +68,7 @@ static struct netcred *vfs_export_lookup(struct mount *, struct sockaddr *);
|
||||
struct netcred {
|
||||
struct radix_node netc_rnodes[2];
|
||||
int netc_exflags;
|
||||
struct ucred netc_anon;
|
||||
struct ucred *netc_anon;
|
||||
int netc_numsecflavors;
|
||||
int netc_secflavors[MAXSECFLAVORS];
|
||||
};
|
||||
@ -83,7 +83,7 @@ struct netexport {
|
||||
|
||||
/*
|
||||
* Build hash lists of net addresses and hang them off the mount point.
|
||||
* Called by ufs_mount() to set up the lists of export addresses.
|
||||
* Called by vfs_export() to set up the lists of export addresses.
|
||||
*/
|
||||
static int
|
||||
vfs_hang_addrlist(struct mount *mp, struct netexport *nep,
|
||||
@ -118,15 +118,14 @@ vfs_hang_addrlist(struct mount *mp, struct netexport *nep,
|
||||
}
|
||||
np = &nep->ne_defexported;
|
||||
np->netc_exflags = argp->ex_flags;
|
||||
bzero(&np->netc_anon, sizeof(np->netc_anon));
|
||||
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));
|
||||
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));
|
||||
np->netc_numsecflavors = argp->ex_numsecflavors;
|
||||
bcopy(argp->ex_secflavors, np->netc_secflavors,
|
||||
sizeof(np->netc_secflavors));
|
||||
refcount_init(&np->netc_anon.cr_ref, 1);
|
||||
MNT_ILOCK(mp);
|
||||
mp->mnt_flag |= MNT_DEFEXPORTED;
|
||||
MNT_IUNLOCK(mp);
|
||||
@ -204,15 +203,14 @@ vfs_hang_addrlist(struct mount *mp, struct netexport *nep,
|
||||
goto out;
|
||||
}
|
||||
np->netc_exflags = argp->ex_flags;
|
||||
bzero(&np->netc_anon, sizeof(np->netc_anon));
|
||||
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));
|
||||
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));
|
||||
np->netc_numsecflavors = argp->ex_numsecflavors;
|
||||
bcopy(argp->ex_secflavors, np->netc_secflavors,
|
||||
sizeof(np->netc_secflavors));
|
||||
refcount_init(&np->netc_anon.cr_ref, 1);
|
||||
return (0);
|
||||
out:
|
||||
free(np, M_NETADDR);
|
||||
@ -267,9 +265,9 @@ vfs_export(struct mount *mp, struct export_args *argp)
|
||||
|| argp->ex_numsecflavors >= MAXSECFLAVORS)
|
||||
return (EINVAL);
|
||||
|
||||
nep = mp->mnt_export;
|
||||
error = 0;
|
||||
lockmgr(&mp->mnt_explock, LK_EXCLUSIVE, NULL);
|
||||
nep = mp->mnt_export;
|
||||
if (argp->ex_flags & MNT_DELEXPORT) {
|
||||
if (nep == NULL) {
|
||||
error = ENOENT;
|
||||
@ -375,8 +373,9 @@ vfs_setpublicfs(struct mount *mp, struct netexport *nep,
|
||||
* If an indexfile was specified, pull it in.
|
||||
*/
|
||||
if (argp->ex_indexfile != NULL) {
|
||||
nfs_pub.np_index = malloc(MAXNAMLEN + 1, M_TEMP,
|
||||
M_WAITOK);
|
||||
if (nfs_pub.np_index != NULL)
|
||||
nfs_pub.np_index = malloc(MAXNAMLEN + 1, M_TEMP,
|
||||
M_WAITOK);
|
||||
error = copyinstr(argp->ex_indexfile, nfs_pub.np_index,
|
||||
MAXNAMLEN, (size_t *)0);
|
||||
if (!error) {
|
||||
@ -392,6 +391,7 @@ vfs_setpublicfs(struct mount *mp, struct netexport *nep,
|
||||
}
|
||||
if (error) {
|
||||
free(nfs_pub.np_index, M_TEMP);
|
||||
nfs_pub.np_index = NULL;
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
@ -461,15 +461,19 @@ vfs_stdcheckexp(struct mount *mp, struct sockaddr *nam, int *extflagsp,
|
||||
|
||||
lockmgr(&mp->mnt_explock, LK_SHARED, NULL);
|
||||
np = vfs_export_lookup(mp, nam);
|
||||
lockmgr(&mp->mnt_explock, LK_RELEASE, NULL);
|
||||
if (np == NULL)
|
||||
if (np == NULL) {
|
||||
lockmgr(&mp->mnt_explock, LK_RELEASE, NULL);
|
||||
*credanonp = NULL;
|
||||
return (EACCES);
|
||||
}
|
||||
*extflagsp = np->netc_exflags;
|
||||
*credanonp = &np->netc_anon;
|
||||
if ((*credanonp = np->netc_anon) != NULL)
|
||||
crhold(*credanonp);
|
||||
if (numsecflavors)
|
||||
*numsecflavors = np->netc_numsecflavors;
|
||||
if (secflavors)
|
||||
*secflavors = np->netc_secflavors;
|
||||
lockmgr(&mp->mnt_explock, LK_RELEASE, NULL);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -1193,6 +1193,9 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, int *vfslockedp,
|
||||
if (!lockflag)
|
||||
VOP_UNLOCK(*vpp, 0);
|
||||
out:
|
||||
if (credanon != NULL)
|
||||
crfree(credanon);
|
||||
|
||||
if (error) {
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
} else
|
||||
|
@ -1752,7 +1752,8 @@ nlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp,
|
||||
}
|
||||
if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
|
||||
crfree(cred);
|
||||
cred = crhold(credanon);
|
||||
cred = credanon;
|
||||
credanon = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1772,6 +1773,8 @@ nlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp,
|
||||
out:
|
||||
if (cred)
|
||||
crfree(cred);
|
||||
if (credanon)
|
||||
crfree(credanon);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ struct direct;
|
||||
struct indir;
|
||||
struct inode;
|
||||
struct mount;
|
||||
struct netcred;
|
||||
struct thread;
|
||||
struct sockaddr;
|
||||
struct ucred;
|
||||
|
Loading…
Reference in New Issue
Block a user