Commit 331818f1 authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Fix an Oops in the NFSv4 getacl code

Commit bf118a34 (NFSv4: include bitmap
in nfsv4 get acl data) introduces the 'acl_scratch' page for the case
where we may need to decode multi-page data. However it fails to take
into account the fact that the variable may be NULL (for the case where
we're not doing multi-page decode), and it also attaches it to the
encoding xdr_stream rather than the decoding one.

The immediate result is an Oops in nfs4_xdr_enc_getacl due to the
call to page_address() with a NULL page pointer.
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
Cc: Andy Adamson <andros@netapp.com>
Cc: stable@vger.kernel.org
parent 7c7ed8ec
...@@ -3575,8 +3575,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu ...@@ -3575,8 +3575,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
} }
if (npages > 1) { if (npages > 1) {
/* for decoding across pages */ /* for decoding across pages */
args.acl_scratch = alloc_page(GFP_KERNEL); res.acl_scratch = alloc_page(GFP_KERNEL);
if (!args.acl_scratch) if (!res.acl_scratch)
goto out_free; goto out_free;
} }
args.acl_len = npages * PAGE_SIZE; args.acl_len = npages * PAGE_SIZE;
...@@ -3612,8 +3612,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu ...@@ -3612,8 +3612,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
for (i = 0; i < npages; i++) for (i = 0; i < npages; i++)
if (pages[i]) if (pages[i])
__free_page(pages[i]); __free_page(pages[i]);
if (args.acl_scratch) if (res.acl_scratch)
__free_page(args.acl_scratch); __free_page(res.acl_scratch);
return ret; return ret;
} }
......
...@@ -2522,7 +2522,6 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -2522,7 +2522,6 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
xdr_inline_pages(&req->rq_rcv_buf, replen << 2, xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
args->acl_pages, args->acl_pgbase, args->acl_len); args->acl_pages, args->acl_pgbase, args->acl_len);
xdr_set_scratch_buffer(xdr, page_address(args->acl_scratch), PAGE_SIZE);
encode_nops(&hdr); encode_nops(&hdr);
} }
...@@ -6032,6 +6031,10 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr, ...@@ -6032,6 +6031,10 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
struct compound_hdr hdr; struct compound_hdr hdr;
int status; int status;
if (res->acl_scratch != NULL) {
void *p = page_address(res->acl_scratch);
xdr_set_scratch_buffer(xdr, p, PAGE_SIZE);
}
status = decode_compound_hdr(xdr, &hdr); status = decode_compound_hdr(xdr, &hdr);
if (status) if (status)
goto out; goto out;
......
...@@ -614,7 +614,6 @@ struct nfs_getaclargs { ...@@ -614,7 +614,6 @@ struct nfs_getaclargs {
size_t acl_len; size_t acl_len;
unsigned int acl_pgbase; unsigned int acl_pgbase;
struct page ** acl_pages; struct page ** acl_pages;
struct page * acl_scratch;
struct nfs4_sequence_args seq_args; struct nfs4_sequence_args seq_args;
}; };
...@@ -624,6 +623,7 @@ struct nfs_getaclres { ...@@ -624,6 +623,7 @@ struct nfs_getaclres {
size_t acl_len; size_t acl_len;
size_t acl_data_offset; size_t acl_data_offset;
int acl_flags; int acl_flags;
struct page * acl_scratch;
struct nfs4_sequence_res seq_res; struct nfs4_sequence_res seq_res;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment