diff options
author | Sachin Prabhu <sprabhu@redhat.com> | 2012-04-17 09:36:40 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-04-27 14:09:53 -0400 |
commit | 5794d21ef4639f0e33440927bb903f9598c21e92 (patch) | |
tree | d4bdbde63624df6e970751f46fd6fe0dacb8718c /fs/nfs | |
parent | 5a00689930ab975fdd1b37b034475017e460cf2a (diff) |
Avoid beyond bounds copy while caching ACL
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>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 12 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 2 |
2 files changed, 6 insertions, 8 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f5f125fdae1b..2ce069880d6b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -3628,16 +3628,16 @@ out: | |||
3628 | return ret; | 3628 | return ret; |
3629 | } | 3629 | } |
3630 | 3630 | ||
3631 | static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len) | 3631 | static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len) |
3632 | { | 3632 | { |
3633 | struct nfs4_cached_acl *acl; | 3633 | struct nfs4_cached_acl *acl; |
3634 | 3634 | ||
3635 | if (buf && acl_len <= PAGE_SIZE) { | 3635 | if (pages && acl_len <= PAGE_SIZE) { |
3636 | acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); | 3636 | acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); |
3637 | if (acl == NULL) | 3637 | if (acl == NULL) |
3638 | goto out; | 3638 | goto out; |
3639 | acl->cached = 1; | 3639 | acl->cached = 1; |
3640 | memcpy(acl->data, buf, acl_len); | 3640 | _copy_from_pages(acl->data, pages, pgbase, acl_len); |
3641 | } else { | 3641 | } else { |
3642 | acl = kmalloc(sizeof(*acl), GFP_KERNEL); | 3642 | acl = kmalloc(sizeof(*acl), GFP_KERNEL); |
3643 | if (acl == NULL) | 3643 | if (acl == NULL) |
@@ -3670,7 +3670,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3670 | struct nfs_getaclres res = { | 3670 | struct nfs_getaclres res = { |
3671 | .acl_len = buflen, | 3671 | .acl_len = buflen, |
3672 | }; | 3672 | }; |
3673 | void *resp_buf; | ||
3674 | struct rpc_message msg = { | 3673 | struct rpc_message msg = { |
3675 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | 3674 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], |
3676 | .rpc_argp = &args, | 3675 | .rpc_argp = &args, |
@@ -3705,7 +3704,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3705 | * the page we send as a guess */ | 3704 | * the page we send as a guess */ |
3706 | if (buf == NULL) | 3705 | if (buf == NULL) |
3707 | res.acl_flags |= NFS4_ACL_LEN_REQUEST; | 3706 | res.acl_flags |= NFS4_ACL_LEN_REQUEST; |
3708 | resp_buf = page_address(pages[0]); | ||
3709 | 3707 | ||
3710 | dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", | 3708 | dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", |
3711 | __func__, buf, buflen, npages, args.acl_len); | 3709 | __func__, buf, buflen, npages, args.acl_len); |
@@ -3716,9 +3714,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3716 | 3714 | ||
3717 | acl_len = res.acl_len - res.acl_data_offset; | 3715 | acl_len = res.acl_len - res.acl_data_offset; |
3718 | if (acl_len > args.acl_len) | 3716 | if (acl_len > args.acl_len) |
3719 | nfs4_write_cached_acl(inode, NULL, acl_len); | 3717 | nfs4_write_cached_acl(inode, NULL, 0, acl_len); |
3720 | else | 3718 | else |
3721 | nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset, | 3719 | nfs4_write_cached_acl(inode, pages, res.acl_data_offset, |
3722 | acl_len); | 3720 | acl_len); |
3723 | if (buf) { | 3721 | if (buf) { |
3724 | ret = -ERANGE; | 3722 | ret = -ERANGE; |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 9312dd78d349..203c0967451b 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -4940,7 +4940,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
4940 | res->acl_len = attrlen; | 4940 | res->acl_len = attrlen; |
4941 | goto out; | 4941 | goto out; |
4942 | } | 4942 | } |
4943 | dprintk("NFS: acl reply: attrlen %zu > page_len %u\n", | 4943 | dprintk("NFS: acl reply: attrlen %u > page_len %zu\n", |
4944 | attrlen, page_len); | 4944 | attrlen, page_len); |
4945 | return -EINVAL; | 4945 | return -EINVAL; |
4946 | } | 4946 | } |