Skip to content

Commit 779327c

Browse files
scottmayhewgregkh
authored andcommitted
nfsd: decouple the xprtsec policy check from check_nfsd_access()
commit e4f574c upstream. 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]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2d68f8a commit 779327c

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
@@ -1075,50 +1075,62 @@ static struct svc_export *exp_find(struct cache_detail *cd,
10751075
}
10761076

10771077
/**
1078-
* check_nfsd_access - check if access to export is allowed.
1078+
* check_xprtsec_policy - check if access to export is allowed by the
1079+
* xprtsec policy
10791080
* @exp: svc_export that is being accessed.
1080-
* @rqstp: svc_rqst attempting to access @exp (will be NULL for LOCALIO).
1081-
* @may_bypass_gss: reduce strictness of authorization check
1081+
* @rqstp: svc_rqst attempting to access @exp.
1082+
*
1083+
* Helper function for check_nfsd_access(). Note that callers should be
1084+
* using check_nfsd_access() instead of calling this function directly. The
1085+
* one exception is __fh_verify() since it has logic that may result in one
1086+
* or both of the helpers being skipped.
10821087
*
10831088
* Return values:
10841089
* %nfs_ok if access is granted, or
10851090
* %nfserr_wrongsec if access is denied
10861091
*/
1087-
__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
1088-
bool may_bypass_gss)
1092+
__be32 check_xprtsec_policy(struct svc_export *exp, struct svc_rqst *rqstp)
10891093
{
1090-
struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
1091-
struct svc_xprt *xprt;
1092-
1093-
/*
1094-
* If rqstp is NULL, this is a LOCALIO request which will only
1095-
* ever use a filehandle/credential pair for which access has
1096-
* been affirmed (by ACCESS or OPEN NFS requests) over the
1097-
* wire. So there is no need for further checks here.
1098-
*/
1099-
if (!rqstp)
1100-
return nfs_ok;
1101-
1102-
xprt = rqstp->rq_xprt;
1094+
struct svc_xprt *xprt = rqstp->rq_xprt;
11031095

11041096
if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_NONE) {
11051097
if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags))
1106-
goto ok;
1098+
return nfs_ok;
11071099
}
11081100
if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_TLS) {
11091101
if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) &&
11101102
!test_bit(XPT_PEER_AUTH, &xprt->xpt_flags))
1111-
goto ok;
1103+
return nfs_ok;
11121104
}
11131105
if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_MTLS) {
11141106
if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) &&
11151107
test_bit(XPT_PEER_AUTH, &xprt->xpt_flags))
1116-
goto ok;
1108+
return nfs_ok;
11171109
}
1118-
if (!may_bypass_gss)
1119-
goto denied;
1110+
return nfserr_wrongsec;
1111+
}
1112+
1113+
/**
1114+
* check_security_flavor - check if access to export is allowed by the
1115+
* security flavor
1116+
* @exp: svc_export that is being accessed.
1117+
* @rqstp: svc_rqst attempting to access @exp.
1118+
* @may_bypass_gss: reduce strictness of authorization check
1119+
*
1120+
* Helper function for check_nfsd_access(). Note that callers should be
1121+
* using check_nfsd_access() instead of calling this function directly. The
1122+
* one exception is __fh_verify() since it has logic that may result in one
1123+
* or both of the helpers being skipped.
1124+
*
1125+
* Return values:
1126+
* %nfs_ok if access is granted, or
1127+
* %nfserr_wrongsec if access is denied
1128+
*/
1129+
__be32 check_security_flavor(struct svc_export *exp, struct svc_rqst *rqstp,
1130+
bool may_bypass_gss)
1131+
{
1132+
struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
11201133

1121-
ok:
11221134
/* legacy gss-only clients are always OK: */
11231135
if (exp->ex_client == rqstp->rq_gssclient)
11241136
return nfs_ok;
@@ -1160,10 +1172,30 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
11601172
}
11611173
}
11621174

1163-
denied:
11641175
return nfserr_wrongsec;
11651176
}
11661177

1178+
/**
1179+
* check_nfsd_access - check if access to export is allowed.
1180+
* @exp: svc_export that is being accessed.
1181+
* @rqstp: svc_rqst attempting to access @exp.
1182+
* @may_bypass_gss: reduce strictness of authorization check
1183+
*
1184+
* Return values:
1185+
* %nfs_ok if access is granted, or
1186+
* %nfserr_wrongsec if access is denied
1187+
*/
1188+
__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
1189+
bool may_bypass_gss)
1190+
{
1191+
__be32 status;
1192+
1193+
status = check_xprtsec_policy(exp, rqstp);
1194+
if (status != nfs_ok)
1195+
return status;
1196+
return check_security_flavor(exp, rqstp, may_bypass_gss);
1197+
}
1198+
11671199
/*
11681200
* Uses rq_client and rq_gssclient to find an export; uses rq_client (an
11691201
* 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
@@ -363,10 +363,30 @@ __fh_verify(struct svc_rqst *rqstp,
363363
if (error)
364364
goto out;
365365

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

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

381-
error = check_nfsd_access(exp, rqstp, may_bypass_gss);
401+
error = check_security_flavor(exp, rqstp, may_bypass_gss);
382402
if (error)
383403
goto out;
404+
384405
/* During LOCALIO call to fh_verify will be called with a NULL rqstp */
385406
if (rqstp)
386407
svc_xprt_set_valid(rqstp->rq_xprt);
387408

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

0 commit comments

Comments
 (0)