From: "J. Bruce Fields" <bfields@fieldses.org>
To: Chuck Lever <chuck.lever@oracle.com>
Cc: bfields@fields.org, linux-nfs@vger.kernel.org
Subject: Re: [PATCH] SUNRPC: Refactor nfsd4_do_encode_secinfo()
Date: Thu, 7 Feb 2013 10:02:13 -0500 [thread overview]
Message-ID: <20130207150213.GC3222@fieldses.org> (raw)
In-Reply-To: <20130201220308.13518.82164.stgit@seurat.1015granger.net>
On Fri, Feb 01, 2013 at 05:43:44PM -0500, Chuck Lever wrote:
> Clean up. This matches a similar API for the client side, and
> keeps ULP fingers out the of the GSS mech switch.
>
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> Acked-by: J. Bruce Fields <bfields@redhat.com>
> ---
>
> Bruce-
>
> This version of the patch follows the existing logic in
> nfsd4_do_encode_secinfo(): If the RPC layer can't find GSS info
> that matches an export security flavor, it assumes the flavor is
> not a GSS pseudoflavor, and simply puts it on the wire.
>
> However, if the below XDR encoding logic is given a legitimate GSS
> pseudoflavor but the RPC layer says it does not support that
> pseudoflavor for some reason, then we leak GSS pseudoflavor numbers
> onto the wire.
>
> I confirmed this happens by blacklisting rpcsec_gss_krb5, then
> attempted a client transition from the pseudo-fs to a Kerberos-only
> share. The client received a flavor list containing the Kerberos
> pseudoflavor numbers, rather than GSS tuples.
>
> The encoder logic can check that each pseudoflavor is less than
> MAXFLAVOR before writing it into the buffer, to prevent this. But
> after "nflavs" is written into the XDR buffer, the encoder can't
> skip writing flavor information into the buffer when it discovers
> the RPC layer doesn't support that flavor.
>
> Is there some way of writing "nflavs" into the XDR buffer after
> the loop that writes the flavor information is complete?
Yes, you can save a pointer and then go back and fill that in--see
encode_fattr for an example.
--b.
>
> What if "nflavs" turns out to be zero? RFC 3530bis, 15.33.4 does
> not explicitly say what should be done if the array of security
> mechanisms for that client and file handle contains zero items.
>
> Or is there a better way to handle this situation? Also, should we
> care about this scenario?
>
>
> fs/nfsd/nfs4xdr.c | 24 +++++++++++------------
> include/linux/sunrpc/auth.h | 2 ++
> include/linux/sunrpc/gss_api.h | 3 +++
> net/sunrpc/auth.c | 34 +++++++++++++++++++++++++++++++++
> net/sunrpc/auth_gss/auth_gss.c | 1 +
> net/sunrpc/auth_gss/gss_mech_switch.c | 34 +++++++++++++++++++++++++++++++--
> 6 files changed, 83 insertions(+), 15 deletions(-)
>
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 0dc1158..424f5a2 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -3127,10 +3127,9 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
>
> static __be32
> nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
> - __be32 nfserr,struct svc_export *exp)
> + __be32 nfserr, struct svc_export *exp)
> {
> - int i = 0;
> - u32 nflavs;
> + u32 i, nflavs;
> struct exp_flavor_info *flavs;
> struct exp_flavor_info def_flavs[2];
> __be32 *p;
> @@ -3161,30 +3160,29 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
> WRITE32(nflavs);
> ADJUST_ARGS();
> for (i = 0; i < nflavs; i++) {
> - u32 flav = flavs[i].pseudoflavor;
> - struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
> + struct rpcsec_gss_info info;
>
> - if (gm) {
> + if (rpcauth_get_gssinfo(flavs[i].pseudoflavor, &info) == 0) {
> RESERVE_SPACE(4);
> WRITE32(RPC_AUTH_GSS);
> ADJUST_ARGS();
> - RESERVE_SPACE(4 + gm->gm_oid.len);
> - WRITE32(gm->gm_oid.len);
> - WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
> + RESERVE_SPACE(4 + info.oid.len);
> + WRITE32(info.oid.len);
> + WRITEMEM(info.oid.data, info.oid.len);
> ADJUST_ARGS();
> RESERVE_SPACE(4);
> - WRITE32(0); /* qop */
> + WRITE32(info.qop);
> ADJUST_ARGS();
> RESERVE_SPACE(4);
> - WRITE32(gss_pseudoflavor_to_service(gm, flav));
> + WRITE32(info.service);
> ADJUST_ARGS();
> - gss_mech_put(gm);
> } else {
> RESERVE_SPACE(4);
> - WRITE32(flav);
> + WRITE32(flavs[i].pseudoflavor);
> ADJUST_ARGS();
> }
> }
> +
> out:
> if (exp)
> exp_put(exp);
> diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
> index 476e97c..c34ac17 100644
> --- a/include/linux/sunrpc/auth.h
> +++ b/include/linux/sunrpc/auth.h
> @@ -105,6 +105,7 @@ struct rpc_authops {
> void (*pipes_destroy)(struct rpc_auth *);
> int (*list_pseudoflavors)(rpc_authflavor_t *, int);
> rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *);
> + int (*flavor2info)(rpc_authflavor_t, struct rpcsec_gss_info *);
> };
>
> struct rpc_credops {
> @@ -140,6 +141,7 @@ int rpcauth_unregister(const struct rpc_authops *);
> struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
> void rpcauth_release(struct rpc_auth *);
> rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t, struct rpcsec_gss_info *);
> +int rpcauth_get_gssinfo(rpc_authflavor_t, struct rpcsec_gss_info *);
> int rpcauth_list_flavors(rpc_authflavor_t *, int);
> struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
> void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
> diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
> index e8299b2..dc1e51b 100644
> --- a/include/linux/sunrpc/gss_api.h
> +++ b/include/linux/sunrpc/gss_api.h
> @@ -132,6 +132,9 @@ void gss_mech_unregister(struct gss_api_mech *);
> /* Given a GSS security tuple, look up a pseudoflavor */
> rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *);
>
> +/* Given a pseudoflavor, look up a GSS security tuple */
> +int gss_mech_flavor2info(rpc_authflavor_t, struct rpcsec_gss_info *);
> +
> /* Returns a reference to a mechanism, given a name like "krb5" etc. */
> struct gss_api_mech *gss_mech_get_by_name(const char *);
>
> diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
> index ec18827..4c551f9 100644
> --- a/net/sunrpc/auth.c
> +++ b/net/sunrpc/auth.c
> @@ -158,6 +158,40 @@ rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info)
> EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor);
>
> /**
> + * rpcauth_get_gssinfo - find GSS tuple matching a GSS pseudoflavor
> + * @pseudoflavor: GSS pseudoflavor to match
> + * @info: rpcsec_gss_info structure to fill in
> + *
> + * Returns zero and fills in "info" if pseudoflavor matches a
> + * supported mechanism.
> + */
> +int
> +rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info)
> +{
> + rpc_authflavor_t flavor = pseudoflavor_to_flavor(pseudoflavor);
> + const struct rpc_authops *ops;
> + int result;
> +
> + if ((ops = auth_flavors[flavor]) == NULL)
> + request_module("rpc-auth-%u", flavor);
> + spin_lock(&rpc_authflavor_lock);
> + ops = auth_flavors[flavor];
> + if (ops == NULL || !try_module_get(ops->owner)) {
> + spin_unlock(&rpc_authflavor_lock);
> + return -ENOENT;
> + }
> + spin_unlock(&rpc_authflavor_lock);
> +
> + result = -ENOENT;
> + if (ops->flavor2info != NULL)
> + result = ops->flavor2info(pseudoflavor, info);
> +
> + module_put(ops->owner);
> + return result;
> +}
> +EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo);
> +
> +/**
> * rpcauth_list_flavors - discover registered flavors and pseudoflavors
> * @array: array to fill in
> * @size: size of "array"
> diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
> index 4522297..ade24b2 100644
> --- a/net/sunrpc/auth_gss/auth_gss.c
> +++ b/net/sunrpc/auth_gss/auth_gss.c
> @@ -1630,6 +1630,7 @@ static const struct rpc_authops authgss_ops = {
> .pipes_destroy = gss_pipes_dentries_destroy,
> .list_pseudoflavors = gss_mech_list_pseudoflavors,
> .info2flavor = gss_mech_info2flavor,
> + .flavor2info = gss_mech_flavor2info,
> };
>
> static const struct rpc_credops gss_credops = {
> diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
> index c8da89e..a8d6ee5 100644
> --- a/net/sunrpc/auth_gss/gss_mech_switch.c
> +++ b/net/sunrpc/auth_gss/gss_mech_switch.c
> @@ -240,8 +240,6 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
> return gm;
> }
>
> -EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor);
> -
> /**
> * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors
> * @array: array to fill in
> @@ -314,6 +312,38 @@ rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info)
> return pseudoflavor;
> }
>
> +/**
> + * gss_mech_flavor2info - look up a GSS tuple for a given pseudoflavor
> + * @pseudoflavor: GSS pseudoflavor to match
> + * @info: rpcsec_gss_info structure to fill in
> + *
> + * Returns zero and fills in "info" if pseudoflavor matches a
> + * supported mechanism. Otherwise a negative errno is returned.
> + */
> +int gss_mech_flavor2info(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info)
> +{
> + struct gss_api_mech *gm;
> + int i;
> +
> + gm = gss_mech_get_by_pseudoflavor(pseudoflavor);
> + if (gm == NULL)
> + return -ENOENT;
> +
> + for (i = 0; i < gm->gm_pf_num; i++) {
> + if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) {
> + memcpy(info->oid.data, gm->gm_oid.data, gm->gm_oid.len);
> + info->oid.len = gm->gm_oid.len;
> + info->qop = gm->gm_pfs[i].qop;
> + info->service = gm->gm_pfs[i].service;
> + gss_mech_put(gm);
> + return 0;
> + }
> + }
> +
> + gss_mech_put(gm);
> + return -ENOENT;
> +}
> +
> u32
> gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
> {
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2013-02-07 15:02 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-02-01 22:43 [PATCH] SUNRPC: Refactor nfsd4_do_encode_secinfo() Chuck Lever
2013-02-07 15:02 ` J. Bruce Fields [this message]
2013-02-07 15:58 ` Chuck Lever
2013-02-07 16:23 ` J. Bruce Fields
2013-02-07 16:26 ` Chuck Lever
2013-02-07 16:55 ` J. Bruce Fields
2013-02-07 17:03 ` Chuck Lever
2013-02-07 17:12 ` Chuck Lever
2013-02-07 17:14 ` J. Bruce Fields
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130207150213.GC3222@fieldses.org \
--to=bfields@fieldses.org \
--cc=bfields@fields.org \
--cc=chuck.lever@oracle.com \
--cc=linux-nfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox