c3c2c28
From: "J. Bruce Fields" <bfields@redhat.com>
c3c2c28
c3c2c28
commit 9dfd87da1aeb0fd364167ad199f40fe96a6a87be upstream.
c3c2c28
c3c2c28
The reply to a gssproxy can include up to NGROUPS_MAX gid's, which will
c3c2c28
take up more than a page.  We therefore need to allocate an array of
c3c2c28
pages to hold the reply instead of trying to allocate a single huge
c3c2c28
buffer.
c3c2c28
c3c2c28
Tested-by: Simo Sorce <simo@redhat.com>
c3c2c28
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
c3c2c28
---
c3c2c28
 net/sunrpc/auth_gss/gss_rpc_upcall.c |   30 ++++++++++++++++++++++++++++++
c3c2c28
 net/sunrpc/auth_gss/gss_rpc_xdr.c    |    3 +++
c3c2c28
 net/sunrpc/auth_gss/gss_rpc_xdr.h    |    5 ++++-
c3c2c28
 3 files changed, 37 insertions(+), 1 deletion(-)
c3c2c28
c3c2c28
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c
c3c2c28
index af7ffd4..be95af3 100644
c3c2c28
--- a/net/sunrpc/auth_gss/gss_rpc_upcall.c
c3c2c28
+++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c
c3c2c28
@@ -213,6 +213,30 @@ static int gssp_call(struct net *net, struct rpc_message *msg)
c3c2c28
 	return status;
c3c2c28
 }
c3c2c28
 
c3c2c28
+static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg)
c3c2c28
+{
c3c2c28
+	int i;
c3c2c28
+
c3c2c28
+	for (i = 0; i < arg->npages && arg->pages[i]; i++)
c3c2c28
+		__free_page(arg->pages[i]);
c3c2c28
+}
c3c2c28
+
c3c2c28
+static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg)
c3c2c28
+{
c3c2c28
+	int i;
c3c2c28
+
c3c2c28
+	arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE);
c3c2c28
+	arg->pages = kzalloc(arg->npages * sizeof(struct page *), GFP_KERNEL);
c3c2c28
+
c3c2c28
+	for (i=0; i < arg->npages; i++) {
c3c2c28
+		arg->pages[i] = alloc_page(GFP_KERNEL);
c3c2c28
+		if (arg->pages[i] == NULL) {
c3c2c28
+			gssp_free_receive_pages(arg);
c3c2c28
+			return -ENOMEM;
c3c2c28
+		}
c3c2c28
+	}
c3c2c28
+	return 0;
c3c2c28
+}
c3c2c28
 
c3c2c28
 /*
c3c2c28
  * Public functions
c3c2c28
@@ -261,10 +285,16 @@ int gssp_accept_sec_context_upcall(struct net *net,
c3c2c28
 		arg.context_handle = &ctx;;
c3c2c28
 	res.output_token->len = GSSX_max_output_token_sz;
c3c2c28
 
c3c2c28
+	ret = gssp_alloc_receive_pages(&arg;;
c3c2c28
+	if (ret)
c3c2c28
+		return ret;
c3c2c28
+
c3c2c28
 	/* use nfs/ for targ_name ? */
c3c2c28
 
c3c2c28
 	ret = gssp_call(net, &msg;;
c3c2c28
 
c3c2c28
+	gssp_free_receive_pages(&arg;;
c3c2c28
+
c3c2c28
 	/* we need to fetch all data even in case of error so
c3c2c28
 	 * that we can free special strctures is they have been allocated */
c3c2c28
 	data->major_status = res.status.major_status;
c3c2c28
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c
c3c2c28
index 3c19c7d..f0f78c5 100644
c3c2c28
--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c
c3c2c28
+++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
c3c2c28
@@ -780,6 +780,9 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
c3c2c28
 	/* arg->options */
c3c2c28
 	err = dummy_enc_opt_array(xdr, &arg->options);
c3c2c28
 
c3c2c28
+	xdr_inline_pages(&req->rq_rcv_buf,
c3c2c28
+		PAGE_SIZE/2 /* pretty arbitrary */,
c3c2c28
+		arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE);
c3c2c28
 done:
c3c2c28
 	if (err)
c3c2c28
 		dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
c3c2c28
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.h b/net/sunrpc/auth_gss/gss_rpc_xdr.h
c3c2c28
index 1c98b27..685a688 100644
c3c2c28
--- a/net/sunrpc/auth_gss/gss_rpc_xdr.h
c3c2c28
+++ b/net/sunrpc/auth_gss/gss_rpc_xdr.h
c3c2c28
@@ -147,6 +147,8 @@ struct gssx_arg_accept_sec_context {
c3c2c28
 	struct gssx_cb *input_cb;
c3c2c28
 	u32 ret_deleg_cred;
c3c2c28
 	struct gssx_option_array options;
c3c2c28
+	struct page **pages;
c3c2c28
+	unsigned int npages;
c3c2c28
 };
c3c2c28
 
c3c2c28
 struct gssx_res_accept_sec_context {
c3c2c28
@@ -240,7 +242,8 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
c3c2c28
 			     2 * GSSX_max_princ_sz + \
c3c2c28
 			     8 + 8 + 4 + 4 + 4)
c3c2c28
 #define GSSX_max_output_token_sz 1024
c3c2c28
-#define GSSX_max_creds_sz (4 + 4 + 4 + NGROUPS_MAX * 4)
c3c2c28
+/* grouplist not included; we allocate separate pages for that: */
c3c2c28
+#define GSSX_max_creds_sz (4 + 4 + 4 /* + NGROUPS_MAX*4 */)
c3c2c28
 #define GSSX_RES_accept_sec_context_sz (GSSX_default_status_sz + \
c3c2c28
 					GSSX_default_ctx_sz + \
c3c2c28
 					GSSX_max_output_token_sz + \
c3c2c28
-- 
c3c2c28
1.7.9.5
c3c2c28
c3c2c28
--
c3c2c28
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
c3c2c28
the body of a message to majordomo@vger.kernel.org
c3c2c28
More majordomo info at  http://vger.kernel.org/majordomo-info.html