Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9dfd87da authored by J. Bruce Fields's avatar J. Bruce Fields
Browse files

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: default avatarSimo Sorce <simo@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 6a36978e
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -213,6 +213,30 @@ static int gssp_call(struct net *net, struct rpc_message *msg)
	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(struct net *net,
		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;
+3 −0
Original line number Diff line number Diff line
@@ -780,6 +780,9 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
	/* 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);
+4 −1
Original line number Diff line number Diff line
@@ -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 rpc_rqst *rqstp,
			     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 + \