On Mon, 2023-03-20 at 10:24 -0400, Chuck Lever wrote: > From: Chuck Lever <chuck.lever@xxxxxxxxxx> > > Enable administrators to require clients to use transport layer > security when accessing particular exports. > Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> > --- > fs/nfsd/export.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--- > fs/nfsd/export.h | 11 +++++++++++ > 2 files changed, 61 insertions(+), 3 deletions(-) > > diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c > index 668c7527b17e..171ebc21bf07 100644 > --- a/fs/nfsd/export.c > +++ b/fs/nfsd/export.c > @@ -439,7 +439,6 @@ static int check_export(struct path *path, int *flags, unsigned char *uuid) > return -EINVAL; > } > return 0; > - > } > > #ifdef CONFIG_NFSD_V4 > @@ -546,6 +545,31 @@ static inline int > secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; } > #endif > > +static int xprtsec_parse(char **mesg, char *buf, struct svc_export *exp) > +{ > + unsigned int i, mode, listsize; > + int err; > + > + err = get_uint(mesg, &listsize); > + if (err) > + return err; > + if (listsize > 3) > + return -EINVAL; Might want to make a note that the limit of 3 here is arbitrary, and that it might need to be lifted in the future (if/when we grow other xprtsec options). > + > + exp->ex_xprtsec_modes = 0; > + for (i = 0; i < listsize; i++) { > + err = get_uint(mesg, &mode); > + if (err) > + return err; > + mode--; > + if (mode > 2) > + return -EINVAL; > + /* Ad hoc */ > + exp->ex_xprtsec_modes |= 1 << mode; > + } > + return 0; > +} > + > static inline int > nfsd_uuid_parse(char **mesg, char *buf, unsigned char **puuid) > { > @@ -608,6 +632,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) > exp.ex_client = dom; > exp.cd = cd; > exp.ex_devid_map = NULL; > + exp.ex_xprtsec_modes = NFSEXP_XPRTSEC_ALL; > > /* expiry */ > err = -EINVAL; > @@ -650,6 +675,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) > err = nfsd_uuid_parse(&mesg, buf, &exp.ex_uuid); > else if (strcmp(buf, "secinfo") == 0) > err = secinfo_parse(&mesg, buf, &exp); > + else if (strcmp(buf, "xprtsec") == 0) > + err = xprtsec_parse(&mesg, buf, &exp); > else > /* quietly ignore unknown words and anything > * following. Newer user-space can try to set > @@ -663,6 +690,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) > err = check_export(&exp.ex_path, &exp.ex_flags, exp.ex_uuid); > if (err) > goto out4; > + > /* > * No point caching this if it would immediately expire. > * Also, this protects exportfs's dummy export from the > @@ -824,6 +852,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) > for (i = 0; i < MAX_SECINFO_LIST; i++) { > new->ex_flavors[i] = item->ex_flavors[i]; > } > + new->ex_xprtsec_modes = item->ex_xprtsec_modes; > } > > static struct cache_head *svc_export_alloc(void) > @@ -1035,9 +1064,26 @@ static struct svc_export *exp_find(struct cache_detail *cd, > > __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) > { > - struct exp_flavor_info *f; > - struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; > + struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors; > + struct svc_xprt *xprt = rqstp->rq_xprt; > + > + if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_NONE) { > + if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags)) > + goto ok; > + } > + if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_TLS) { > + if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) && > + !test_bit(XPT_PEER_AUTH, &xprt->xpt_flags)) > + goto ok; > + } > + if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_MTLS) { > + if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) && > + test_bit(XPT_PEER_AUTH, &xprt->xpt_flags)) > + goto ok; > + } > + goto denied; > > +ok: > /* legacy gss-only clients are always OK: */ > if (exp->ex_client == rqstp->rq_gssclient) > return 0; > @@ -1062,6 +1108,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) > if (nfsd4_spo_must_allow(rqstp)) > 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 d03f7f6a8642..61e1e8383c3d 100644 > --- a/fs/nfsd/export.h > +++ b/fs/nfsd/export.h > @@ -77,8 +77,19 @@ struct svc_export { > struct cache_detail *cd; > struct rcu_head ex_rcu; > struct export_stats ex_stats; > + unsigned long ex_xprtsec_modes; > }; > > +enum { > + NFSEXP_XPRTSEC_NONE = 0x01, > + NFSEXP_XPRTSEC_TLS = 0x02, > + NFSEXP_XPRTSEC_MTLS = 0x04, > +}; > + > +#define NFSEXP_XPRTSEC_ALL (NFSEXP_XPRTSEC_NONE | \ > + NFSEXP_XPRTSEC_TLS | \ > + NFSEXP_XPRTSEC_MTLS) > + > /* an "export key" (expkey) maps a filehandlefragement to an > * svc_export for a given client. There can be several per export, > * for the different fsid types. > > -- Jeff Layton <jlayton@xxxxxxxxxx>