--- /dev/null
+From 778e512bb1d3315c6b55832248cd30c566c081d7 Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Wed, 21 Aug 2013 10:32:52 -0400
+Subject: rpc: clean up decoding of gssproxy linux creds
+
+From: "J. Bruce Fields" <bfields@redhat.com>
+
+commit 778e512bb1d3315c6b55832248cd30c566c081d7 upstream.
+
+We can use the normal coding infrastructure here.
+
+Two minor behavior changes:
+
+ - we're assuming no wasted space at the end of the linux cred.
+ That seems to match gss-proxy's behavior, and I can't see why
+ it would need to do differently in the future.
+
+ - NGROUPS_MAX check added: note groups_alloc doesn't do this,
+ this is the caller's responsibility.
+
+Tested-by: Simo Sorce <simo@redhat.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/sunrpc/auth_gss/gss_rpc_xdr.c | 32 +++++++++++++-------------------
+ 1 file changed, 13 insertions(+), 19 deletions(-)
+
+--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c
++++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
+@@ -166,14 +166,14 @@ static int dummy_dec_opt_array(struct xd
+ return 0;
+ }
+
+-static int get_s32(void **p, void *max, s32 *res)
++static int get_s32(struct xdr_stream *xdr, s32 *res)
+ {
+- void *base = *p;
+- void *next = (void *)((char *)base + sizeof(s32));
+- if (unlikely(next > max || next < base))
++ __be32 *p;
++
++ p = xdr_inline_decode(xdr, 4);
++ if (!p)
+ return -EINVAL;
+- memcpy(res, base, sizeof(s32));
+- *p = next;
++ memcpy(res, p, sizeof(s32));
+ return 0;
+ }
+
+@@ -182,7 +182,6 @@ static int gssx_dec_linux_creds(struct x
+ {
+ u32 length;
+ __be32 *p;
+- void *q, *end;
+ s32 tmp;
+ int N, i, err;
+
+@@ -192,33 +191,28 @@ static int gssx_dec_linux_creds(struct x
+
+ length = be32_to_cpup(p);
+
+- /* FIXME: we do not want to use the scratch buffer for this one
+- * may need to use functions that allows us to access an io vector
+- * directly */
+- p = xdr_inline_decode(xdr, length);
+- if (unlikely(p == NULL))
++ if (length > (3 + NGROUPS_MAX) * sizeof(u32))
+ return -ENOSPC;
+
+- q = p;
+- end = q + length;
+-
+ /* uid */
+- err = get_s32(&q, end, &tmp);
++ err = get_s32(xdr, &tmp);
+ if (err)
+ return err;
+ creds->cr_uid = make_kuid(&init_user_ns, tmp);
+
+ /* gid */
+- err = get_s32(&q, end, &tmp);
++ err = get_s32(xdr, &tmp);
+ if (err)
+ return err;
+ creds->cr_gid = make_kgid(&init_user_ns, tmp);
+
+ /* number of additional gid's */
+- err = get_s32(&q, end, &tmp);
++ err = get_s32(xdr, &tmp);
+ if (err)
+ return err;
+ N = tmp;
++ if ((3 + N) * sizeof(u32) != length)
++ return -EINVAL;
+ creds->cr_group_info = groups_alloc(N);
+ if (creds->cr_group_info == NULL)
+ return -ENOMEM;
+@@ -226,7 +220,7 @@ static int gssx_dec_linux_creds(struct x
+ /* gid's */
+ for (i = 0; i < N; i++) {
+ kgid_t kgid;
+- err = get_s32(&q, end, &tmp);
++ err = get_s32(xdr, &tmp);
+ if (err)
+ goto out_free_groups;
+ err = -EINVAL;
--- /dev/null
+From 6a36978e6931e6601be586eb313375335f2cfaa3 Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Fri, 23 Aug 2013 11:17:53 -0400
+Subject: rpc: comment on linux_cred encoding, treat all as unsigned
+
+From: "J. Bruce Fields" <bfields@redhat.com>
+
+commit 6a36978e6931e6601be586eb313375335f2cfaa3 upstream.
+
+The encoding of linux creds is a bit confusing.
+
+Also: I think in practice it doesn't really matter whether we treat any
+of these things as signed or unsigned, but unsigned seems more
+straightforward: uid_t/gid_t are unsigned and it simplifies the ngroups
+overflow check.
+
+Tested-by: Simo Sorce <simo@redhat.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/sunrpc/auth_gss/gss_rpc_xdr.c | 18 ++++++++++--------
+ 1 file changed, 10 insertions(+), 8 deletions(-)
+
+--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c
++++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
+@@ -166,14 +166,15 @@ static int dummy_dec_opt_array(struct xd
+ return 0;
+ }
+
+-static int get_s32(struct xdr_stream *xdr, s32 *res)
++static int get_host_u32(struct xdr_stream *xdr, u32 *res)
+ {
+ __be32 *p;
+
+ p = xdr_inline_decode(xdr, 4);
+ if (!p)
+ return -EINVAL;
+- memcpy(res, p, sizeof(s32));
++ /* Contents of linux creds are all host-endian: */
++ memcpy(res, p, sizeof(u32));
+ return 0;
+ }
+
+@@ -182,8 +183,9 @@ static int gssx_dec_linux_creds(struct x
+ {
+ u32 length;
+ __be32 *p;
+- s32 tmp;
+- int N, i, err;
++ u32 tmp;
++ u32 N;
++ int i, err;
+
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(p == NULL))
+@@ -195,19 +197,19 @@ static int gssx_dec_linux_creds(struct x
+ return -ENOSPC;
+
+ /* uid */
+- err = get_s32(xdr, &tmp);
++ err = get_host_u32(xdr, &tmp);
+ if (err)
+ return err;
+ creds->cr_uid = make_kuid(&init_user_ns, tmp);
+
+ /* gid */
+- err = get_s32(xdr, &tmp);
++ err = get_host_u32(xdr, &tmp);
+ if (err)
+ return err;
+ creds->cr_gid = make_kgid(&init_user_ns, tmp);
+
+ /* number of additional gid's */
+- err = get_s32(xdr, &tmp);
++ err = get_host_u32(xdr, &tmp);
+ if (err)
+ return err;
+ N = tmp;
+@@ -220,7 +222,7 @@ static int gssx_dec_linux_creds(struct x
+ /* gid's */
+ for (i = 0; i < N; i++) {
+ kgid_t kgid;
+- err = get_s32(xdr, &tmp);
++ err = get_host_u32(xdr, &tmp);
+ if (err)
+ goto out_free_groups;
+ err = -EINVAL;
--- /dev/null
+From 9dfd87da1aeb0fd364167ad199f40fe96a6a87be Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Tue, 20 Aug 2013 18:13:27 -0400
+Subject: rpc: fix huge kmalloc's in gss-proxy
+
+From: "J. Bruce Fields" <bfields@redhat.com>
+
+commit 9dfd87da1aeb0fd364167ad199f40fe96a6a87be upstream.
+
+The reply to a gssproxy can include up to NGROUPS_MAX gid's, which will
+take up more than a page. We therefore need to allocate an array of
+pages to hold the reply instead of trying to allocate a single huge
+buffer.
+
+Tested-by: Simo Sorce <simo@redhat.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/sunrpc/auth_gss/gss_rpc_upcall.c | 30 ++++++++++++++++++++++++++++++
+ net/sunrpc/auth_gss/gss_rpc_xdr.c | 3 +++
+ net/sunrpc/auth_gss/gss_rpc_xdr.h | 5 ++++-
+ 3 files changed, 37 insertions(+), 1 deletion(-)
+
+--- a/net/sunrpc/auth_gss/gss_rpc_upcall.c
++++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c
+@@ -213,6 +213,30 @@ static int gssp_call(struct net *net, st
+ return status;
+ }
+
++static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg)
++{
++ int i;
++
++ for (i = 0; i < arg->npages && arg->pages[i]; i++)
++ __free_page(arg->pages[i]);
++}
++
++static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg)
++{
++ int i;
++
++ arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE);
++ arg->pages = kzalloc(arg->npages * sizeof(struct page *), GFP_KERNEL);
++
++ for (i=0; i < arg->npages; i++) {
++ arg->pages[i] = alloc_page(GFP_KERNEL);
++ if (arg->pages[i] == NULL) {
++ gssp_free_receive_pages(arg);
++ return -ENOMEM;
++ }
++ }
++ return 0;
++}
+
+ /*
+ * Public functions
+@@ -261,10 +285,16 @@ int gssp_accept_sec_context_upcall(struc
+ arg.context_handle = &ctxh;
+ res.output_token->len = GSSX_max_output_token_sz;
+
++ ret = gssp_alloc_receive_pages(&arg);
++ if (ret)
++ return ret;
++
+ /* use nfs/ for targ_name ? */
+
+ ret = gssp_call(net, &msg);
+
++ gssp_free_receive_pages(&arg);
++
+ /* we need to fetch all data even in case of error so
+ * that we can free special strctures is they have been allocated */
+ data->major_status = res.status.major_status;
+--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c
++++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
+@@ -780,6 +780,9 @@ void gssx_enc_accept_sec_context(struct
+ /* arg->options */
+ err = dummy_enc_opt_array(xdr, &arg->options);
+
++ xdr_inline_pages(&req->rq_rcv_buf,
++ PAGE_SIZE/2 /* pretty arbitrary */,
++ arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE);
+ done:
+ if (err)
+ dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err);
+--- a/net/sunrpc/auth_gss/gss_rpc_xdr.h
++++ b/net/sunrpc/auth_gss/gss_rpc_xdr.h
+@@ -147,6 +147,8 @@ struct gssx_arg_accept_sec_context {
+ struct gssx_cb *input_cb;
+ u32 ret_deleg_cred;
+ struct gssx_option_array options;
++ struct page **pages;
++ unsigned int npages;
+ };
+
+ struct gssx_res_accept_sec_context {
+@@ -240,7 +242,8 @@ int gssx_dec_accept_sec_context(struct r
+ 2 * GSSX_max_princ_sz + \
+ 8 + 8 + 4 + 4 + 4)
+ #define GSSX_max_output_token_sz 1024
+-#define GSSX_max_creds_sz (4 + 4 + 4 + NGROUPS_MAX * 4)
++/* grouplist not included; we allocate separate pages for that: */
++#define GSSX_max_creds_sz (4 + 4 + 4 /* + NGROUPS_MAX*4 */)
+ #define GSSX_RES_accept_sec_context_sz (GSSX_default_status_sz + \
+ GSSX_default_ctx_sz + \
+ GSSX_max_output_token_sz + \
--- /dev/null
+From d4a516560fc96a9d486a9939bcb567e3fdce8f49 Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Fri, 23 Aug 2013 17:26:28 -0400
+Subject: rpc: let xdr layer allocate gssproxy receieve pages
+
+From: "J. Bruce Fields" <bfields@redhat.com>
+
+commit d4a516560fc96a9d486a9939bcb567e3fdce8f49 upstream.
+
+In theory the linux cred in a gssproxy reply can include up to
+NGROUPS_MAX data, 256K of data. In the common case we expect it to be
+shorter. So do as the nfsv3 ACL code does and let the xdr code allocate
+the pages as they come in, instead of allocating a lot of pages that
+won't typically be used.
+
+Tested-by: Simo Sorce <simo@redhat.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/sunrpc/auth_gss/gss_rpc_upcall.c | 16 ++++++----------
+ 1 file changed, 6 insertions(+), 10 deletions(-)
+
+--- a/net/sunrpc/auth_gss/gss_rpc_upcall.c
++++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c
+@@ -223,18 +223,14 @@ static void gssp_free_receive_pages(stru
+
+ static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg)
+ {
+- int i;
+-
+ arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE);
+ arg->pages = kzalloc(arg->npages * sizeof(struct page *), GFP_KERNEL);
+-
+- for (i=0; i < arg->npages; i++) {
+- arg->pages[i] = alloc_page(GFP_KERNEL);
+- if (arg->pages[i] == NULL) {
+- gssp_free_receive_pages(arg);
+- return -ENOMEM;
+- }
+- }
++ /*
++ * XXX: actual pages are allocated by xdr layer in
++ * xdr_partial_copy_from_skb.
++ */
++ if (!arg->pages)
++ return -ENOMEM;
+ return 0;
+ }
+
perf-tools-handle-jited-code-in-shared-memory.patch
bio-integrity-fix-use-of-bs-bio_integrity_pool-after-free.patch
cfq-explicitly-use-64bit-divide-operation-for-64bit-arguments.patch
+rpc-clean-up-decoding-of-gssproxy-linux-creds.patch
+rpc-comment-on-linux_cred-encoding-treat-all-as-unsigned.patch
+rpc-fix-huge-kmalloc-s-in-gss-proxy.patch
+rpc-let-xdr-layer-allocate-gssproxy-receieve-pages.patch