Return-Path: Received: from fieldses.org ([173.255.197.46]:60602 "EHLO fieldses.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755050AbdCJRbJ (ORCPT ); Fri, 10 Mar 2017 12:31:09 -0500 Date: Fri, 10 Mar 2017 12:31:07 -0500 From: "J. Bruce Fields" To: andros@netapp.com Cc: trond.myklebust@primarydata.com, schumaker.anna@gmail.com, linux-nfs@vger.kernel.org Subject: Re: [PATCH Version 5 08/17] SUNRPC AUTH_GSS RPCSEC_GSS_CREATE with label payload Message-ID: <20170310173107.GE29791@fieldses.org> References: <20170224221953.5502-1-andros@netapp.com> <20170224221953.5502-9-andros@netapp.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii In-Reply-To: <20170224221953.5502-9-andros@netapp.com> Sender: linux-nfs-owner@vger.kernel.org List-ID: On Fri, Feb 24, 2017 at 05:19:44PM -0500, andros@netapp.com wrote: > From: Andy Adamson > > Signed-off-by: Andy Adamson > --- > net/sunrpc/auth_gss/auth_gss.c | 140 ++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 138 insertions(+), 2 deletions(-) > > diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c > index 6ffb16d..98971cf 100644 > --- a/net/sunrpc/auth_gss/auth_gss.c > +++ b/net/sunrpc/auth_gss/auth_gss.c > @@ -52,9 +52,12 @@ > #include > #include > #include > +#include > > #include "../netns.h" > > +static int gss3_create_label(struct rpc_cred *cred, int gss_vers); > + > static const struct rpc_authops authgss_ops; > > static const struct rpc_credops gss_credops; > @@ -128,6 +131,20 @@ gss_put_ctx(struct gss_cl_ctx *ctx) > gss_free_ctx(ctx); > } > > +/* gss3_label_enabled: > + * Called to determine if Full Mode Mandatory Access Control (MAC) > + * over a GSS connection is desired. > + * > + * Note: > + * Currently Full Mode MAC is assuemed if SeLinux is enabled and > + * RPCSEC_GSS version 3 is in use. Eventually I guess we may want support for GSSv3-enabled copy without full MAC, so we'll want some way to configure this. Also, do I understand right that currently it's gssd that decides whether to enable GSSv3, by passing down the new version number? How will the user choose whether to enable GSSv3 or not? Should that be a mount option? The mount option could then cause some "use_gss3" flag to be added in rpc_pipefs, in an info file or whatever. I think that'd also provide backwards compatibility (if you're not already handling that some other way), since gssd could use the presence of that flag to decide whether the kernel was new enough to support the new downcall. --b. > + */ > +static inline bool > +gss3_label_assertion_is_enabled(u32 rpcsec_version) > +{ > + return (rpcsec_version == RPC_GSS3_VERSION && selinux_is_enabled()); > +} > + > /* gss_cred_set_ctx: > * called by gss_upcall_callback and gss_create_upcall in order > * to set the gss context. The actual exchange of an old context > @@ -145,6 +162,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) > set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); > smp_mb__before_atomic(); > clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); > + gss3_create_label(cred, ctx->gc_v); > } > > static const void * > @@ -1602,6 +1620,75 @@ static int gss_cred_is_negative_entry(struct rpc_cred *cred) > #define GSS3_createres_maxsz (1 /* cr_hlen */ + \ > XDR_QUADLEN(1024) /* cr_handle*/ + \ > GSS3_createargs_maxsz) > +#define GSS3_labelargs_maxsz (1 /* la_lfs */ + \ > + 1 /* la_pi */ + \ > + 1 /* la_label.len */ + \ > + XDR_QUADLEN(1024) /* la_label.data */) > +#define GSS3_labelres_maxsz GSS3_labelargs_maxsz > + > +static void > +gss3_enc_label(struct rpc_rqst *req, struct xdr_stream *xdr, > + const struct gss3_create_args *g3ca) > +{ > + struct gss3_label *gl; > + __be32 *p; > + > + gl = &g3ca->ca_assertions[0].u.au_label; > + > + dprintk("RPC: %5u encoding GSSv3 label %s:%d\n", req->rq_task->tk_pid, > + (char *)gl->la_label.data, gl->la_label.len); > + > + p = xdr_reserve_space(xdr, GSS3_labelargs_maxsz << 2); > + *p++ = cpu_to_be32(0); /* la_lfs */ > + *p++ = cpu_to_be32(0); /* la_pi */ > + p = xdr_encode_netobj(p, &gl->la_label); > +} > + > +static int > +gss3_dec_label(struct rpc_rqst *req, struct xdr_stream *xdr, > + struct gss3_create_res *g3cr) > +{ > + struct gss3_label *gl; > + struct gss3_assertion_u *g3a; > + __be32 *p; > + > + /* Used to store assertion in parent gss_cl_ctx */ > + g3a = kzalloc(sizeof(*g3a), GFP_KERNEL); > + if (!g3a) > + goto out_err; > + > + g3a->au_type = GSS3_LABEL; > + gl = &g3a->u.au_label; > + > + p = xdr_inline_decode(xdr, 12); > + if (unlikely(!p)) > + goto out_overflow; > + > + gl->la_lfs = be32_to_cpup(p++); > + gl->la_pi = be32_to_cpup(p++); > + gl->la_label.len = be32_to_cpup(p++); > + > + p = xdr_inline_decode(xdr, gl->la_label.len); > + if (unlikely(!p)) > + goto out_overflow; > + > + gl->la_label.data = kmemdup(p, gl->la_label.len, GFP_KERNEL); > + if (!gl->la_label.data) > + goto out_free_assert; > + > + g3cr->cr_assertions = g3a; > + > + return 0; > + > +out_free_assert: > + kfree(g3a); > +out_err: > + return -EIO; > +out_overflow: > + pr_warn("RPC %s End of receive buffer. Remaining len: %tu words.\n", > + __func__, xdr->end - xdr->p); > + goto out_free_assert; > +} > > static void > gss3_enc_create(struct rpc_rqst *req, struct xdr_stream *xdr, > @@ -1618,6 +1705,8 @@ gss3_enc_create(struct rpc_rqst *req, struct xdr_stream *xdr, > *p++ = type; > switch (type) { > case GSS3_LABEL: > + gss3_enc_label(req, xdr, g3ca); > + break; > case GSS3_PRIVS: > default: > /* drop through to return */ > @@ -1673,6 +1762,9 @@ gss3_dec_create(struct rpc_rqst *req, struct xdr_stream *xdr, > type = be32_to_cpup(p++); > switch (type) { > case GSS3_LABEL: > + if (gss3_dec_label(req, xdr, g3cr) != 0) > + goto out_free_handle; > + break; > case GSS3_PRIVS: > default: > pr_warn("RPC Unsupported gss3 create assertion %d\n", type); > @@ -1692,13 +1784,16 @@ gss3_dec_create(struct rpc_rqst *req, struct xdr_stream *xdr, > > #define RPC_PROC_NULL 0 > > +#define GSS3_create_args_max (GSS3_createargs_maxsz + GSS3_labelargs_maxsz) > +#define GSS3_create_res_max (GSS3_createres_maxsz + GSS3_labelres_maxsz) > + > struct rpc_procinfo gss3_label_assertion[] = { > [RPC_GSS_PROC_CREATE] = { > .p_proc = RPC_PROC_NULL, > .p_encode = (kxdreproc_t)gss3_enc_create, > .p_decode = (kxdrdproc_t)gss3_dec_create, > - .p_arglen = GSS3_createargs_maxsz, > - .p_replen = GSS3_createres_maxsz, > + .p_arglen = GSS3_create_args_max, > + .p_replen = GSS3_create_res_max, > .p_statidx = RPC_GSS_PROC_CREATE, > .p_timer = 0, > .p_name = "GSS_PROC_CREATE", > @@ -1773,6 +1868,47 @@ gss3_proc_create(struct rpc_cred *cred, struct gss3_assertion_u *asserts, > return ret; > } > > +/** > + * GSS3 Label Assertion > + * > + * Support one label assertion > + * > + * XXX Return not checked. Should we fail nfs requests if > + * a label fails to be created? I think the server enforcing > + * Full Mode MAC will reject an NFS request that does not use > + * a GSS3 (child) context with the correct label. > + */ > +static int > +gss3_create_label(struct rpc_cred *cred, int gss_vers) > +{ > + struct gss3_assertion_u *asserts; > + struct gss3_label *gl; > + int ret; > + > + if (!gss3_label_assertion_is_enabled(gss_vers)) > + return -EINVAL; > + > + asserts = kzalloc(sizeof(*asserts), GFP_NOFS); > + if (!asserts) > + return -ENOMEM; > + > + /* NOTE: not setting la_lfs, la_pi. Do we even need them? */ > + asserts->au_type = GSS3_LABEL; > + gl = &asserts->u.au_label; > + > + ret = -EINVAL; > + ret = security_current_sid_to_context((char **)&gl->la_label.data, > + &gl->la_label.len); > + if (ret) > + goto out_free_asserts; > + > + return gss3_proc_create(cred, asserts, 1); > + > +out_free_asserts: > + kfree(asserts); > + return ret; > +} > + > /* > * Refresh credentials. XXX - finish > */ > -- > 2.9.3