[PATCH v5 02/18] nfsd: move check_nfsd_access() call into nfsd_cross_mnt()
NeilBrown <[email protected]> Fri, 17 Jul 2026 19:27:50 +1000
| Newsgroups | gmane.linux.nfs |
|---|---|
| Message-ID | <[email protected]> |
From: NeilBrown <neil-+NVA1uvv1dVBDLzU/[email protected]> Whenever we cross a mount point, we need to check_nfsd_access() for v4. So move the call into nfsd_cross_mnt() in the place where we actually do cross. This avoids the possibility of calling nfsd_cross_mnt() without the required check_nfsd_access(). Also remove the last arg from check_nfsd_access(), which is always false. nfsd_cross_mnt() now returns an nfserr rather than an errno. Signed-off-by: NeilBrown <neil-+NVA1uvv1dVBDLzU/[email protected]> --- fs/nfsd/export.c | 6 ++---- fs/nfsd/export.h | 3 +-- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfs4xdr.c | 9 +------- fs/nfsd/vfs.c | 54 +++++++++++++++++++++++++--------------------- fs/nfsd/vfs.h | 4 ++-- 6 files changed, 36 insertions(+), 42 deletions(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index a47c90f40422..5aefb388cc27 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1890,21 +1890,19 @@ __be32 check_security_flavor(struct svc_export *exp, struct svc_rqst *rqstp, * check_nfsd_access - check if access to export is allowed. * @exp: svc_export that is being accessed. * @rqstp: svc_rqst attempting to access @exp. - * @may_bypass_gss: reduce strictness of authorization check * * Return values: * %nfs_ok if access is granted, or * %nfserr_wrongsec if access is denied */ -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, - bool may_bypass_gss) +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) { __be32 status; status = check_xprtsec_policy(exp, rqstp); if (status != nfs_ok) return status; - return check_security_flavor(exp, rqstp, may_bypass_gss); + return check_security_flavor(exp, rqstp, false); } /* diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h index d2b09cd76145..117fb28db1e0 100644 --- a/fs/nfsd/export.h +++ b/fs/nfsd/export.h @@ -104,8 +104,7 @@ int nfsexp_flags(struct svc_cred *cred, struct svc_export *exp); __be32 check_xprtsec_policy(struct svc_export *exp, struct svc_rqst *rqstp); __be32 check_security_flavor(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss); -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, - bool may_bypass_gss); +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp); /* * Function declarations diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index bb99ab6b78b5..0317ff3f1c39 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -3328,7 +3328,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) if (current_fh->fh_export && need_wrongsec_check(rqstp)) - op->status = check_nfsd_access(current_fh->fh_export, rqstp, false); + op->status = check_nfsd_access(current_fh->fh_export, rqstp); } encode_op: if (op->status == nfserr_replay_me) { diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 606ddcb085c0..04755c41d871 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4574,8 +4574,6 @@ nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name, * directly from the mountpoint dentry. */ if (nfsd_mountpoint(dentry, exp)) { - int err; - if (!(exp->ex_flags & NFSEXP_V4ROOT) && !attributes_need_mount(cd->rd_bmval)) { ignore_crossmnt = 1; @@ -4586,12 +4584,7 @@ nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name, * Different "."/".." handling? Something else? * At least, add a comment here to explain.... */ - err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); - if (err) { - nfserr = nfserrno(err); - goto out_put; - } - nfserr = check_nfsd_access(exp, cd->rd_rqstp, false); + nfserr = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); if (nfserr) goto out_put; crossed = true; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 8923a9910a08..7898af35874b 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -118,15 +118,15 @@ nfserrno (int errno) return nfserr_io; } -/* - * Called from nfsd_lookup and encode_dirent. Check if we have crossed +/* + * Called from nfsd_lookup and encode_dirent. Check if we have crossed * a mount point. - * Returns -EAGAIN or -ETIMEDOUT leaving *dpp and *expp unchanged, + * Returns an nfs error leaving *dpp and *expp unchanged, * or nfs_ok having possibly changed *dpp and *expp */ -int -nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, - struct svc_export **expp) +__be32 +nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, + struct svc_export **expp) { struct svc_export *exp = *expp, *exp2 = NULL; struct dentry *dentry = *dpp; @@ -134,6 +134,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, .dentry = dget(dentry)}; unsigned int follow_flags = 0; int err = 0; + __be32 nfserr = nfs_ok; if (exp->ex_flags & NFSEXP_CROSSMOUNT) follow_flags = LOOKUP_AUTOMOUNT; @@ -163,23 +164,28 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, err = 0; } else if (nfsd_v4client(rqstp) || (exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) { - /* successfully crossed mount point */ - /* - * This is subtle: path.dentry is *not* on path.mnt - * at this point. The only reason we are safe is that - * original mnt is pinned down by exp, so we should - * put path *before* putting exp - */ - *dpp = path.dentry; - path.dentry = dentry; - *expp = exp2; - exp2 = exp; + nfserr = check_nfsd_access(exp, rqstp); + if (nfserr == nfs_ok) { + /* successfully crossed mount point */ + /* + * This is subtle: path.dentry is *not* on path.mnt + * at this point. The only reason we are safe is that + * original mnt is pinned down by exp, so we should + * put path *before* putting exp + */ + *dpp = path.dentry; + path.dentry = dentry; + *expp = exp2; + exp2 = exp; + } } out: path_put(&path); if (exp2) exp_put(exp2); - return err; + if (nfserr) + return nfserr; + return nfserrno(err); } static void follow_to_parent(struct path *path) @@ -277,10 +283,11 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, if (IS_ERR(dentry)) goto out_nfserr; if (nfsd_mountpoint(dentry, exp)) { - host_err = nfsd_cross_mnt(rqstp, &dentry, &exp); - if (host_err) { + int nfserr = nfsd_cross_mnt(rqstp, &dentry, &exp); + if (nfserr) { dput(dentry); - goto out_nfserr; + exp_put(exp); + return nfserr; } } } @@ -327,9 +334,6 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry); if (err) return err; - err = check_nfsd_access(exp, rqstp, false); - if (err) - goto out; /* * Note: we compose the file handle now, but as the * dentry may be negative, it may need to be updated. @@ -337,7 +341,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, err = fh_compose(resfh, exp, dentry, fhp); if (!err && d_really_is_negative(dentry)) err = nfserr_noent; -out: + dput(dentry); exp_put(exp); return err; diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 4af2ff9e9dfe..5554878781f4 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -76,8 +76,8 @@ static inline bool nfsd_attrs_valid(struct nfsd_attrs *attrs) } __be32 nfserrno (int errno); -int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, - struct svc_export **expp); +__be32 nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, + struct svc_export **expp); __be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *, const char *, unsigned int, struct svc_fh *); __be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *, -- 2.50.0.107.gf914562f5916.dirty