Skip to content

Commit

Permalink
Avoid beyond bounds copy while caching ACL
Browse files Browse the repository at this point in the history
When attempting to cache ACLs returned from the server, if the bitmap
size + the ACL size is greater than a PAGE_SIZE but the ACL size itself
is smaller than a PAGE_SIZE, we can read past the buffer page boundary.

Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
Reported-by: Jian Li <jiali@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Sachin Prabhu authored and Trond Myklebust committed Apr 27, 2012
1 parent 5a00689 commit 5794d21
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 8 deletions.
12 changes: 5 additions & 7 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3628,16 +3628,16 @@ static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_
return ret;
}

static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len)
static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len)
{
struct nfs4_cached_acl *acl;

if (buf && acl_len <= PAGE_SIZE) {
if (pages && acl_len <= PAGE_SIZE) {
acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL);
if (acl == NULL)
goto out;
acl->cached = 1;
memcpy(acl->data, buf, acl_len);
_copy_from_pages(acl->data, pages, pgbase, acl_len);
} else {
acl = kmalloc(sizeof(*acl), GFP_KERNEL);
if (acl == NULL)
Expand Down Expand Up @@ -3670,7 +3670,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
struct nfs_getaclres res = {
.acl_len = buflen,
};
void *resp_buf;
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL],
.rpc_argp = &args,
Expand Down Expand Up @@ -3705,7 +3704,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
* the page we send as a guess */
if (buf == NULL)
res.acl_flags |= NFS4_ACL_LEN_REQUEST;
resp_buf = page_address(pages[0]);

dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n",
__func__, buf, buflen, npages, args.acl_len);
Expand All @@ -3716,9 +3714,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu

acl_len = res.acl_len - res.acl_data_offset;
if (acl_len > args.acl_len)
nfs4_write_cached_acl(inode, NULL, acl_len);
nfs4_write_cached_acl(inode, NULL, 0, acl_len);
else
nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset,
nfs4_write_cached_acl(inode, pages, res.acl_data_offset,
acl_len);
if (buf) {
ret = -ERANGE;
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/nfs4xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -4940,7 +4940,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
res->acl_len = attrlen;
goto out;
}
dprintk("NFS: acl reply: attrlen %zu > page_len %u\n",
dprintk("NFS: acl reply: attrlen %u > page_len %zu\n",
attrlen, page_len);
return -EINVAL;
}
Expand Down

0 comments on commit 5794d21

Please sign in to comment.