diff options
author | J. Bruce Fields <bfields@redhat.com> | 2013-08-20 18:13:27 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2013-09-06 11:45:58 -0400 |
commit | 9dfd87da1aeb0fd364167ad199f40fe96a6a87be (patch) | |
tree | adf9d2edff56be3fa54e330b55b3c76fe51c25cf /net/sunrpc | |
parent | 6a36978e6931e6601be586eb313375335f2cfaa3 (diff) |
rpc: fix huge kmalloc's in gss-proxy
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>
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/auth_gss/gss_rpc_upcall.c | 30 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_rpc_xdr.c | 3 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_rpc_xdr.h | 5 |
3 files changed, 37 insertions, 1 deletions
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c index af7ffd447fee..be95af3d1058 100644 --- 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, struct rpc_message *msg) | |||
213 | return status; | 213 | return status; |
214 | } | 214 | } |
215 | 215 | ||
216 | static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg) | ||
217 | { | ||
218 | int i; | ||
219 | |||
220 | for (i = 0; i < arg->npages && arg->pages[i]; i++) | ||
221 | __free_page(arg->pages[i]); | ||
222 | } | ||
223 | |||
224 | static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg) | ||
225 | { | ||
226 | int i; | ||
227 | |||
228 | arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE); | ||
229 | arg->pages = kzalloc(arg->npages * sizeof(struct page *), GFP_KERNEL); | ||
230 | |||
231 | for (i=0; i < arg->npages; i++) { | ||
232 | arg->pages[i] = alloc_page(GFP_KERNEL); | ||
233 | if (arg->pages[i] == NULL) { | ||
234 | gssp_free_receive_pages(arg); | ||
235 | return -ENOMEM; | ||
236 | } | ||
237 | } | ||
238 | return 0; | ||
239 | } | ||
216 | 240 | ||
217 | /* | 241 | /* |
218 | * Public functions | 242 | * Public functions |
@@ -261,10 +285,16 @@ int gssp_accept_sec_context_upcall(struct net *net, | |||
261 | arg.context_handle = &ctxh; | 285 | arg.context_handle = &ctxh; |
262 | res.output_token->len = GSSX_max_output_token_sz; | 286 | res.output_token->len = GSSX_max_output_token_sz; |
263 | 287 | ||
288 | ret = gssp_alloc_receive_pages(&arg); | ||
289 | if (ret) | ||
290 | return ret; | ||
291 | |||
264 | /* use nfs/ for targ_name ? */ | 292 | /* use nfs/ for targ_name ? */ |
265 | 293 | ||
266 | ret = gssp_call(net, &msg); | 294 | ret = gssp_call(net, &msg); |
267 | 295 | ||
296 | gssp_free_receive_pages(&arg); | ||
297 | |||
268 | /* we need to fetch all data even in case of error so | 298 | /* we need to fetch all data even in case of error so |
269 | * that we can free special strctures is they have been allocated */ | 299 | * that we can free special strctures is they have been allocated */ |
270 | data->major_status = res.status.major_status; | 300 | data->major_status = res.status.major_status; |
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c index 3c19c7d48899..f0f78c5f1c7d 100644 --- 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 rpc_rqst *req, | |||
780 | /* arg->options */ | 780 | /* arg->options */ |
781 | err = dummy_enc_opt_array(xdr, &arg->options); | 781 | err = dummy_enc_opt_array(xdr, &arg->options); |
782 | 782 | ||
783 | xdr_inline_pages(&req->rq_rcv_buf, | ||
784 | PAGE_SIZE/2 /* pretty arbitrary */, | ||
785 | arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE); | ||
783 | done: | 786 | done: |
784 | if (err) | 787 | if (err) |
785 | dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); | 788 | dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); |
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.h b/net/sunrpc/auth_gss/gss_rpc_xdr.h index 1c98b27d870c..685a688f3d8a 100644 --- 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 { | |||
147 | struct gssx_cb *input_cb; | 147 | struct gssx_cb *input_cb; |
148 | u32 ret_deleg_cred; | 148 | u32 ret_deleg_cred; |
149 | struct gssx_option_array options; | 149 | struct gssx_option_array options; |
150 | struct page **pages; | ||
151 | unsigned int npages; | ||
150 | }; | 152 | }; |
151 | 153 | ||
152 | struct gssx_res_accept_sec_context { | 154 | struct gssx_res_accept_sec_context { |
@@ -240,7 +242,8 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, | |||
240 | 2 * GSSX_max_princ_sz + \ | 242 | 2 * GSSX_max_princ_sz + \ |
241 | 8 + 8 + 4 + 4 + 4) | 243 | 8 + 8 + 4 + 4 + 4) |
242 | #define GSSX_max_output_token_sz 1024 | 244 | #define GSSX_max_output_token_sz 1024 |
243 | #define GSSX_max_creds_sz (4 + 4 + 4 + NGROUPS_MAX * 4) | 245 | /* grouplist not included; we allocate separate pages for that: */ |
246 | #define GSSX_max_creds_sz (4 + 4 + 4 /* + NGROUPS_MAX*4 */) | ||
244 | #define GSSX_RES_accept_sec_context_sz (GSSX_default_status_sz + \ | 247 | #define GSSX_RES_accept_sec_context_sz (GSSX_default_status_sz + \ |
245 | GSSX_default_ctx_sz + \ | 248 | GSSX_default_ctx_sz + \ |
246 | GSSX_max_output_token_sz + \ | 249 | GSSX_max_output_token_sz + \ |