diff mbox series

nfsd: Fix NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT

Message ID 20240912221917.23802-1-pali@kernel.org (mailing list archive)
State New
Headers show
Series nfsd: Fix NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT | expand

Commit Message

Pali Rohár Sept. 12, 2024, 10:19 p.m. UTC
Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
only GSS, but bypass any authentication method. This is problem specially
for NFS3 AUTH_NULL-only exports.

The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
section 2.3.2, to allow mounting NFS2/3 GSS-only export without
authentication. So few procedures which do not expose security risk used
during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
client mount operation to finish successfully.

The problem with current implementation is that for AUTH_NULL-only exports,
the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
AUTH_NONE on active mount, which makes the mount inaccessible.

Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
and really allow to bypass only exports which have some GSS auth flavor
enabled.

The result would be: For AUTH_NULL-only export if client attempts to do
mount with AUTH_UNIX flavor then it will receive access errors, which
instruct client that AUTH_UNIX flavor is not usable and will either try
other auth flavor (AUTH_NULL if enabled) or fails mount procedure.

This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 fs/nfsd/export.c   | 19 ++++++++++++++++++-
 fs/nfsd/export.h   |  2 +-
 fs/nfsd/nfs4proc.c |  2 +-
 fs/nfsd/nfs4xdr.c  |  2 +-
 fs/nfsd/nfsfh.c    | 12 +++++++++---
 fs/nfsd/vfs.c      |  2 +-
 6 files changed, 31 insertions(+), 8 deletions(-)

Comments

NeilBrown Sept. 12, 2024, 10:52 p.m. UTC | #1
On Fri, 13 Sep 2024, Pali Rohár wrote:
> Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
> only GSS, but bypass any authentication method. This is problem specially
> for NFS3 AUTH_NULL-only exports.
> 
> The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
> section 2.3.2, to allow mounting NFS2/3 GSS-only export without
> authentication. So few procedures which do not expose security risk used
> during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
> client mount operation to finish successfully.
> 
> The problem with current implementation is that for AUTH_NULL-only exports,
> the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
> attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
> enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
> AUTH_NONE on active mount, which makes the mount inaccessible.
> 
> Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
> and really allow to bypass only exports which have some GSS auth flavor
> enabled.
> 
> The result would be: For AUTH_NULL-only export if client attempts to do
> mount with AUTH_UNIX flavor then it will receive access errors, which
> instruct client that AUTH_UNIX flavor is not usable and will either try
> other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
> 
> This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
> client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
> AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).

The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
your change it doesn't.  I don't think we want to make that change.

I think that what you want to do makes sense.  Higher security can be
downgraded to AUTH_UNIX, but AUTH_NULL mustn't be upgraded to to
AUTH_UNIX.

Maybe that needs to be explicit in the code.  The bypass is ONLY allowed
for AUTH_UNIX and only if something other than AUTH_NULL is allowed.

Thanks,
NeilBrown



> 
> Signed-off-by: Pali Rohár <pali@kernel.org>
> ---
>  fs/nfsd/export.c   | 19 ++++++++++++++++++-
>  fs/nfsd/export.h   |  2 +-
>  fs/nfsd/nfs4proc.c |  2 +-
>  fs/nfsd/nfs4xdr.c  |  2 +-
>  fs/nfsd/nfsfh.c    | 12 +++++++++---
>  fs/nfsd/vfs.c      |  2 +-
>  6 files changed, 31 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
> index 50b3135d07ac..eb11d3fdffe1 100644
> --- a/fs/nfsd/export.c
> +++ b/fs/nfsd/export.c
> @@ -1074,7 +1074,7 @@ static struct svc_export *exp_find(struct cache_detail *cd,
>  	return exp;
>  }
>  
> -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss)
>  {
>  	struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
>  	struct svc_xprt *xprt = rqstp->rq_xprt;
> @@ -1120,6 +1120,23 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
>  	if (nfsd4_spo_must_allow(rqstp))
>  		return 0;
>  
> +	/* Some calls may be processed without authentication
> +	 * on GSS exports. For example NFS2/3 calls on root
> +	 * directory, see section 2.3.2 of rfc 2623.
> +	 * For "may_bypass_gss" check that export has really
> +	 * enabled some GSS flavor and also check that the
> +	 * used auth flavor is without auth (none or sys).
> +	 */
> +	if (may_bypass_gss && (
> +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
> +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)) {
> +		for (f = exp->ex_flavors; f < end; f++) {
> +			if (f->pseudoflavor == RPC_AUTH_GSS ||
> +			    f->pseudoflavor >= RPC_AUTH_GSS_KRB5)
> +				return 0;
> +		}
> +	}
> +
>  denied:
>  	return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
>  }
> diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
> index ca9dc230ae3d..dc7cf4f6ac53 100644
> --- a/fs/nfsd/export.h
> +++ b/fs/nfsd/export.h
> @@ -100,7 +100,7 @@ struct svc_expkey {
>  #define EX_WGATHER(exp)		((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
>  
>  int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp);
> -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
> +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss);
>  
>  /*
>   * Function declarations
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 2e39cf2e502a..0f67f4a7b8b2 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -2791,7 +2791,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);
> +				op->status = check_nfsd_access(current_fh->fh_export, rqstp, false);
>  		}
>  encode_op:
>  		if (op->status == nfserr_replay_me) {
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 97f583777972..b45ea5757652 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -3775,7 +3775,7 @@ nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name,
>  			nfserr = nfserrno(err);
>  			goto out_put;
>  		}
> -		nfserr = check_nfsd_access(exp, cd->rd_rqstp);
> +		nfserr = check_nfsd_access(exp, cd->rd_rqstp, false);
>  		if (nfserr)
>  			goto out_put;
>  
> diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> index dd4e11a703aa..ed0eabfa3cb0 100644
> --- a/fs/nfsd/nfsfh.c
> +++ b/fs/nfsd/nfsfh.c
> @@ -329,6 +329,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
>  {
>  	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
>  	struct svc_export *exp = NULL;
> +	bool may_bypass_gss = false;
>  	struct dentry	*dentry;
>  	__be32		error;
>  
> @@ -375,8 +376,13 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
>  	 * which clients virtually always use auth_sys for,
>  	 * even while using RPCSEC_GSS for NFS.
>  	 */
> -	if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
> +	if (access & NFSD_MAY_LOCK)
>  		goto skip_pseudoflavor_check;
> +	/*
> +	 * NFS4 PUTFH may bypass GSS (see nfsd4_putfh() in nfs4proc.c).
> +	 */
> +	if (access & NFSD_MAY_BYPASS_GSS)
> +		may_bypass_gss = true;
>  	/*
>  	 * Clients may expect to be able to use auth_sys during mount,
>  	 * even if they use gss for everything else; see section 2.3.2
> @@ -384,9 +390,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
>  	 */
>  	if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
>  			&& exp->ex_path.dentry == dentry)
> -		goto skip_pseudoflavor_check;
> +		may_bypass_gss = true;
>  
> -	error = check_nfsd_access(exp, rqstp);
> +	error = check_nfsd_access(exp, rqstp, may_bypass_gss);
>  	if (error)
>  		goto out;
>  
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index 29b1f3613800..b2f5ea7c2187 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -320,7 +320,7 @@ 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);
> +	err = check_nfsd_access(exp, rqstp, false);
>  	if (err)
>  		goto out;
>  	/*
> -- 
> 2.20.1
> 
>
Pali Rohár Sept. 12, 2024, 11 p.m. UTC | #2
On Friday 13 September 2024 08:52:20 NeilBrown wrote:
> On Fri, 13 Sep 2024, Pali Rohár wrote:
> > Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
> > only GSS, but bypass any authentication method. This is problem specially
> > for NFS3 AUTH_NULL-only exports.
> > 
> > The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
> > section 2.3.2, to allow mounting NFS2/3 GSS-only export without
> > authentication. So few procedures which do not expose security risk used
> > during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
> > client mount operation to finish successfully.
> > 
> > The problem with current implementation is that for AUTH_NULL-only exports,
> > the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
> > attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
> > enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
> > AUTH_NONE on active mount, which makes the mount inaccessible.
> > 
> > Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
> > and really allow to bypass only exports which have some GSS auth flavor
> > enabled.
> > 
> > The result would be: For AUTH_NULL-only export if client attempts to do
> > mount with AUTH_UNIX flavor then it will receive access errors, which
> > instruct client that AUTH_UNIX flavor is not usable and will either try
> > other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
> > 
> > This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
> > client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
> > AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
> 
> The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
> your change it doesn't.  I don't think we want to make that change.

Ok. But this is not obvious really obvious ass the option has GSS in its name.

> I think that what you want to do makes sense.  Higher security can be
> downgraded to AUTH_UNIX, but AUTH_NULL mustn't be upgraded to to
> AUTH_UNIX.
> 
> Maybe that needs to be explicit in the code.  The bypass is ONLY allowed
> for AUTH_UNIX and only if something other than AUTH_NULL is allowed.

Ok, this sound good.

> Thanks,
> NeilBrown
> 
> 
> 
> > 
> > Signed-off-by: Pali Rohár <pali@kernel.org>
> > ---
> >  fs/nfsd/export.c   | 19 ++++++++++++++++++-
> >  fs/nfsd/export.h   |  2 +-
> >  fs/nfsd/nfs4proc.c |  2 +-
> >  fs/nfsd/nfs4xdr.c  |  2 +-
> >  fs/nfsd/nfsfh.c    | 12 +++++++++---
> >  fs/nfsd/vfs.c      |  2 +-
> >  6 files changed, 31 insertions(+), 8 deletions(-)
> > 
> > diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
> > index 50b3135d07ac..eb11d3fdffe1 100644
> > --- a/fs/nfsd/export.c
> > +++ b/fs/nfsd/export.c
> > @@ -1074,7 +1074,7 @@ static struct svc_export *exp_find(struct cache_detail *cd,
> >  	return exp;
> >  }
> >  
> > -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> > +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss)
> >  {
> >  	struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
> >  	struct svc_xprt *xprt = rqstp->rq_xprt;
> > @@ -1120,6 +1120,23 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> >  	if (nfsd4_spo_must_allow(rqstp))
> >  		return 0;
> >  
> > +	/* Some calls may be processed without authentication
> > +	 * on GSS exports. For example NFS2/3 calls on root
> > +	 * directory, see section 2.3.2 of rfc 2623.
> > +	 * For "may_bypass_gss" check that export has really
> > +	 * enabled some GSS flavor and also check that the
> > +	 * used auth flavor is without auth (none or sys).
> > +	 */
> > +	if (may_bypass_gss && (
> > +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
> > +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)) {
> > +		for (f = exp->ex_flavors; f < end; f++) {
> > +			if (f->pseudoflavor == RPC_AUTH_GSS ||
> > +			    f->pseudoflavor >= RPC_AUTH_GSS_KRB5)
> > +				return 0;
> > +		}
> > +	}
> > +
> >  denied:
> >  	return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
> >  }
> > diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
> > index ca9dc230ae3d..dc7cf4f6ac53 100644
> > --- a/fs/nfsd/export.h
> > +++ b/fs/nfsd/export.h
> > @@ -100,7 +100,7 @@ struct svc_expkey {
> >  #define EX_WGATHER(exp)		((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
> >  
> >  int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp);
> > -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
> > +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss);
> >  
> >  /*
> >   * Function declarations
> > diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> > index 2e39cf2e502a..0f67f4a7b8b2 100644
> > --- a/fs/nfsd/nfs4proc.c
> > +++ b/fs/nfsd/nfs4proc.c
> > @@ -2791,7 +2791,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);
> > +				op->status = check_nfsd_access(current_fh->fh_export, rqstp, false);
> >  		}
> >  encode_op:
> >  		if (op->status == nfserr_replay_me) {
> > diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> > index 97f583777972..b45ea5757652 100644
> > --- a/fs/nfsd/nfs4xdr.c
> > +++ b/fs/nfsd/nfs4xdr.c
> > @@ -3775,7 +3775,7 @@ nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name,
> >  			nfserr = nfserrno(err);
> >  			goto out_put;
> >  		}
> > -		nfserr = check_nfsd_access(exp, cd->rd_rqstp);
> > +		nfserr = check_nfsd_access(exp, cd->rd_rqstp, false);
> >  		if (nfserr)
> >  			goto out_put;
> >  
> > diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> > index dd4e11a703aa..ed0eabfa3cb0 100644
> > --- a/fs/nfsd/nfsfh.c
> > +++ b/fs/nfsd/nfsfh.c
> > @@ -329,6 +329,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> >  {
> >  	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
> >  	struct svc_export *exp = NULL;
> > +	bool may_bypass_gss = false;
> >  	struct dentry	*dentry;
> >  	__be32		error;
> >  
> > @@ -375,8 +376,13 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> >  	 * which clients virtually always use auth_sys for,
> >  	 * even while using RPCSEC_GSS for NFS.
> >  	 */
> > -	if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
> > +	if (access & NFSD_MAY_LOCK)
> >  		goto skip_pseudoflavor_check;
> > +	/*
> > +	 * NFS4 PUTFH may bypass GSS (see nfsd4_putfh() in nfs4proc.c).
> > +	 */
> > +	if (access & NFSD_MAY_BYPASS_GSS)
> > +		may_bypass_gss = true;
> >  	/*
> >  	 * Clients may expect to be able to use auth_sys during mount,
> >  	 * even if they use gss for everything else; see section 2.3.2
> > @@ -384,9 +390,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> >  	 */
> >  	if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
> >  			&& exp->ex_path.dentry == dentry)
> > -		goto skip_pseudoflavor_check;
> > +		may_bypass_gss = true;
> >  
> > -	error = check_nfsd_access(exp, rqstp);
> > +	error = check_nfsd_access(exp, rqstp, may_bypass_gss);
> >  	if (error)
> >  		goto out;
> >  
> > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> > index 29b1f3613800..b2f5ea7c2187 100644
> > --- a/fs/nfsd/vfs.c
> > +++ b/fs/nfsd/vfs.c
> > @@ -320,7 +320,7 @@ 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);
> > +	err = check_nfsd_access(exp, rqstp, false);
> >  	if (err)
> >  		goto out;
> >  	/*
> > -- 
> > 2.20.1
> > 
> > 
>
Chuck Lever Oct. 6, 2024, 5:50 p.m. UTC | #3
On Fri, Sep 13, 2024 at 08:52:20AM +1000, NeilBrown wrote:
> On Fri, 13 Sep 2024, Pali Rohár wrote:
> > Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
> > only GSS, but bypass any authentication method. This is problem specially
> > for NFS3 AUTH_NULL-only exports.
> > 
> > The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
> > section 2.3.2, to allow mounting NFS2/3 GSS-only export without
> > authentication. So few procedures which do not expose security risk used
> > during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
> > client mount operation to finish successfully.
> > 
> > The problem with current implementation is that for AUTH_NULL-only exports,
> > the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
> > attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
> > enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
> > AUTH_NONE on active mount, which makes the mount inaccessible.
> > 
> > Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
> > and really allow to bypass only exports which have some GSS auth flavor
> > enabled.
> > 
> > The result would be: For AUTH_NULL-only export if client attempts to do
> > mount with AUTH_UNIX flavor then it will receive access errors, which
> > instruct client that AUTH_UNIX flavor is not usable and will either try
> > other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
> > 
> > This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
> > client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
> > AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
> 
> The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
> your change it doesn't.  I don't think we want to make that change.

Neil, I'm not seeing this, I must be missing something.

RPC_AUTH_TLS is used only on NULL procedures.

The export's xprtsec= setting determines whether a TLS session must
be present to access the files on the export. If the TLS session
meets the xprtsec= policy, then the normal user authentication
settings apply. In other words, I don't think execution gets close
to check_nfsd_access() unless the xprtsec policy setting is met.

I'm not convinced check_nfsd_access() needs to care about
RPC_AUTH_TLS. Can you expand a little on your concern?


> I think that what you want to do makes sense.  Higher security can be
> downgraded to AUTH_UNIX, but AUTH_NULL mustn't be upgraded to to
> AUTH_UNIX.
> 
> Maybe that needs to be explicit in the code.  The bypass is ONLY allowed
> for AUTH_UNIX and only if something other than AUTH_NULL is allowed.
> 
> Thanks,
> NeilBrown
> 
> 
> 
> > 
> > Signed-off-by: Pali Rohár <pali@kernel.org>
> > ---
> >  fs/nfsd/export.c   | 19 ++++++++++++++++++-
> >  fs/nfsd/export.h   |  2 +-
> >  fs/nfsd/nfs4proc.c |  2 +-
> >  fs/nfsd/nfs4xdr.c  |  2 +-
> >  fs/nfsd/nfsfh.c    | 12 +++++++++---
> >  fs/nfsd/vfs.c      |  2 +-
> >  6 files changed, 31 insertions(+), 8 deletions(-)
> > 
> > diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
> > index 50b3135d07ac..eb11d3fdffe1 100644
> > --- a/fs/nfsd/export.c
> > +++ b/fs/nfsd/export.c
> > @@ -1074,7 +1074,7 @@ static struct svc_export *exp_find(struct cache_detail *cd,
> >  	return exp;
> >  }
> >  
> > -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> > +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss)
> >  {
> >  	struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
> >  	struct svc_xprt *xprt = rqstp->rq_xprt;
> > @@ -1120,6 +1120,23 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> >  	if (nfsd4_spo_must_allow(rqstp))
> >  		return 0;
> >  
> > +	/* Some calls may be processed without authentication
> > +	 * on GSS exports. For example NFS2/3 calls on root
> > +	 * directory, see section 2.3.2 of rfc 2623.
> > +	 * For "may_bypass_gss" check that export has really
> > +	 * enabled some GSS flavor and also check that the
> > +	 * used auth flavor is without auth (none or sys).
> > +	 */
> > +	if (may_bypass_gss && (
> > +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
> > +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)) {
> > +		for (f = exp->ex_flavors; f < end; f++) {
> > +			if (f->pseudoflavor == RPC_AUTH_GSS ||
> > +			    f->pseudoflavor >= RPC_AUTH_GSS_KRB5)
> > +				return 0;
> > +		}
> > +	}
> > +
> >  denied:
> >  	return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
> >  }
> > diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
> > index ca9dc230ae3d..dc7cf4f6ac53 100644
> > --- a/fs/nfsd/export.h
> > +++ b/fs/nfsd/export.h
> > @@ -100,7 +100,7 @@ struct svc_expkey {
> >  #define EX_WGATHER(exp)		((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
> >  
> >  int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp);
> > -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
> > +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss);
> >  
> >  /*
> >   * Function declarations
> > diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> > index 2e39cf2e502a..0f67f4a7b8b2 100644
> > --- a/fs/nfsd/nfs4proc.c
> > +++ b/fs/nfsd/nfs4proc.c
> > @@ -2791,7 +2791,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);
> > +				op->status = check_nfsd_access(current_fh->fh_export, rqstp, false);
> >  		}
> >  encode_op:
> >  		if (op->status == nfserr_replay_me) {
> > diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> > index 97f583777972..b45ea5757652 100644
> > --- a/fs/nfsd/nfs4xdr.c
> > +++ b/fs/nfsd/nfs4xdr.c
> > @@ -3775,7 +3775,7 @@ nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name,
> >  			nfserr = nfserrno(err);
> >  			goto out_put;
> >  		}
> > -		nfserr = check_nfsd_access(exp, cd->rd_rqstp);
> > +		nfserr = check_nfsd_access(exp, cd->rd_rqstp, false);
> >  		if (nfserr)
> >  			goto out_put;
> >  
> > diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> > index dd4e11a703aa..ed0eabfa3cb0 100644
> > --- a/fs/nfsd/nfsfh.c
> > +++ b/fs/nfsd/nfsfh.c
> > @@ -329,6 +329,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> >  {
> >  	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
> >  	struct svc_export *exp = NULL;
> > +	bool may_bypass_gss = false;
> >  	struct dentry	*dentry;
> >  	__be32		error;
> >  
> > @@ -375,8 +376,13 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> >  	 * which clients virtually always use auth_sys for,
> >  	 * even while using RPCSEC_GSS for NFS.
> >  	 */
> > -	if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
> > +	if (access & NFSD_MAY_LOCK)
> >  		goto skip_pseudoflavor_check;
> > +	/*
> > +	 * NFS4 PUTFH may bypass GSS (see nfsd4_putfh() in nfs4proc.c).
> > +	 */
> > +	if (access & NFSD_MAY_BYPASS_GSS)
> > +		may_bypass_gss = true;
> >  	/*
> >  	 * Clients may expect to be able to use auth_sys during mount,
> >  	 * even if they use gss for everything else; see section 2.3.2
> > @@ -384,9 +390,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> >  	 */
> >  	if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
> >  			&& exp->ex_path.dentry == dentry)
> > -		goto skip_pseudoflavor_check;
> > +		may_bypass_gss = true;
> >  
> > -	error = check_nfsd_access(exp, rqstp);
> > +	error = check_nfsd_access(exp, rqstp, may_bypass_gss);
> >  	if (error)
> >  		goto out;
> >  
> > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> > index 29b1f3613800..b2f5ea7c2187 100644
> > --- a/fs/nfsd/vfs.c
> > +++ b/fs/nfsd/vfs.c
> > @@ -320,7 +320,7 @@ 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);
> > +	err = check_nfsd_access(exp, rqstp, false);
> >  	if (err)
> >  		goto out;
> >  	/*
> > -- 
> > 2.20.1
> > 
> > 
>
NeilBrown Oct. 6, 2024, 10:13 p.m. UTC | #4
On Mon, 07 Oct 2024, Chuck Lever wrote:
> On Fri, Sep 13, 2024 at 08:52:20AM +1000, NeilBrown wrote:
> > On Fri, 13 Sep 2024, Pali Rohár wrote:
> > > Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
> > > only GSS, but bypass any authentication method. This is problem specially
> > > for NFS3 AUTH_NULL-only exports.
> > > 
> > > The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
> > > section 2.3.2, to allow mounting NFS2/3 GSS-only export without
> > > authentication. So few procedures which do not expose security risk used
> > > during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
> > > client mount operation to finish successfully.
> > > 
> > > The problem with current implementation is that for AUTH_NULL-only exports,
> > > the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
> > > attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
> > > enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
> > > AUTH_NONE on active mount, which makes the mount inaccessible.
> > > 
> > > Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
> > > and really allow to bypass only exports which have some GSS auth flavor
> > > enabled.
> > > 
> > > The result would be: For AUTH_NULL-only export if client attempts to do
> > > mount with AUTH_UNIX flavor then it will receive access errors, which
> > > instruct client that AUTH_UNIX flavor is not usable and will either try
> > > other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
> > > 
> > > This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
> > > client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
> > > AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
> > 
> > The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
> > your change it doesn't.  I don't think we want to make that change.
> 
> Neil, I'm not seeing this, I must be missing something.
> 
> RPC_AUTH_TLS is used only on NULL procedures.
> 
> The export's xprtsec= setting determines whether a TLS session must
> be present to access the files on the export. If the TLS session
> meets the xprtsec= policy, then the normal user authentication
> settings apply. In other words, I don't think execution gets close
> to check_nfsd_access() unless the xprtsec policy setting is met.

check_nfsd_access() is literally the ONLY place that ->ex_xprtsec_modes
is tested and that seems to be where xprtsec= export settings are stored.

> 
> I'm not convinced check_nfsd_access() needs to care about
> RPC_AUTH_TLS. Can you expand a little on your concern?

Probably it doesn't care about RPC_AUTH_TLS which as you say is only
used on NULL procedures when setting up the TLS connection.

But it *does* care about NFS_XPRTSEC_MTLS etc.

But I now see that RPC_AUTH_TLS is never reported by OP_SECINFO as an
acceptable flavour, so the client cannot dynamically determine that TLS
is required.  So there is no value in giving non-tls clients access to
xprtsec=mtls exports so they can discover that for themselves.  The
client needs to explicitly mount with tls, or possibly the client can
opportunistically try TLS in every case, and call back.

So the original patch is OK.

NeilBrown


> 
> 
> > I think that what you want to do makes sense.  Higher security can be
> > downgraded to AUTH_UNIX, but AUTH_NULL mustn't be upgraded to to
> > AUTH_UNIX.
> > 
> > Maybe that needs to be explicit in the code.  The bypass is ONLY allowed
> > for AUTH_UNIX and only if something other than AUTH_NULL is allowed.
> > 
> > Thanks,
> > NeilBrown
> > 
> > 
> > 
> > > 
> > > Signed-off-by: Pali Rohár <pali@kernel.org>
> > > ---
> > >  fs/nfsd/export.c   | 19 ++++++++++++++++++-
> > >  fs/nfsd/export.h   |  2 +-
> > >  fs/nfsd/nfs4proc.c |  2 +-
> > >  fs/nfsd/nfs4xdr.c  |  2 +-
> > >  fs/nfsd/nfsfh.c    | 12 +++++++++---
> > >  fs/nfsd/vfs.c      |  2 +-
> > >  6 files changed, 31 insertions(+), 8 deletions(-)
> > > 
> > > diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
> > > index 50b3135d07ac..eb11d3fdffe1 100644
> > > --- a/fs/nfsd/export.c
> > > +++ b/fs/nfsd/export.c
> > > @@ -1074,7 +1074,7 @@ static struct svc_export *exp_find(struct cache_detail *cd,
> > >  	return exp;
> > >  }
> > >  
> > > -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> > > +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss)
> > >  {
> > >  	struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
> > >  	struct svc_xprt *xprt = rqstp->rq_xprt;
> > > @@ -1120,6 +1120,23 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> > >  	if (nfsd4_spo_must_allow(rqstp))
> > >  		return 0;
> > >  
> > > +	/* Some calls may be processed without authentication
> > > +	 * on GSS exports. For example NFS2/3 calls on root
> > > +	 * directory, see section 2.3.2 of rfc 2623.
> > > +	 * For "may_bypass_gss" check that export has really
> > > +	 * enabled some GSS flavor and also check that the
> > > +	 * used auth flavor is without auth (none or sys).
> > > +	 */
> > > +	if (may_bypass_gss && (
> > > +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
> > > +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)) {
> > > +		for (f = exp->ex_flavors; f < end; f++) {
> > > +			if (f->pseudoflavor == RPC_AUTH_GSS ||
> > > +			    f->pseudoflavor >= RPC_AUTH_GSS_KRB5)
> > > +				return 0;
> > > +		}
> > > +	}
> > > +
> > >  denied:
> > >  	return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
> > >  }
> > > diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
> > > index ca9dc230ae3d..dc7cf4f6ac53 100644
> > > --- a/fs/nfsd/export.h
> > > +++ b/fs/nfsd/export.h
> > > @@ -100,7 +100,7 @@ struct svc_expkey {
> > >  #define EX_WGATHER(exp)		((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
> > >  
> > >  int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp);
> > > -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
> > > +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss);
> > >  
> > >  /*
> > >   * Function declarations
> > > diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> > > index 2e39cf2e502a..0f67f4a7b8b2 100644
> > > --- a/fs/nfsd/nfs4proc.c
> > > +++ b/fs/nfsd/nfs4proc.c
> > > @@ -2791,7 +2791,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);
> > > +				op->status = check_nfsd_access(current_fh->fh_export, rqstp, false);
> > >  		}
> > >  encode_op:
> > >  		if (op->status == nfserr_replay_me) {
> > > diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> > > index 97f583777972..b45ea5757652 100644
> > > --- a/fs/nfsd/nfs4xdr.c
> > > +++ b/fs/nfsd/nfs4xdr.c
> > > @@ -3775,7 +3775,7 @@ nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name,
> > >  			nfserr = nfserrno(err);
> > >  			goto out_put;
> > >  		}
> > > -		nfserr = check_nfsd_access(exp, cd->rd_rqstp);
> > > +		nfserr = check_nfsd_access(exp, cd->rd_rqstp, false);
> > >  		if (nfserr)
> > >  			goto out_put;
> > >  
> > > diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> > > index dd4e11a703aa..ed0eabfa3cb0 100644
> > > --- a/fs/nfsd/nfsfh.c
> > > +++ b/fs/nfsd/nfsfh.c
> > > @@ -329,6 +329,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> > >  {
> > >  	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
> > >  	struct svc_export *exp = NULL;
> > > +	bool may_bypass_gss = false;
> > >  	struct dentry	*dentry;
> > >  	__be32		error;
> > >  
> > > @@ -375,8 +376,13 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> > >  	 * which clients virtually always use auth_sys for,
> > >  	 * even while using RPCSEC_GSS for NFS.
> > >  	 */
> > > -	if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
> > > +	if (access & NFSD_MAY_LOCK)
> > >  		goto skip_pseudoflavor_check;
> > > +	/*
> > > +	 * NFS4 PUTFH may bypass GSS (see nfsd4_putfh() in nfs4proc.c).
> > > +	 */
> > > +	if (access & NFSD_MAY_BYPASS_GSS)
> > > +		may_bypass_gss = true;
> > >  	/*
> > >  	 * Clients may expect to be able to use auth_sys during mount,
> > >  	 * even if they use gss for everything else; see section 2.3.2
> > > @@ -384,9 +390,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> > >  	 */
> > >  	if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
> > >  			&& exp->ex_path.dentry == dentry)
> > > -		goto skip_pseudoflavor_check;
> > > +		may_bypass_gss = true;
> > >  
> > > -	error = check_nfsd_access(exp, rqstp);
> > > +	error = check_nfsd_access(exp, rqstp, may_bypass_gss);
> > >  	if (error)
> > >  		goto out;
> > >  
> > > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> > > index 29b1f3613800..b2f5ea7c2187 100644
> > > --- a/fs/nfsd/vfs.c
> > > +++ b/fs/nfsd/vfs.c
> > > @@ -320,7 +320,7 @@ 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);
> > > +	err = check_nfsd_access(exp, rqstp, false);
> > >  	if (err)
> > >  		goto out;
> > >  	/*
> > > -- 
> > > 2.20.1
> > > 
> > > 
> > 
> 
> -- 
> Chuck Lever
>
Pali Rohár Oct. 6, 2024, 10:29 p.m. UTC | #5
On Monday 07 October 2024 09:13:17 NeilBrown wrote:
> On Mon, 07 Oct 2024, Chuck Lever wrote:
> > On Fri, Sep 13, 2024 at 08:52:20AM +1000, NeilBrown wrote:
> > > On Fri, 13 Sep 2024, Pali Rohár wrote:
> > > > Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
> > > > only GSS, but bypass any authentication method. This is problem specially
> > > > for NFS3 AUTH_NULL-only exports.
> > > > 
> > > > The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
> > > > section 2.3.2, to allow mounting NFS2/3 GSS-only export without
> > > > authentication. So few procedures which do not expose security risk used
> > > > during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
> > > > client mount operation to finish successfully.
> > > > 
> > > > The problem with current implementation is that for AUTH_NULL-only exports,
> > > > the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
> > > > attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
> > > > enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
> > > > AUTH_NONE on active mount, which makes the mount inaccessible.
> > > > 
> > > > Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
> > > > and really allow to bypass only exports which have some GSS auth flavor
> > > > enabled.
> > > > 
> > > > The result would be: For AUTH_NULL-only export if client attempts to do
> > > > mount with AUTH_UNIX flavor then it will receive access errors, which
> > > > instruct client that AUTH_UNIX flavor is not usable and will either try
> > > > other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
> > > > 
> > > > This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
> > > > client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
> > > > AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
> > > 
> > > The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
> > > your change it doesn't.  I don't think we want to make that change.
> > 
> > Neil, I'm not seeing this, I must be missing something.
> > 
> > RPC_AUTH_TLS is used only on NULL procedures.
> > 
> > The export's xprtsec= setting determines whether a TLS session must
> > be present to access the files on the export. If the TLS session
> > meets the xprtsec= policy, then the normal user authentication
> > settings apply. In other words, I don't think execution gets close
> > to check_nfsd_access() unless the xprtsec policy setting is met.
> 
> check_nfsd_access() is literally the ONLY place that ->ex_xprtsec_modes
> is tested and that seems to be where xprtsec= export settings are stored.
> 
> > 
> > I'm not convinced check_nfsd_access() needs to care about
> > RPC_AUTH_TLS. Can you expand a little on your concern?
> 
> Probably it doesn't care about RPC_AUTH_TLS which as you say is only
> used on NULL procedures when setting up the TLS connection.
> 
> But it *does* care about NFS_XPRTSEC_MTLS etc.
> 
> But I now see that RPC_AUTH_TLS is never reported by OP_SECINFO as an
> acceptable flavour, so the client cannot dynamically determine that TLS
> is required.

Why is not RPC_AUTH_TLS announced in NFS4 OP_SECINFO? Should not NFS4
OP_SECINFO report all possible auth methods for particular filehandle?

> So there is no value in giving non-tls clients access to
> xprtsec=mtls exports so they can discover that for themselves.  The
> client needs to explicitly mount with tls, or possibly the client can
> opportunistically try TLS in every case, and call back.
> 
> So the original patch is OK.
> 
> NeilBrown
Chuck Lever Oct. 6, 2024, 10:58 p.m. UTC | #6
> On Oct 6, 2024, at 6:29 PM, Pali Rohár <pali@kernel.org> wrote:
> 
> On Monday 07 October 2024 09:13:17 NeilBrown wrote:
>> On Mon, 07 Oct 2024, Chuck Lever wrote:
>>> On Fri, Sep 13, 2024 at 08:52:20AM +1000, NeilBrown wrote:
>>>> On Fri, 13 Sep 2024, Pali Rohár wrote:
>>>>> Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
>>>>> only GSS, but bypass any authentication method. This is problem specially
>>>>> for NFS3 AUTH_NULL-only exports.
>>>>> 
>>>>> The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
>>>>> section 2.3.2, to allow mounting NFS2/3 GSS-only export without
>>>>> authentication. So few procedures which do not expose security risk used
>>>>> during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
>>>>> client mount operation to finish successfully.
>>>>> 
>>>>> The problem with current implementation is that for AUTH_NULL-only exports,
>>>>> the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
>>>>> attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
>>>>> enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
>>>>> AUTH_NONE on active mount, which makes the mount inaccessible.
>>>>> 
>>>>> Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
>>>>> and really allow to bypass only exports which have some GSS auth flavor
>>>>> enabled.
>>>>> 
>>>>> The result would be: For AUTH_NULL-only export if client attempts to do
>>>>> mount with AUTH_UNIX flavor then it will receive access errors, which
>>>>> instruct client that AUTH_UNIX flavor is not usable and will either try
>>>>> other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
>>>>> 
>>>>> This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
>>>>> client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
>>>>> AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
>>>> 
>>>> The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
>>>> your change it doesn't.  I don't think we want to make that change.
>>> 
>>> Neil, I'm not seeing this, I must be missing something.
>>> 
>>> RPC_AUTH_TLS is used only on NULL procedures.
>>> 
>>> The export's xprtsec= setting determines whether a TLS session must
>>> be present to access the files on the export. If the TLS session
>>> meets the xprtsec= policy, then the normal user authentication
>>> settings apply. In other words, I don't think execution gets close
>>> to check_nfsd_access() unless the xprtsec policy setting is met.
>> 
>> check_nfsd_access() is literally the ONLY place that ->ex_xprtsec_modes
>> is tested and that seems to be where xprtsec= export settings are stored.
>> 
>>> 
>>> I'm not convinced check_nfsd_access() needs to care about
>>> RPC_AUTH_TLS. Can you expand a little on your concern?
>> 
>> Probably it doesn't care about RPC_AUTH_TLS which as you say is only
>> used on NULL procedures when setting up the TLS connection.
>> 
>> But it *does* care about NFS_XPRTSEC_MTLS etc.
>> 
>> But I now see that RPC_AUTH_TLS is never reported by OP_SECINFO as an
>> acceptable flavour, so the client cannot dynamically determine that TLS
>> is required.
> 
> Why is not RPC_AUTH_TLS announced in NFS4 OP_SECINFO? Should not NFS4
> OP_SECINFO report all possible auth methods for particular filehandle?

SECINFO reports user authentication flavors and pseudoflavors.

RPC_AUTH_TLS is not a user authentication flavor, it is merely
a query to see if the server peer supports RPC-with-TLS.

So far the nfsv4 WG has not been able to come to consensus
about how a server's transport layer security policies should
be reported to clients. There does not seem to be a clean way
to do that with existing NFSv4 protocol elements, so a
protocol extension might be needed.


>> So there is no value in giving non-tls clients access to
>> xprtsec=mtls exports so they can discover that for themselves.  The
>> client needs to explicitly mount with tls, or possibly the client can
>> opportunistically try TLS in every case, and call back.
>> 
>> So the original patch is OK.
>> 
>> NeilBrown


--
Chuck Lever
NeilBrown Oct. 6, 2024, 11:36 p.m. UTC | #7
On Mon, 07 Oct 2024, Chuck Lever III wrote:
> 
> 
> > On Oct 6, 2024, at 6:29 PM, Pali Rohár <pali@kernel.org> wrote:
> > 
> > On Monday 07 October 2024 09:13:17 NeilBrown wrote:
> >> On Mon, 07 Oct 2024, Chuck Lever wrote:
> >>> On Fri, Sep 13, 2024 at 08:52:20AM +1000, NeilBrown wrote:
> >>>> On Fri, 13 Sep 2024, Pali Rohár wrote:
> >>>>> Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
> >>>>> only GSS, but bypass any authentication method. This is problem specially
> >>>>> for NFS3 AUTH_NULL-only exports.
> >>>>> 
> >>>>> The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
> >>>>> section 2.3.2, to allow mounting NFS2/3 GSS-only export without
> >>>>> authentication. So few procedures which do not expose security risk used
> >>>>> during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
> >>>>> client mount operation to finish successfully.
> >>>>> 
> >>>>> The problem with current implementation is that for AUTH_NULL-only exports,
> >>>>> the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
> >>>>> attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
> >>>>> enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
> >>>>> AUTH_NONE on active mount, which makes the mount inaccessible.
> >>>>> 
> >>>>> Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
> >>>>> and really allow to bypass only exports which have some GSS auth flavor
> >>>>> enabled.
> >>>>> 
> >>>>> The result would be: For AUTH_NULL-only export if client attempts to do
> >>>>> mount with AUTH_UNIX flavor then it will receive access errors, which
> >>>>> instruct client that AUTH_UNIX flavor is not usable and will either try
> >>>>> other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
> >>>>> 
> >>>>> This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
> >>>>> client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
> >>>>> AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
> >>>> 
> >>>> The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
> >>>> your change it doesn't.  I don't think we want to make that change.
> >>> 
> >>> Neil, I'm not seeing this, I must be missing something.
> >>> 
> >>> RPC_AUTH_TLS is used only on NULL procedures.
> >>> 
> >>> The export's xprtsec= setting determines whether a TLS session must
> >>> be present to access the files on the export. If the TLS session
> >>> meets the xprtsec= policy, then the normal user authentication
> >>> settings apply. In other words, I don't think execution gets close
> >>> to check_nfsd_access() unless the xprtsec policy setting is met.
> >> 
> >> check_nfsd_access() is literally the ONLY place that ->ex_xprtsec_modes
> >> is tested and that seems to be where xprtsec= export settings are stored.
> >> 
> >>> 
> >>> I'm not convinced check_nfsd_access() needs to care about
> >>> RPC_AUTH_TLS. Can you expand a little on your concern?
> >> 
> >> Probably it doesn't care about RPC_AUTH_TLS which as you say is only
> >> used on NULL procedures when setting up the TLS connection.
> >> 
> >> But it *does* care about NFS_XPRTSEC_MTLS etc.
> >> 
> >> But I now see that RPC_AUTH_TLS is never reported by OP_SECINFO as an
> >> acceptable flavour, so the client cannot dynamically determine that TLS
> >> is required.
> > 
> > Why is not RPC_AUTH_TLS announced in NFS4 OP_SECINFO? Should not NFS4
> > OP_SECINFO report all possible auth methods for particular filehandle?
> 
> SECINFO reports user authentication flavors and pseudoflavors.
> 
> RPC_AUTH_TLS is not a user authentication flavor, it is merely
> a query to see if the server peer supports RPC-with-TLS.
> 
> So far the nfsv4 WG has not been able to come to consensus
> about how a server's transport layer security policies should
> be reported to clients. There does not seem to be a clean way
> to do that with existing NFSv4 protocol elements, so a
> protocol extension might be needed.

Interesting...

The distinction between RPC_AUTH_GSS_KRB5I and RPC_AUTH_GSS_KRB5P is not
about user authentication, it is about transport privacy.

And the distinction between xprtsec=tls and xprtsec=mtls seems to be
precisely about user authentication.

I would describe the current pseudo flavours as not "a clean way" to
advise the client of security requirements, but they are at least
established practice.

RPC_AUTH_SYS_TLS  seems to me to be an obvious sort of pseudo flavour.

But I suspect all these arguments and more have already been discussed
within the working group and people can sensibly have different
opinions.

Thanks for helping me understand NFS/TLS a bit better.

NeilBrown



> 
> 
> >> So there is no value in giving non-tls clients access to
> >> xprtsec=mtls exports so they can discover that for themselves.  The
> >> client needs to explicitly mount with tls, or possibly the client can
> >> opportunistically try TLS in every case, and call back.
> >> 
> >> So the original patch is OK.
> >> 
> >> NeilBrown
> 
> 
> --
> Chuck Lever
> 
> 
>
Chuck Lever Oct. 7, 2024, 3:50 p.m. UTC | #8
> On Oct 6, 2024, at 7:36 PM, NeilBrown <neilb@suse.de> wrote:
> 
> On Mon, 07 Oct 2024, Chuck Lever III wrote:
>> 
>> 
>>> On Oct 6, 2024, at 6:29 PM, Pali Rohár <pali@kernel.org> wrote:
>>> 
>>> On Monday 07 October 2024 09:13:17 NeilBrown wrote:
>>>> On Mon, 07 Oct 2024, Chuck Lever wrote:
>>>>> On Fri, Sep 13, 2024 at 08:52:20AM +1000, NeilBrown wrote:
>>>>>> On Fri, 13 Sep 2024, Pali Rohár wrote:
>>>>>>> Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
>>>>>>> only GSS, but bypass any authentication method. This is problem specially
>>>>>>> for NFS3 AUTH_NULL-only exports.
>>>>>>> 
>>>>>>> The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
>>>>>>> section 2.3.2, to allow mounting NFS2/3 GSS-only export without
>>>>>>> authentication. So few procedures which do not expose security risk used
>>>>>>> during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
>>>>>>> client mount operation to finish successfully.
>>>>>>> 
>>>>>>> The problem with current implementation is that for AUTH_NULL-only exports,
>>>>>>> the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
>>>>>>> attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
>>>>>>> enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
>>>>>>> AUTH_NONE on active mount, which makes the mount inaccessible.
>>>>>>> 
>>>>>>> Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
>>>>>>> and really allow to bypass only exports which have some GSS auth flavor
>>>>>>> enabled.
>>>>>>> 
>>>>>>> The result would be: For AUTH_NULL-only export if client attempts to do
>>>>>>> mount with AUTH_UNIX flavor then it will receive access errors, which
>>>>>>> instruct client that AUTH_UNIX flavor is not usable and will either try
>>>>>>> other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
>>>>>>> 
>>>>>>> This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
>>>>>>> client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
>>>>>>> AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
>>>>>> 
>>>>>> The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
>>>>>> your change it doesn't.  I don't think we want to make that change.
>>>>> 
>>>>> Neil, I'm not seeing this, I must be missing something.
>>>>> 
>>>>> RPC_AUTH_TLS is used only on NULL procedures.
>>>>> 
>>>>> The export's xprtsec= setting determines whether a TLS session must
>>>>> be present to access the files on the export. If the TLS session
>>>>> meets the xprtsec= policy, then the normal user authentication
>>>>> settings apply. In other words, I don't think execution gets close
>>>>> to check_nfsd_access() unless the xprtsec policy setting is met.
>>>> 
>>>> check_nfsd_access() is literally the ONLY place that ->ex_xprtsec_modes
>>>> is tested and that seems to be where xprtsec= export settings are stored.
>>>> 
>>>>> 
>>>>> I'm not convinced check_nfsd_access() needs to care about
>>>>> RPC_AUTH_TLS. Can you expand a little on your concern?
>>>> 
>>>> Probably it doesn't care about RPC_AUTH_TLS which as you say is only
>>>> used on NULL procedures when setting up the TLS connection.
>>>> 
>>>> But it *does* care about NFS_XPRTSEC_MTLS etc.
>>>> 
>>>> But I now see that RPC_AUTH_TLS is never reported by OP_SECINFO as an
>>>> acceptable flavour, so the client cannot dynamically determine that TLS
>>>> is required.
>>> 
>>> Why is not RPC_AUTH_TLS announced in NFS4 OP_SECINFO? Should not NFS4
>>> OP_SECINFO report all possible auth methods for particular filehandle?
>> 
>> SECINFO reports user authentication flavors and pseudoflavors.
>> 
>> RPC_AUTH_TLS is not a user authentication flavor, it is merely
>> a query to see if the server peer supports RPC-with-TLS.
>> 
>> So far the nfsv4 WG has not been able to come to consensus
>> about how a server's transport layer security policies should
>> be reported to clients. There does not seem to be a clean way
>> to do that with existing NFSv4 protocol elements, so a
>> protocol extension might be needed.
> 
> Interesting...
> 
> The distinction between RPC_AUTH_GSS_KRB5I and RPC_AUTH_GSS_KRB5P is not
> about user authentication, it is about transport privacy.

RPC_AUTH_GSS_KRB5I is Kerberos user authentication plus
Kerberos integrity protection.

RPC_AUTH_GSS_KRB5P is Kerberos user authentication plus
Kerberos confidentiality.

So, both of these pseudoflavors select Kerberos user
authentication (versus, say, RPC_AUTH_UNIX, which does
not).


> And the distinction between xprtsec=tls and xprtsec=mtls seems to be
> precisely about user authentication.

No: xprtsec authentication is /peer/ authentication. User
authentication is still set via sec= . See the final
paragraph in Section 4.2 of RFC 9289.


> I would describe the current pseudo flavours as not "a clean way" to
> advise the client of security requirements, but they are at least
> established practice.
> 
> RPC_AUTH_SYS_TLS  seems to me to be an obvious sort of pseudo flavour.
> 
> But I suspect all these arguments and more have already been discussed
> within the working group and people can sensibly have different
> opinions.

Yes, these arguments were discussed within the WG, and
I even wrote a draft (now expired) that treated the
various combinations of TLS and user authentication
flavors as unique pseudoflavors. The idea was rejected.


> Thanks for helping me understand NFS/TLS a bit better.
> 
> NeilBrown
> 
> 
> 
>> 
>> 
>>>> So there is no value in giving non-tls clients access to
>>>> xprtsec=mtls exports so they can discover that for themselves.  The
>>>> client needs to explicitly mount with tls, or possibly the client can
>>>> opportunistically try TLS in every case, and call back.
>>>> 
>>>> So the original patch is OK.
>>>> 
>>>> NeilBrown
>> 
>> 
>> --
>> Chuck Lever


--
Chuck Lever
Rick Macklem Oct. 8, 2024, 1:17 a.m. UTC | #9
On Mon, Oct 7, 2024 at 8:51 AM Chuck Lever III <chuck.lever@oracle.com> wrote:
>
> CAUTION: This email originated from outside of the University of Guelph. Do not click links or open attachments unless you recognize the sender and know the content is safe. If in doubt, forward suspicious emails to IThelp@uoguelph.ca.
>
>
>
>
> > On Oct 6, 2024, at 7:36 PM, NeilBrown <neilb@suse.de> wrote:
> >
> > On Mon, 07 Oct 2024, Chuck Lever III wrote:
> >>
> >>
> >>> On Oct 6, 2024, at 6:29 PM, Pali Rohár <pali@kernel.org> wrote:
> >>>
> >>> On Monday 07 October 2024 09:13:17 NeilBrown wrote:
> >>>> On Mon, 07 Oct 2024, Chuck Lever wrote:
> >>>>> On Fri, Sep 13, 2024 at 08:52:20AM +1000, NeilBrown wrote:
> >>>>>> On Fri, 13 Sep 2024, Pali Rohár wrote:
> >>>>>>> Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
> >>>>>>> only GSS, but bypass any authentication method. This is problem specially
> >>>>>>> for NFS3 AUTH_NULL-only exports.
> >>>>>>>
> >>>>>>> The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
> >>>>>>> section 2.3.2, to allow mounting NFS2/3 GSS-only export without
> >>>>>>> authentication. So few procedures which do not expose security risk used
> >>>>>>> during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
> >>>>>>> client mount operation to finish successfully.
> >>>>>>>
> >>>>>>> The problem with current implementation is that for AUTH_NULL-only exports,
> >>>>>>> the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
> >>>>>>> attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
> >>>>>>> enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
> >>>>>>> AUTH_NONE on active mount, which makes the mount inaccessible.
> >>>>>>>
> >>>>>>> Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
> >>>>>>> and really allow to bypass only exports which have some GSS auth flavor
> >>>>>>> enabled.
> >>>>>>>
> >>>>>>> The result would be: For AUTH_NULL-only export if client attempts to do
> >>>>>>> mount with AUTH_UNIX flavor then it will receive access errors, which
> >>>>>>> instruct client that AUTH_UNIX flavor is not usable and will either try
> >>>>>>> other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
> >>>>>>>
> >>>>>>> This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
> >>>>>>> client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
> >>>>>>> AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
> >>>>>>
> >>>>>> The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
> >>>>>> your change it doesn't.  I don't think we want to make that change.
> >>>>>
> >>>>> Neil, I'm not seeing this, I must be missing something.
> >>>>>
> >>>>> RPC_AUTH_TLS is used only on NULL procedures.
> >>>>>
> >>>>> The export's xprtsec= setting determines whether a TLS session must
> >>>>> be present to access the files on the export. If the TLS session
> >>>>> meets the xprtsec= policy, then the normal user authentication
> >>>>> settings apply. In other words, I don't think execution gets close
> >>>>> to check_nfsd_access() unless the xprtsec policy setting is met.
> >>>>
> >>>> check_nfsd_access() is literally the ONLY place that ->ex_xprtsec_modes
> >>>> is tested and that seems to be where xprtsec= export settings are stored.
> >>>>
> >>>>>
> >>>>> I'm not convinced check_nfsd_access() needs to care about
> >>>>> RPC_AUTH_TLS. Can you expand a little on your concern?
> >>>>
> >>>> Probably it doesn't care about RPC_AUTH_TLS which as you say is only
> >>>> used on NULL procedures when setting up the TLS connection.
> >>>>
> >>>> But it *does* care about NFS_XPRTSEC_MTLS etc.
> >>>>
> >>>> But I now see that RPC_AUTH_TLS is never reported by OP_SECINFO as an
> >>>> acceptable flavour, so the client cannot dynamically determine that TLS
> >>>> is required.
> >>>
> >>> Why is not RPC_AUTH_TLS announced in NFS4 OP_SECINFO? Should not NFS4
> >>> OP_SECINFO report all possible auth methods for particular filehandle?
> >>
> >> SECINFO reports user authentication flavors and pseudoflavors.
> >>
> >> RPC_AUTH_TLS is not a user authentication flavor, it is merely
> >> a query to see if the server peer supports RPC-with-TLS.
> >>
> >> So far the nfsv4 WG has not been able to come to consensus
> >> about how a server's transport layer security policies should
> >> be reported to clients. There does not seem to be a clean way
> >> to do that with existing NFSv4 protocol elements, so a
> >> protocol extension might be needed.
> >
> > Interesting...
> >
> > The distinction between RPC_AUTH_GSS_KRB5I and RPC_AUTH_GSS_KRB5P is not
> > about user authentication, it is about transport privacy.
>
> RPC_AUTH_GSS_KRB5I is Kerberos user authentication plus
> Kerberos integrity protection.
>
> RPC_AUTH_GSS_KRB5P is Kerberos user authentication plus
> Kerberos confidentiality.
>
> So, both of these pseudoflavors select Kerberos user
> authentication (versus, say, RPC_AUTH_UNIX, which does
> not).
I'd argue they also select on-the-wire protection. It just happens
that they use the session key for a user credential.
I'd agree with Neil, in that the 'p' refers to on-the-wire privacy.
>
>
> > And the distinction between xprtsec=tls and xprtsec=mtls seems to be
> > precisely about user authentication.
>
> No: xprtsec authentication is /peer/ authentication. User
> authentication is still set via sec= . See the final
> paragraph in Section 4.2 of RFC 9289.
True, but for krb5[ip] there is a (mis)use of a user principal for the
client's machine credential. (The user principal that does SetClientID
or ExchangeID.)
--> I'd argue that this user principal is really a client machine (or peer,
if you prefer) credential.
--> I think that the host based service principal in the client's keytab
      is a pita and maybe one of the reasons that krb5[ip] doesn't get
      used that much.

>
>
> > I would describe the current pseudo flavours as not "a clean way" to
> > advise the client of security requirements, but they are at least
> > established practice.
> >
> > RPC_AUTH_SYS_TLS  seems to me to be an obvious sort of pseudo flavour.
> >
> > But I suspect all these arguments and more have already been discussed
> > within the working group and people can sensibly have different
> > opinions.
>
> Yes, these arguments were discussed within the WG, and
> I even wrote a draft (now expired) that treated the
> various combinations of TLS and user authentication
> flavors as unique pseudoflavors. The idea was rejected.
I'll encourage NeilBrown to make comments related to the D. Noveck
security draft over on nfsv4@ieft.org. (I'll admit I have great difficulty
getting around to reading/commenting on these drafts, but I will try to
get around to the security one one of these days.)

The piece I'd like to see is mtls being accepted as a reasonable
alternative to krb5i/krb5p for SP4_MACH_CRED.

Personally, I think the pseudo-flavors make sense.
Maybe I/Neil can illicit further discussion w.r.t. them, rick

>
>
> > Thanks for helping me understand NFS/TLS a bit better.
> >
> > NeilBrown
> >
> >
> >
> >>
> >>
> >>>> So there is no value in giving non-tls clients access to
> >>>> xprtsec=mtls exports so they can discover that for themselves.  The
> >>>> client needs to explicitly mount with tls, or possibly the client can
> >>>> opportunistically try TLS in every case, and call back.
> >>>>
> >>>> So the original patch is OK.
> >>>>
> >>>> NeilBrown
> >>
> >>
> >> --
> >> Chuck Lever
>
>
> --
> Chuck Lever
>
>
Pali Rohár Oct. 8, 2024, 6:54 p.m. UTC | #10
On Monday 07 October 2024 09:13:17 NeilBrown wrote:
> On Mon, 07 Oct 2024, Chuck Lever wrote:
> > On Fri, Sep 13, 2024 at 08:52:20AM +1000, NeilBrown wrote:
> > > On Fri, 13 Sep 2024, Pali Rohár wrote:
> > > > Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
> > > > only GSS, but bypass any authentication method. This is problem specially
> > > > for NFS3 AUTH_NULL-only exports.
> > > > 
> > > > The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
> > > > section 2.3.2, to allow mounting NFS2/3 GSS-only export without
> > > > authentication. So few procedures which do not expose security risk used
> > > > during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
> > > > client mount operation to finish successfully.
> > > > 
> > > > The problem with current implementation is that for AUTH_NULL-only exports,
> > > > the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
> > > > attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
> > > > enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
> > > > AUTH_NONE on active mount, which makes the mount inaccessible.
> > > > 
> > > > Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
> > > > and really allow to bypass only exports which have some GSS auth flavor
> > > > enabled.
> > > > 
> > > > The result would be: For AUTH_NULL-only export if client attempts to do
> > > > mount with AUTH_UNIX flavor then it will receive access errors, which
> > > > instruct client that AUTH_UNIX flavor is not usable and will either try
> > > > other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
> > > > 
> > > > This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
> > > > client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
> > > > AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
> > > 
> > > The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
> > > your change it doesn't.  I don't think we want to make that change.
> > 
> > Neil, I'm not seeing this, I must be missing something.
> > 
> > RPC_AUTH_TLS is used only on NULL procedures.
> > 
> > The export's xprtsec= setting determines whether a TLS session must
> > be present to access the files on the export. If the TLS session
> > meets the xprtsec= policy, then the normal user authentication
> > settings apply. In other words, I don't think execution gets close
> > to check_nfsd_access() unless the xprtsec policy setting is met.
> 
> check_nfsd_access() is literally the ONLY place that ->ex_xprtsec_modes
> is tested and that seems to be where xprtsec= export settings are stored.
> 
> > 
> > I'm not convinced check_nfsd_access() needs to care about
> > RPC_AUTH_TLS. Can you expand a little on your concern?
> 
> Probably it doesn't care about RPC_AUTH_TLS which as you say is only
> used on NULL procedures when setting up the TLS connection.
> 
> But it *does* care about NFS_XPRTSEC_MTLS etc.
> 
> But I now see that RPC_AUTH_TLS is never reported by OP_SECINFO as an
> acceptable flavour, so the client cannot dynamically determine that TLS
> is required.  So there is no value in giving non-tls clients access to
> xprtsec=mtls exports so they can discover that for themselves.  The
> client needs to explicitly mount with tls, or possibly the client can
> opportunistically try TLS in every case, and call back.
> 
> So the original patch is OK.

So if the original patch is also OK, you can choose which one you like
more. Original V1 restrict bypass to only GSS. V2 allows bypass for any
non-null/unix methods.

Let me know if something more is needed for this change.
Chuck Lever Oct. 8, 2024, 6:57 p.m. UTC | #11
On Mon, Oct 07, 2024 at 09:13:17AM +1100, NeilBrown wrote:
> On Mon, 07 Oct 2024, Chuck Lever wrote:
> > On Fri, Sep 13, 2024 at 08:52:20AM +1000, NeilBrown wrote:
> > > On Fri, 13 Sep 2024, Pali Rohár wrote:
> > > > Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
> > > > only GSS, but bypass any authentication method. This is problem specially
> > > > for NFS3 AUTH_NULL-only exports.
> > > > 
> > > > The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
> > > > section 2.3.2, to allow mounting NFS2/3 GSS-only export without
> > > > authentication. So few procedures which do not expose security risk used
> > > > during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
> > > > client mount operation to finish successfully.
> > > > 
> > > > The problem with current implementation is that for AUTH_NULL-only exports,
> > > > the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
> > > > attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
> > > > enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
> > > > AUTH_NONE on active mount, which makes the mount inaccessible.
> > > > 
> > > > Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
> > > > and really allow to bypass only exports which have some GSS auth flavor
> > > > enabled.
> > > > 
> > > > The result would be: For AUTH_NULL-only export if client attempts to do
> > > > mount with AUTH_UNIX flavor then it will receive access errors, which
> > > > instruct client that AUTH_UNIX flavor is not usable and will either try
> > > > other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
> > > > 
> > > > This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
> > > > client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
> > > > AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
> > > 
> > > The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
> > > your change it doesn't.  I don't think we want to make that change.
> > 
> > Neil, I'm not seeing this, I must be missing something.
> > 
> > RPC_AUTH_TLS is used only on NULL procedures.
> > 
> > The export's xprtsec= setting determines whether a TLS session must
> > be present to access the files on the export. If the TLS session
> > meets the xprtsec= policy, then the normal user authentication
> > settings apply. In other words, I don't think execution gets close
> > to check_nfsd_access() unless the xprtsec policy setting is met.
> 
> check_nfsd_access() is literally the ONLY place that ->ex_xprtsec_modes
> is tested and that seems to be where xprtsec= export settings are stored.
> 
> > 
> > I'm not convinced check_nfsd_access() needs to care about
> > RPC_AUTH_TLS. Can you expand a little on your concern?
> 
> Probably it doesn't care about RPC_AUTH_TLS which as you say is only
> used on NULL procedures when setting up the TLS connection.
> 
> But it *does* care about NFS_XPRTSEC_MTLS etc.
> 
> But I now see that RPC_AUTH_TLS is never reported by OP_SECINFO as an
> acceptable flavour, so the client cannot dynamically determine that TLS
> is required.  So there is no value in giving non-tls clients access to
> xprtsec=mtls exports so they can discover that for themselves.  The
> client needs to explicitly mount with tls, or possibly the client can
> opportunistically try TLS in every case, and call back.
> 
> So the original patch is OK.

May I add "Reviewed-by: NeilBrown <neilb@suse.de>" ?


> NeilBrown
> 
> 
> > 
> > 
> > > I think that what you want to do makes sense.  Higher security can be
> > > downgraded to AUTH_UNIX, but AUTH_NULL mustn't be upgraded to to
> > > AUTH_UNIX.
> > > 
> > > Maybe that needs to be explicit in the code.  The bypass is ONLY allowed
> > > for AUTH_UNIX and only if something other than AUTH_NULL is allowed.
> > > 
> > > Thanks,
> > > NeilBrown
> > > 
> > > 
> > > 
> > > > 
> > > > Signed-off-by: Pali Rohár <pali@kernel.org>
> > > > ---
> > > >  fs/nfsd/export.c   | 19 ++++++++++++++++++-
> > > >  fs/nfsd/export.h   |  2 +-
> > > >  fs/nfsd/nfs4proc.c |  2 +-
> > > >  fs/nfsd/nfs4xdr.c  |  2 +-
> > > >  fs/nfsd/nfsfh.c    | 12 +++++++++---
> > > >  fs/nfsd/vfs.c      |  2 +-
> > > >  6 files changed, 31 insertions(+), 8 deletions(-)
> > > > 
> > > > diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
> > > > index 50b3135d07ac..eb11d3fdffe1 100644
> > > > --- a/fs/nfsd/export.c
> > > > +++ b/fs/nfsd/export.c
> > > > @@ -1074,7 +1074,7 @@ static struct svc_export *exp_find(struct cache_detail *cd,
> > > >  	return exp;
> > > >  }
> > > >  
> > > > -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> > > > +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss)
> > > >  {
> > > >  	struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
> > > >  	struct svc_xprt *xprt = rqstp->rq_xprt;
> > > > @@ -1120,6 +1120,23 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> > > >  	if (nfsd4_spo_must_allow(rqstp))
> > > >  		return 0;
> > > >  
> > > > +	/* Some calls may be processed without authentication
> > > > +	 * on GSS exports. For example NFS2/3 calls on root
> > > > +	 * directory, see section 2.3.2 of rfc 2623.
> > > > +	 * For "may_bypass_gss" check that export has really
> > > > +	 * enabled some GSS flavor and also check that the
> > > > +	 * used auth flavor is without auth (none or sys).
> > > > +	 */
> > > > +	if (may_bypass_gss && (
> > > > +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
> > > > +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)) {
> > > > +		for (f = exp->ex_flavors; f < end; f++) {
> > > > +			if (f->pseudoflavor == RPC_AUTH_GSS ||
> > > > +			    f->pseudoflavor >= RPC_AUTH_GSS_KRB5)
> > > > +				return 0;
> > > > +		}
> > > > +	}
> > > > +
> > > >  denied:
> > > >  	return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
> > > >  }
> > > > diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
> > > > index ca9dc230ae3d..dc7cf4f6ac53 100644
> > > > --- a/fs/nfsd/export.h
> > > > +++ b/fs/nfsd/export.h
> > > > @@ -100,7 +100,7 @@ struct svc_expkey {
> > > >  #define EX_WGATHER(exp)		((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
> > > >  
> > > >  int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp);
> > > > -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
> > > > +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss);
> > > >  
> > > >  /*
> > > >   * Function declarations
> > > > diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> > > > index 2e39cf2e502a..0f67f4a7b8b2 100644
> > > > --- a/fs/nfsd/nfs4proc.c
> > > > +++ b/fs/nfsd/nfs4proc.c
> > > > @@ -2791,7 +2791,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);
> > > > +				op->status = check_nfsd_access(current_fh->fh_export, rqstp, false);
> > > >  		}
> > > >  encode_op:
> > > >  		if (op->status == nfserr_replay_me) {
> > > > diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> > > > index 97f583777972..b45ea5757652 100644
> > > > --- a/fs/nfsd/nfs4xdr.c
> > > > +++ b/fs/nfsd/nfs4xdr.c
> > > > @@ -3775,7 +3775,7 @@ nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name,
> > > >  			nfserr = nfserrno(err);
> > > >  			goto out_put;
> > > >  		}
> > > > -		nfserr = check_nfsd_access(exp, cd->rd_rqstp);
> > > > +		nfserr = check_nfsd_access(exp, cd->rd_rqstp, false);
> > > >  		if (nfserr)
> > > >  			goto out_put;
> > > >  
> > > > diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> > > > index dd4e11a703aa..ed0eabfa3cb0 100644
> > > > --- a/fs/nfsd/nfsfh.c
> > > > +++ b/fs/nfsd/nfsfh.c
> > > > @@ -329,6 +329,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> > > >  {
> > > >  	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
> > > >  	struct svc_export *exp = NULL;
> > > > +	bool may_bypass_gss = false;
> > > >  	struct dentry	*dentry;
> > > >  	__be32		error;
> > > >  
> > > > @@ -375,8 +376,13 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> > > >  	 * which clients virtually always use auth_sys for,
> > > >  	 * even while using RPCSEC_GSS for NFS.
> > > >  	 */
> > > > -	if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
> > > > +	if (access & NFSD_MAY_LOCK)
> > > >  		goto skip_pseudoflavor_check;
> > > > +	/*
> > > > +	 * NFS4 PUTFH may bypass GSS (see nfsd4_putfh() in nfs4proc.c).
> > > > +	 */
> > > > +	if (access & NFSD_MAY_BYPASS_GSS)
> > > > +		may_bypass_gss = true;
> > > >  	/*
> > > >  	 * Clients may expect to be able to use auth_sys during mount,
> > > >  	 * even if they use gss for everything else; see section 2.3.2
> > > > @@ -384,9 +390,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> > > >  	 */
> > > >  	if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
> > > >  			&& exp->ex_path.dentry == dentry)
> > > > -		goto skip_pseudoflavor_check;
> > > > +		may_bypass_gss = true;
> > > >  
> > > > -	error = check_nfsd_access(exp, rqstp);
> > > > +	error = check_nfsd_access(exp, rqstp, may_bypass_gss);
> > > >  	if (error)
> > > >  		goto out;
> > > >  
> > > > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> > > > index 29b1f3613800..b2f5ea7c2187 100644
> > > > --- a/fs/nfsd/vfs.c
> > > > +++ b/fs/nfsd/vfs.c
> > > > @@ -320,7 +320,7 @@ 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);
> > > > +	err = check_nfsd_access(exp, rqstp, false);
> > > >  	if (err)
> > > >  		goto out;
> > > >  	/*
> > > > -- 
> > > > 2.20.1
> > > > 
> > > > 
> > > 
> > 
> > -- 
> > Chuck Lever
> > 
>
NeilBrown Oct. 8, 2024, 9:47 p.m. UTC | #12
On Wed, 09 Oct 2024, Chuck Lever wrote:
> On Mon, Oct 07, 2024 at 09:13:17AM +1100, NeilBrown wrote:
> > On Mon, 07 Oct 2024, Chuck Lever wrote:
> > > On Fri, Sep 13, 2024 at 08:52:20AM +1000, NeilBrown wrote:
> > > > On Fri, 13 Sep 2024, Pali Rohár wrote:
> > > > > Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
> > > > > only GSS, but bypass any authentication method. This is problem specially
> > > > > for NFS3 AUTH_NULL-only exports.
> > > > > 
> > > > > The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
> > > > > section 2.3.2, to allow mounting NFS2/3 GSS-only export without
> > > > > authentication. So few procedures which do not expose security risk used
> > > > > during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
> > > > > client mount operation to finish successfully.
> > > > > 
> > > > > The problem with current implementation is that for AUTH_NULL-only exports,
> > > > > the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
> > > > > attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
> > > > > enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
> > > > > AUTH_NONE on active mount, which makes the mount inaccessible.
> > > > > 
> > > > > Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
> > > > > and really allow to bypass only exports which have some GSS auth flavor
> > > > > enabled.
> > > > > 
> > > > > The result would be: For AUTH_NULL-only export if client attempts to do
> > > > > mount with AUTH_UNIX flavor then it will receive access errors, which
> > > > > instruct client that AUTH_UNIX flavor is not usable and will either try
> > > > > other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
> > > > > 
> > > > > This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
> > > > > client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
> > > > > AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
> > > > 
> > > > The MAY_BYPASS_GSS flag currently also bypasses TLS restrictions.  With
> > > > your change it doesn't.  I don't think we want to make that change.
> > > 
> > > Neil, I'm not seeing this, I must be missing something.
> > > 
> > > RPC_AUTH_TLS is used only on NULL procedures.
> > > 
> > > The export's xprtsec= setting determines whether a TLS session must
> > > be present to access the files on the export. If the TLS session
> > > meets the xprtsec= policy, then the normal user authentication
> > > settings apply. In other words, I don't think execution gets close
> > > to check_nfsd_access() unless the xprtsec policy setting is met.
> > 
> > check_nfsd_access() is literally the ONLY place that ->ex_xprtsec_modes
> > is tested and that seems to be where xprtsec= export settings are stored.
> > 
> > > 
> > > I'm not convinced check_nfsd_access() needs to care about
> > > RPC_AUTH_TLS. Can you expand a little on your concern?
> > 
> > Probably it doesn't care about RPC_AUTH_TLS which as you say is only
> > used on NULL procedures when setting up the TLS connection.
> > 
> > But it *does* care about NFS_XPRTSEC_MTLS etc.
> > 
> > But I now see that RPC_AUTH_TLS is never reported by OP_SECINFO as an
> > acceptable flavour, so the client cannot dynamically determine that TLS
> > is required.  So there is no value in giving non-tls clients access to
> > xprtsec=mtls exports so they can discover that for themselves.  The
> > client needs to explicitly mount with tls, or possibly the client can
> > opportunistically try TLS in every case, and call back.
> > 
> > So the original patch is OK.
> 
> May I add "Reviewed-by: NeilBrown <neilb@suse.de>" ?

Yes, though I would prefer v2.

I also would love it if NFSD_MAY_BYPASS_GSS were renamed to
NFSD_MAY_BYPASS_SEC.
And NFSD_MAY_LOCK should be discarded, and nlm_fopen() should set
NFSD_MAY_BYPASS_SEC.
And I wonder if there is really any value in having
NFSD_MAY_BYPASS_GSS_ON_ROOT being separate from NFSD_MAY_BYPASS_GSS.

But I'm not offering patches - at least not today - and those concerns
don't need to block this patch.

Reviewed-by: NeilBrown <neilb@suse.de>

Thanks,
NeilBrown

> 
> 
> > NeilBrown
> > 
> > 
> > > 
> > > 
> > > > I think that what you want to do makes sense.  Higher security can be
> > > > downgraded to AUTH_UNIX, but AUTH_NULL mustn't be upgraded to to
> > > > AUTH_UNIX.
> > > > 
> > > > Maybe that needs to be explicit in the code.  The bypass is ONLY allowed
> > > > for AUTH_UNIX and only if something other than AUTH_NULL is allowed.
> > > > 
> > > > Thanks,
> > > > NeilBrown
> > > > 
> > > > 
> > > > 
> > > > > 
> > > > > Signed-off-by: Pali Rohár <pali@kernel.org>
> > > > > ---
> > > > >  fs/nfsd/export.c   | 19 ++++++++++++++++++-
> > > > >  fs/nfsd/export.h   |  2 +-
> > > > >  fs/nfsd/nfs4proc.c |  2 +-
> > > > >  fs/nfsd/nfs4xdr.c  |  2 +-
> > > > >  fs/nfsd/nfsfh.c    | 12 +++++++++---
> > > > >  fs/nfsd/vfs.c      |  2 +-
> > > > >  6 files changed, 31 insertions(+), 8 deletions(-)
> > > > > 
> > > > > diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
> > > > > index 50b3135d07ac..eb11d3fdffe1 100644
> > > > > --- a/fs/nfsd/export.c
> > > > > +++ b/fs/nfsd/export.c
> > > > > @@ -1074,7 +1074,7 @@ static struct svc_export *exp_find(struct cache_detail *cd,
> > > > >  	return exp;
> > > > >  }
> > > > >  
> > > > > -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> > > > > +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss)
> > > > >  {
> > > > >  	struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
> > > > >  	struct svc_xprt *xprt = rqstp->rq_xprt;
> > > > > @@ -1120,6 +1120,23 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
> > > > >  	if (nfsd4_spo_must_allow(rqstp))
> > > > >  		return 0;
> > > > >  
> > > > > +	/* Some calls may be processed without authentication
> > > > > +	 * on GSS exports. For example NFS2/3 calls on root
> > > > > +	 * directory, see section 2.3.2 of rfc 2623.
> > > > > +	 * For "may_bypass_gss" check that export has really
> > > > > +	 * enabled some GSS flavor and also check that the
> > > > > +	 * used auth flavor is without auth (none or sys).
> > > > > +	 */
> > > > > +	if (may_bypass_gss && (
> > > > > +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
> > > > > +	     rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)) {
> > > > > +		for (f = exp->ex_flavors; f < end; f++) {
> > > > > +			if (f->pseudoflavor == RPC_AUTH_GSS ||
> > > > > +			    f->pseudoflavor >= RPC_AUTH_GSS_KRB5)
> > > > > +				return 0;
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > >  denied:
> > > > >  	return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
> > > > >  }
> > > > > diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
> > > > > index ca9dc230ae3d..dc7cf4f6ac53 100644
> > > > > --- a/fs/nfsd/export.h
> > > > > +++ b/fs/nfsd/export.h
> > > > > @@ -100,7 +100,7 @@ struct svc_expkey {
> > > > >  #define EX_WGATHER(exp)		((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
> > > > >  
> > > > >  int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp);
> > > > > -__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
> > > > > +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss);
> > > > >  
> > > > >  /*
> > > > >   * Function declarations
> > > > > diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> > > > > index 2e39cf2e502a..0f67f4a7b8b2 100644
> > > > > --- a/fs/nfsd/nfs4proc.c
> > > > > +++ b/fs/nfsd/nfs4proc.c
> > > > > @@ -2791,7 +2791,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);
> > > > > +				op->status = check_nfsd_access(current_fh->fh_export, rqstp, false);
> > > > >  		}
> > > > >  encode_op:
> > > > >  		if (op->status == nfserr_replay_me) {
> > > > > diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> > > > > index 97f583777972..b45ea5757652 100644
> > > > > --- a/fs/nfsd/nfs4xdr.c
> > > > > +++ b/fs/nfsd/nfs4xdr.c
> > > > > @@ -3775,7 +3775,7 @@ nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name,
> > > > >  			nfserr = nfserrno(err);
> > > > >  			goto out_put;
> > > > >  		}
> > > > > -		nfserr = check_nfsd_access(exp, cd->rd_rqstp);
> > > > > +		nfserr = check_nfsd_access(exp, cd->rd_rqstp, false);
> > > > >  		if (nfserr)
> > > > >  			goto out_put;
> > > > >  
> > > > > diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> > > > > index dd4e11a703aa..ed0eabfa3cb0 100644
> > > > > --- a/fs/nfsd/nfsfh.c
> > > > > +++ b/fs/nfsd/nfsfh.c
> > > > > @@ -329,6 +329,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> > > > >  {
> > > > >  	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
> > > > >  	struct svc_export *exp = NULL;
> > > > > +	bool may_bypass_gss = false;
> > > > >  	struct dentry	*dentry;
> > > > >  	__be32		error;
> > > > >  
> > > > > @@ -375,8 +376,13 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> > > > >  	 * which clients virtually always use auth_sys for,
> > > > >  	 * even while using RPCSEC_GSS for NFS.
> > > > >  	 */
> > > > > -	if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
> > > > > +	if (access & NFSD_MAY_LOCK)
> > > > >  		goto skip_pseudoflavor_check;
> > > > > +	/*
> > > > > +	 * NFS4 PUTFH may bypass GSS (see nfsd4_putfh() in nfs4proc.c).
> > > > > +	 */
> > > > > +	if (access & NFSD_MAY_BYPASS_GSS)
> > > > > +		may_bypass_gss = true;
> > > > >  	/*
> > > > >  	 * Clients may expect to be able to use auth_sys during mount,
> > > > >  	 * even if they use gss for everything else; see section 2.3.2
> > > > > @@ -384,9 +390,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> > > > >  	 */
> > > > >  	if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
> > > > >  			&& exp->ex_path.dentry == dentry)
> > > > > -		goto skip_pseudoflavor_check;
> > > > > +		may_bypass_gss = true;
> > > > >  
> > > > > -	error = check_nfsd_access(exp, rqstp);
> > > > > +	error = check_nfsd_access(exp, rqstp, may_bypass_gss);
> > > > >  	if (error)
> > > > >  		goto out;
> > > > >  
> > > > > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> > > > > index 29b1f3613800..b2f5ea7c2187 100644
> > > > > --- a/fs/nfsd/vfs.c
> > > > > +++ b/fs/nfsd/vfs.c
> > > > > @@ -320,7 +320,7 @@ 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);
> > > > > +	err = check_nfsd_access(exp, rqstp, false);
> > > > >  	if (err)
> > > > >  		goto out;
> > > > >  	/*
> > > > > -- 
> > > > > 2.20.1
> > > > > 
> > > > > 
> > > > 
> > > 
> > > -- 
> > > Chuck Lever
> > > 
> > 
> 
> -- 
> Chuck Lever
>
Chuck Lever Oct. 9, 2024, 7:55 p.m. UTC | #13
On Tue, Oct 08, 2024 at 05:47:55PM -0400, NeilBrown wrote:
> And NFSD_MAY_LOCK should be discarded, and nlm_fopen() should set
> NFSD_MAY_BYPASS_SEC.

366         /*                                                                      
367          * pseudoflavor restrictions are not enforced on NLM,                   

Wrt the mention of "NLM", nfsd4_lock() also sets NFSD_MAY_LOCK.

368          * which clients virtually always use auth_sys for,                     
369          * even while using RPCSEC_GSS for NFS.                                 
370          */                                                                     
371         if (access & NFSD_MAY_LOCK)                                             
372                 goto skip_pseudoflavor_check;                                   
373         if (access & NFSD_MAY_BYPASS_GSS)                                       
374                 may_bypass_gss = true;
375         /*                                                                      
376          * Clients may expect to be able to use auth_sys during mount,          
377          * even if they use gss for everything else; see section 2.3.2          
378          * of rfc 2623.                                                         
379          */                                                                     
380         if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT                                
381                         && exp->ex_path.dentry == dentry)                       
382                 may_bypass_gss = true;                                          
383                                                                                 
384         error = check_nfsd_access(exp, rqstp, may_bypass_gss);                  
385         if (error)                                                              
386                 goto out;                                                       
387                                                                                 
388 skip_pseudoflavor_check:                                                        
389         /* Finally, check access permissions. */                                
390         error = nfsd_permission(cred, exp, dentry, access);     

MAY_LOCK is checked in nfsd_permission() and __fh_verify().

But MAY_BYPASS_GSS is set in loads of places that use those two
functions. How can we be certain that the two flags are equivalent? 

Though I agree, simplifying this hot path would both help
performance scalability and reduce reader headaches. It might be a
little nicer to pass the NFSD_MAY flags directly to
check_nfsd_access(), for example.
NeilBrown Oct. 9, 2024, 8:14 p.m. UTC | #14
On Thu, 10 Oct 2024, Chuck Lever wrote:
> On Tue, Oct 08, 2024 at 05:47:55PM -0400, NeilBrown wrote:
> > And NFSD_MAY_LOCK should be discarded, and nlm_fopen() should set
> > NFSD_MAY_BYPASS_SEC.
> 
> 366         /*                                                                      
> 367          * pseudoflavor restrictions are not enforced on NLM,                   
> 
> Wrt the mention of "NLM", nfsd4_lock() also sets NFSD_MAY_LOCK.

True, but it shouldn't.  NFSD_MAY_LOCK is only used to bypass the GSS
requirement.  It must have been copied into nfsd4_lock() without a full
understanding of its purpose.

> 
> 368          * which clients virtually always use auth_sys for,                     
> 369          * even while using RPCSEC_GSS for NFS.                                 
> 370          */                                                                     
> 371         if (access & NFSD_MAY_LOCK)                                             
> 372                 goto skip_pseudoflavor_check;                                   
> 373         if (access & NFSD_MAY_BYPASS_GSS)                                       
> 374                 may_bypass_gss = true;
> 375         /*                                                                      
> 376          * Clients may expect to be able to use auth_sys during mount,          
> 377          * even if they use gss for everything else; see section 2.3.2          
> 378          * of rfc 2623.                                                         
> 379          */                                                                     
> 380         if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT                                
> 381                         && exp->ex_path.dentry == dentry)                       
> 382                 may_bypass_gss = true;                                          
> 383                                                                                 
> 384         error = check_nfsd_access(exp, rqstp, may_bypass_gss);                  
> 385         if (error)                                                              
> 386                 goto out;                                                       
> 387                                                                                 
> 388 skip_pseudoflavor_check:                                                        
> 389         /* Finally, check access permissions. */                                
> 390         error = nfsd_permission(cred, exp, dentry, access);     
> 
> MAY_LOCK is checked in nfsd_permission() and __fh_verify().
> 
> But MAY_BYPASS_GSS is set in loads of places that use those two
> functions. How can we be certain that the two flags are equivalent? 

We can be certain by looking at the effect.  Before a recent patch they
both did "goto skip_pseudoflavor_check" and nothing else.

> 
> Though I agree, simplifying this hot path would both help
> performance scalability and reduce reader headaches. It might be a
> little nicer to pass the NFSD_MAY flags directly to
> check_nfsd_access(), for example.

Yes, that might be cleaner.

Thanks,
NeilBrown
Chuck Lever Oct. 9, 2024, 11:30 p.m. UTC | #15
On Thu, Oct 10, 2024 at 07:14:07AM +1100, NeilBrown wrote:
> On Thu, 10 Oct 2024, Chuck Lever wrote:
> > On Tue, Oct 08, 2024 at 05:47:55PM -0400, NeilBrown wrote:
> > > And NFSD_MAY_LOCK should be discarded, and nlm_fopen() should set
> > > NFSD_MAY_BYPASS_SEC.
> > 
> > 366         /*                                                                      
> > 367          * pseudoflavor restrictions are not enforced on NLM,                   
> > 
> > Wrt the mention of "NLM", nfsd4_lock() also sets NFSD_MAY_LOCK.
> 
> True, but it shouldn't.  NFSD_MAY_LOCK is only used to bypass the GSS
> requirement.  It must have been copied into nfsd4_lock() without a full
> understanding of its purpose.

nfsd4_lock()'s use of MAY_LOCK goes back before the git era, so it's
difficult to say with certainty.

I would like to keep such subtle changes bisectable. To me, it seems
like it would be a basic first step to change the fh_verify() call
in nfsd4_lock() to use (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)
instead of NFSD_MAY_LOCK, as a separate patch.


> > 368          * which clients virtually always use auth_sys for,                     
> > 369          * even while using RPCSEC_GSS for NFS.                                 
> > 370          */                                                                     
> > 371         if (access & NFSD_MAY_LOCK)                                             
> > 372                 goto skip_pseudoflavor_check;                                   
> > 373         if (access & NFSD_MAY_BYPASS_GSS)                                       
> > 374                 may_bypass_gss = true;
> > 375         /*                                                                      
> > 376          * Clients may expect to be able to use auth_sys during mount,          
> > 377          * even if they use gss for everything else; see section 2.3.2          
> > 378          * of rfc 2623.                                                         
> > 379          */                                                                     
> > 380         if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT                                
> > 381                         && exp->ex_path.dentry == dentry)                       
> > 382                 may_bypass_gss = true;                                          
> > 383                                                                                 
> > 384         error = check_nfsd_access(exp, rqstp, may_bypass_gss);                  
> > 385         if (error)                                                              
> > 386                 goto out;                                                       
> > 387                                                                                 
> > 388 skip_pseudoflavor_check:                                                        
> > 389         /* Finally, check access permissions. */                                
> > 390         error = nfsd_permission(cred, exp, dentry, access);     
> > 
> > MAY_LOCK is checked in nfsd_permission() and __fh_verify().
> > 
> > But MAY_BYPASS_GSS is set in loads of places that use those two
> > functions. How can we be certain that the two flags are equivalent? 
> 
> We can be certain by looking at the effect.  Before a recent patch they
> both did "goto skip_pseudoflavor_check" and nothing else.

I'm still not convinced MAY_LOCK and MAY_BYPASS_GSS are 100%
equivalent.  nfsd_permission() checks for MAY_LOCK, but does not
check for MAY_BYPASS_GSS:

        if (acc & NFSD_MAY_LOCK) {
                /* If we cannot rely on authentication in NLM requests,
                 * just allow locks, otherwise require read permission, or
                 * ownership
                 */
                if (exp->ex_flags & NFSEXP_NOAUTHNLM)
                        return 0;
                else 
                        acc = NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE;
        } 

The only consumer of MAY_BYPASS_GSS seems to be OP_PUTFH, now that
I'm looking closely for it. But I don't think we want the
no_auth_nlm export option to modify the way PUTFH behaves.
NeilBrown Oct. 10, 2024, 8:49 p.m. UTC | #16
On Thu, 10 Oct 2024, Chuck Lever wrote:
> On Thu, Oct 10, 2024 at 07:14:07AM +1100, NeilBrown wrote:
> > On Thu, 10 Oct 2024, Chuck Lever wrote:
> > > On Tue, Oct 08, 2024 at 05:47:55PM -0400, NeilBrown wrote:
> > > > And NFSD_MAY_LOCK should be discarded, and nlm_fopen() should set
> > > > NFSD_MAY_BYPASS_SEC.
> > > 
> > > 366         /*                                                                      
> > > 367          * pseudoflavor restrictions are not enforced on NLM,                   
> > > 
> > > Wrt the mention of "NLM", nfsd4_lock() also sets NFSD_MAY_LOCK.
> > 
> > True, but it shouldn't.  NFSD_MAY_LOCK is only used to bypass the GSS
> > requirement.  It must have been copied into nfsd4_lock() without a full
> > understanding of its purpose.
> 
> nfsd4_lock()'s use of MAY_LOCK goes back before the git era, so it's
> difficult to say with certainty.
> 
> I would like to keep such subtle changes bisectable. To me, it seems
> like it would be a basic first step to change the fh_verify() call
> in nfsd4_lock() to use (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)
> instead of NFSD_MAY_LOCK, as a separate patch.

Yes, that is sensible ...  though lockd used NFSD_MAY_WRITE for write
locks.
So if a process doesn't have read access to a file but does have write
access, and isn't the owner, then NLM would grant a write lock, but
NFSv4 would not.  check_fmode_for_setlk() makes the same choice, so a
local user could also get the lock.  Only NFSv4 would reject it.

> 
> 
> > > 368          * which clients virtually always use auth_sys for,                     
> > > 369          * even while using RPCSEC_GSS for NFS.                                 
> > > 370          */                                                                     
> > > 371         if (access & NFSD_MAY_LOCK)                                             
> > > 372                 goto skip_pseudoflavor_check;                                   
> > > 373         if (access & NFSD_MAY_BYPASS_GSS)                                       
> > > 374                 may_bypass_gss = true;
> > > 375         /*                                                                      
> > > 376          * Clients may expect to be able to use auth_sys during mount,          
> > > 377          * even if they use gss for everything else; see section 2.3.2          
> > > 378          * of rfc 2623.                                                         
> > > 379          */                                                                     
> > > 380         if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT                                
> > > 381                         && exp->ex_path.dentry == dentry)                       
> > > 382                 may_bypass_gss = true;                                          
> > > 383                                                                                 
> > > 384         error = check_nfsd_access(exp, rqstp, may_bypass_gss);                  
> > > 385         if (error)                                                              
> > > 386                 goto out;                                                       
> > > 387                                                                                 
> > > 388 skip_pseudoflavor_check:                                                        
> > > 389         /* Finally, check access permissions. */                                
> > > 390         error = nfsd_permission(cred, exp, dentry, access);     
> > > 
> > > MAY_LOCK is checked in nfsd_permission() and __fh_verify().
> > > 
> > > But MAY_BYPASS_GSS is set in loads of places that use those two
> > > functions. How can we be certain that the two flags are equivalent? 
> > 
> > We can be certain by looking at the effect.  Before a recent patch they
> > both did "goto skip_pseudoflavor_check" and nothing else.
> 
> I'm still not convinced MAY_LOCK and MAY_BYPASS_GSS are 100%
> equivalent.  nfsd_permission() checks for MAY_LOCK, but does not
> check for MAY_BYPASS_GSS:
> 
>         if (acc & NFSD_MAY_LOCK) {
>                 /* If we cannot rely on authentication in NLM requests,
>                  * just allow locks, otherwise require read permission, or
>                  * ownership
>                  */
>                 if (exp->ex_flags & NFSEXP_NOAUTHNLM)
>                         return 0;
>                 else 
>                         acc = NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE;
>         } 
> 
> The only consumer of MAY_BYPASS_GSS seems to be OP_PUTFH, now that
> I'm looking closely for it. But I don't think we want the
> no_auth_nlm export option to modify the way PUTFH behaves.

Thanks for fact-checking my claim!  I had forgotten about noauthnlm.

I'll suggest a patch which might make it all a bit clearer.

Thanks,
NeilBrown


> 
> 
> -- 
> Chuck Lever
>
diff mbox series

Patch

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 50b3135d07ac..eb11d3fdffe1 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1074,7 +1074,7 @@  static struct svc_export *exp_find(struct cache_detail *cd,
 	return exp;
 }
 
-__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
+__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss)
 {
 	struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
 	struct svc_xprt *xprt = rqstp->rq_xprt;
@@ -1120,6 +1120,23 @@  __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
 	if (nfsd4_spo_must_allow(rqstp))
 		return 0;
 
+	/* Some calls may be processed without authentication
+	 * on GSS exports. For example NFS2/3 calls on root
+	 * directory, see section 2.3.2 of rfc 2623.
+	 * For "may_bypass_gss" check that export has really
+	 * enabled some GSS flavor and also check that the
+	 * used auth flavor is without auth (none or sys).
+	 */
+	if (may_bypass_gss && (
+	     rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
+	     rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)) {
+		for (f = exp->ex_flavors; f < end; f++) {
+			if (f->pseudoflavor == RPC_AUTH_GSS ||
+			    f->pseudoflavor >= RPC_AUTH_GSS_KRB5)
+				return 0;
+		}
+	}
+
 denied:
 	return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
 }
diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
index ca9dc230ae3d..dc7cf4f6ac53 100644
--- a/fs/nfsd/export.h
+++ b/fs/nfsd/export.h
@@ -100,7 +100,7 @@  struct svc_expkey {
 #define EX_WGATHER(exp)		((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
 
 int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp);
-__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
+__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp, bool may_bypass_gss);
 
 /*
  * Function declarations
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 2e39cf2e502a..0f67f4a7b8b2 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -2791,7 +2791,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);
+				op->status = check_nfsd_access(current_fh->fh_export, rqstp, false);
 		}
 encode_op:
 		if (op->status == nfserr_replay_me) {
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 97f583777972..b45ea5757652 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3775,7 +3775,7 @@  nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name,
 			nfserr = nfserrno(err);
 			goto out_put;
 		}
-		nfserr = check_nfsd_access(exp, cd->rd_rqstp);
+		nfserr = check_nfsd_access(exp, cd->rd_rqstp, false);
 		if (nfserr)
 			goto out_put;
 
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index dd4e11a703aa..ed0eabfa3cb0 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -329,6 +329,7 @@  fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
 {
 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 	struct svc_export *exp = NULL;
+	bool may_bypass_gss = false;
 	struct dentry	*dentry;
 	__be32		error;
 
@@ -375,8 +376,13 @@  fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
 	 * which clients virtually always use auth_sys for,
 	 * even while using RPCSEC_GSS for NFS.
 	 */
-	if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
+	if (access & NFSD_MAY_LOCK)
 		goto skip_pseudoflavor_check;
+	/*
+	 * NFS4 PUTFH may bypass GSS (see nfsd4_putfh() in nfs4proc.c).
+	 */
+	if (access & NFSD_MAY_BYPASS_GSS)
+		may_bypass_gss = true;
 	/*
 	 * Clients may expect to be able to use auth_sys during mount,
 	 * even if they use gss for everything else; see section 2.3.2
@@ -384,9 +390,9 @@  fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
 	 */
 	if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
 			&& exp->ex_path.dentry == dentry)
-		goto skip_pseudoflavor_check;
+		may_bypass_gss = true;
 
-	error = check_nfsd_access(exp, rqstp);
+	error = check_nfsd_access(exp, rqstp, may_bypass_gss);
 	if (error)
 		goto out;
 
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 29b1f3613800..b2f5ea7c2187 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -320,7 +320,7 @@  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);
+	err = check_nfsd_access(exp, rqstp, false);
 	if (err)
 		goto out;
 	/*