Skip to content

Commit e4f574c

Browse files
scottmayhewchucklever
authored andcommitted
nfsd: decouple the xprtsec policy check from check_nfsd_access()
A while back I had reported that an NFSv3 client could successfully mount using '-o xprtsec=none' an export that had been exported with 'xprtsec=tls:mtls'. By "successfully" I mean that the mount command would succeed and the mount would show up in /proc/mount. Attempting to do anything futher with the mount would be met with NFS3ERR_ACCES. This was fixed (albeit accidentally) by commit bb4f07f ("nfsd: Fix NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT") and was subsequently re-broken by commit 0813c5f ("nfsd: fix access checking for NLM under XPRTSEC policies"). Transport Layer Security isn't an RPC security flavor or pseudo-flavor, so we shouldn't be conflating them when determining whether the access checks can be bypassed. Split check_nfsd_access() into two helpers, and have __fh_verify() call the helpers directly since __fh_verify() has logic that allows one or both of the checks to be skipped. All other sites will continue to call check_nfsd_access(). Link: https://lore.kernel.org/linux-nfs/ZjO3Qwf_G87yNXb2@aion/ Fixes: 9280c57 ("NFSD: Handle new xprtsec= export option") Cc: [email protected] Signed-off-by: Scott Mayhew <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent ab1c282 commit e4f574c

File tree

3 files changed

+83
-26
lines changed

3 files changed

+83
-26
lines changed

fs/nfsd/export.c

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,50 +1082,62 @@ static struct svc_export *exp_find(struct cache_detail *cd,
10821082
}
10831083

10841084
/**
1085-
* check_nfsd_access - check if access to export is allowed.
1085+
* check_xprtsec_policy - check if access to export is allowed by the
1086+
* xprtsec policy
10861087
* @exp: svc_export that is being accessed.
1087-
* @rqstp: svc_rqst attempting to access @exp (will be NULL for LOCALIO).
1088-
* @may_bypass_gss: reduce strictness of authorization check
1088+
* @rqstp: svc_rqst attempting to access @exp.
1089+
*
1090+
* Helper function for check_nfsd_access(). Note that callers should be
1091+
* using check_nfsd_access() instead of calling this function directly. The
1092+
* one exception is __fh_verify() since it has logic that may result in one
1093+
* or both of the helpers being skipped.
10891094
*
10901095
* Return values:
10911096
* %nfs_ok if access is granted, or
10921097
* %nfserr_wrongsec if access is denied
10931098
*/
1094-
__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
1095-
bool may_bypass_gss)
1099+
__be32 check_xprtsec_policy(struct svc_export *exp, struct svc_rqst *rqstp)
10961100
{
1097-
struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
1098-
struct svc_xprt *xprt;
1099-
1100-
/*
1101-
* If rqstp is NULL, this is a LOCALIO request which will only
1102-
* ever use a filehandle/credential pair for which access has
1103-
* been affirmed (by ACCESS or OPEN NFS requests) over the
1104-
* wire. So there is no need for further checks here.
1105-
*/
1106-
if (!rqstp)
1107-
return nfs_ok;
1108-
1109-
xprt = rqstp->rq_xprt;
1101+
struct svc_xprt *xprt = rqstp->rq_xprt;
11101102

11111103
if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_NONE) {
11121104
if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags))
1113-
goto ok;
1105+
return nfs_ok;
11141106
}
11151107
if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_TLS) {
11161108
if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) &&
11171109
!test_bit(XPT_PEER_AUTH, &xprt->xpt_flags))
1118-
goto ok;
1110+
return nfs_ok;
11191111
}
11201112
if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_MTLS) {
11211113
if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) &&
11221114
test_bit(XPT_PEER_AUTH, &xprt->xpt_flags))
1123-
goto ok;
1115+
return nfs_ok;
11241116
}
1125-
if (!may_bypass_gss)
1126-
goto denied;
1117+
return nfserr_wrongsec;
1118+
}
1119+
1120+
/**
1121+
* check_security_flavor - check if access to export is allowed by the
1122+
* security flavor
1123+
* @exp: svc_export that is being accessed.
1124+
* @rqstp: svc_rqst attempting to access @exp.
1125+
* @may_bypass_gss: reduce strictness of authorization check
1126+
*
1127+
* Helper function for check_nfsd_access(). Note that callers should be
1128+
* using check_nfsd_access() instead of calling this function directly. The
1129+
* one exception is __fh_verify() since it has logic that may result in one
1130+
* or both of the helpers being skipped.
1131+
*
1132+
* Return values:
1133+
* %nfs_ok if access is granted, or
1134+
* %nfserr_wrongsec if access is denied
1135+
*/
1136+
__be32 check_security_flavor(struct svc_export *exp, struct svc_rqst *rqstp,
1137+
bool may_bypass_gss)
1138+
{
1139+
struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
11271140

1128-
ok:
11291141
/* legacy gss-only clients are always OK: */
11301142
if (exp->ex_client == rqstp->rq_gssclient)
11311143
return nfs_ok;
@@ -1167,10 +1179,30 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
11671179
}
11681180
}
11691181

1170-
denied:
11711182
return nfserr_wrongsec;
11721183
}
11731184

1185+
/**
1186+
* check_nfsd_access - check if access to export is allowed.
1187+
* @exp: svc_export that is being accessed.
1188+
* @rqstp: svc_rqst attempting to access @exp.
1189+
* @may_bypass_gss: reduce strictness of authorization check
1190+
*
1191+
* Return values:
1192+
* %nfs_ok if access is granted, or
1193+
* %nfserr_wrongsec if access is denied
1194+
*/
1195+
__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
1196+
bool may_bypass_gss)
1197+
{
1198+
__be32 status;
1199+
1200+
status = check_xprtsec_policy(exp, rqstp);
1201+
if (status != nfs_ok)
1202+
return status;
1203+
return check_security_flavor(exp, rqstp, may_bypass_gss);
1204+
}
1205+
11741206
/*
11751207
* Uses rq_client and rq_gssclient to find an export; uses rq_client (an
11761208
* auth_unix client) if it's available and has secinfo information;

fs/nfsd/export.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ struct svc_expkey {
101101

102102
struct svc_cred;
103103
int nfsexp_flags(struct svc_cred *cred, struct svc_export *exp);
104+
__be32 check_xprtsec_policy(struct svc_export *exp, struct svc_rqst *rqstp);
105+
__be32 check_security_flavor(struct svc_export *exp, struct svc_rqst *rqstp,
106+
bool may_bypass_gss);
104107
__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
105108
bool may_bypass_gss);
106109

fs/nfsd/nfsfh.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,10 +364,30 @@ __fh_verify(struct svc_rqst *rqstp,
364364
if (error)
365365
goto out;
366366

367+
/*
368+
* If rqstp is NULL, this is a LOCALIO request which will only
369+
* ever use a filehandle/credential pair for which access has
370+
* been affirmed (by ACCESS or OPEN NFS requests) over the
371+
* wire. Skip both the xprtsec policy and the security flavor
372+
* checks.
373+
*/
374+
if (!rqstp)
375+
goto check_permissions;
376+
367377
if ((access & NFSD_MAY_NLM) && (exp->ex_flags & NFSEXP_NOAUTHNLM))
368378
/* NLM is allowed to fully bypass authentication */
369379
goto out;
370380

381+
/*
382+
* NLM is allowed to bypass the xprtsec policy check because lockd
383+
* doesn't support xprtsec.
384+
*/
385+
if (!(access & NFSD_MAY_NLM)) {
386+
error = check_xprtsec_policy(exp, rqstp);
387+
if (error)
388+
goto out;
389+
}
390+
371391
if (access & NFSD_MAY_BYPASS_GSS)
372392
may_bypass_gss = true;
373393
/*
@@ -379,13 +399,15 @@ __fh_verify(struct svc_rqst *rqstp,
379399
&& exp->ex_path.dentry == dentry)
380400
may_bypass_gss = true;
381401

382-
error = check_nfsd_access(exp, rqstp, may_bypass_gss);
402+
error = check_security_flavor(exp, rqstp, may_bypass_gss);
383403
if (error)
384404
goto out;
405+
385406
/* During LOCALIO call to fh_verify will be called with a NULL rqstp */
386407
if (rqstp)
387408
svc_xprt_set_valid(rqstp->rq_xprt);
388409

410+
check_permissions:
389411
/* Finally, check access permissions. */
390412
error = nfsd_permission(cred, exp, dentry, access);
391413
out:

0 commit comments

Comments
 (0)