From 22a93b390bf04b020f4dd5296efb2e8aa89246a8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 18 May 2012 13:17:36 -0700 Subject: [PATCH] 3.3-stable patches added patches: avoid-beyond-bounds-copy-while-caching-acl.patch avoid-reading-past-buffer-when-calling-getacl.patch --- ...beyond-bounds-copy-while-caching-acl.patch | 72 +++++++++++ ...ding-past-buffer-when-calling-getacl.patch | 119 ++++++++++++++++++ queue-3.3/series | 2 + 3 files changed, 193 insertions(+) create mode 100644 queue-3.3/avoid-beyond-bounds-copy-while-caching-acl.patch create mode 100644 queue-3.3/avoid-reading-past-buffer-when-calling-getacl.patch diff --git a/queue-3.3/avoid-beyond-bounds-copy-while-caching-acl.patch b/queue-3.3/avoid-beyond-bounds-copy-while-caching-acl.patch new file mode 100644 index 00000000000..6cbbff5b607 --- /dev/null +++ b/queue-3.3/avoid-beyond-bounds-copy-while-caching-acl.patch @@ -0,0 +1,72 @@ +From 5794d21ef4639f0e33440927bb903f9598c21e92 Mon Sep 17 00:00:00 2001 +From: Sachin Prabhu +Date: Tue, 17 Apr 2012 14:36:40 +0100 +Subject: Avoid beyond bounds copy while caching ACL + +From: Sachin Prabhu + +commit 5794d21ef4639f0e33440927bb903f9598c21e92 upstream. + +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 +Reported-by: Jian Li +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -3532,16 +3532,16 @@ out: + 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) +@@ -3574,7 +3574,6 @@ static ssize_t __nfs4_get_acl_uncached(s + struct nfs_getaclres res = { + .acl_len = buflen, + }; +- void *resp_buf; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], + .rpc_argp = &args, +@@ -3605,7 +3604,6 @@ static ssize_t __nfs4_get_acl_uncached(s + * 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); +@@ -3616,9 +3614,9 @@ static ssize_t __nfs4_get_acl_uncached(s + + 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; diff --git a/queue-3.3/avoid-reading-past-buffer-when-calling-getacl.patch b/queue-3.3/avoid-reading-past-buffer-when-calling-getacl.patch new file mode 100644 index 00000000000..4c290e85f79 --- /dev/null +++ b/queue-3.3/avoid-reading-past-buffer-when-calling-getacl.patch @@ -0,0 +1,119 @@ +From 5a00689930ab975fdd1b37b034475017e460cf2a Mon Sep 17 00:00:00 2001 +From: Sachin Prabhu +Date: Tue, 17 Apr 2012 14:35:39 +0100 +Subject: Avoid reading past buffer when calling GETACL + +From: Sachin Prabhu + +commit 5a00689930ab975fdd1b37b034475017e460cf2a upstream. + +Bug noticed in commit +bf118a342f10dafe44b14451a1392c3254629a1f + +When calling GETACL, if the size of the bitmap array, the length +attribute and the acl returned by the server is greater than the +allocated buffer(args.acl_len), we can Oops with a General Protection +fault at _copy_from_pages() when we attempt to read past the pages +allocated. + +This patch allocates an extra PAGE for the bitmap and checks to see that +the bitmap + attribute_length + ACLs don't exceed the buffer space +allocated to it. + +Signed-off-by: Sachin Prabhu +Reported-by: Jian Li +[Trond: Fixed a size_t vs unsigned int printk() warning] +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 16 ++++++++++------ + fs/nfs/nfs4xdr.c | 18 +++++++++++------- + 2 files changed, 21 insertions(+), 13 deletions(-) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -3587,19 +3587,23 @@ static ssize_t __nfs4_get_acl_uncached(s + if (npages == 0) + npages = 1; + ++ /* Add an extra page to handle the bitmap returned */ ++ npages++; ++ + for (i = 0; i < npages; i++) { + pages[i] = alloc_page(GFP_KERNEL); + if (!pages[i]) + goto out_free; + } +- if (npages > 1) { +- /* for decoding across pages */ +- res.acl_scratch = alloc_page(GFP_KERNEL); +- if (!res.acl_scratch) +- goto out_free; +- } ++ ++ /* for decoding across pages */ ++ res.acl_scratch = alloc_page(GFP_KERNEL); ++ if (!res.acl_scratch) ++ goto out_free; ++ + args.acl_len = npages * PAGE_SIZE; + args.acl_pgbase = 0; ++ + /* Let decode_getfacl know not to fail if the ACL data is larger than + * the page we send as a guess */ + if (buf == NULL) +--- a/fs/nfs/nfs4xdr.c ++++ b/fs/nfs/nfs4xdr.c +@@ -4975,11 +4975,19 @@ static int decode_getacl(struct xdr_stre + bitmap[3] = {0}; + struct kvec *iov = req->rq_rcv_buf.head; + int status; ++ size_t page_len = xdr->buf->page_len; + + res->acl_len = 0; + if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) + goto out; ++ + bm_p = xdr->p; ++ res->acl_data_offset = be32_to_cpup(bm_p) + 2; ++ res->acl_data_offset <<= 2; ++ /* Check if the acl data starts beyond the allocated buffer */ ++ if (res->acl_data_offset > page_len) ++ return -ERANGE; ++ + if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) + goto out; + if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) +@@ -4989,28 +4997,24 @@ static int decode_getacl(struct xdr_stre + return -EIO; + if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { + size_t hdrlen; +- u32 recvd; + + /* The bitmap (xdr len + bitmaps) and the attr xdr len words + * are stored with the acl data to handle the problem of + * variable length bitmaps.*/ + xdr->p = bm_p; +- res->acl_data_offset = be32_to_cpup(bm_p) + 2; +- res->acl_data_offset <<= 2; + + /* We ignore &savep and don't do consistency checks on + * the attr length. Let userspace figure it out.... */ + hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; + attrlen += res->acl_data_offset; +- recvd = req->rq_rcv_buf.len - hdrlen; +- if (attrlen > recvd) { ++ if (attrlen > page_len) { + if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { + /* getxattr interface called with a NULL buf */ + res->acl_len = attrlen; + goto out; + } +- dprintk("NFS: acl reply: attrlen %u > recvd %u\n", +- attrlen, recvd); ++ dprintk("NFS: acl reply: attrlen %u > page_len %zu\n", ++ attrlen, page_len); + return -EINVAL; + } + xdr_read_pages(xdr, attrlen); diff --git a/queue-3.3/series b/queue-3.3/series index 061b6a281dd..5c1a2afee20 100644 --- a/queue-3.3/series +++ b/queue-3.3/series @@ -43,3 +43,5 @@ spi-topcliff-pch-modify-pci-bus-number-dynamically-to-get-dma-device-info.patch spi-topcliff-pch-fix-issue-for-transmitting-over-4kbyte.patch spi-topcliff-pch-supports-a-spi-mode-setup-and-bit-order-setup-by-io-control.patch spi-topcliff-pch-add-recovery-processing-in-case-wait-event-timeout.patch +avoid-beyond-bounds-copy-while-caching-acl.patch +avoid-reading-past-buffer-when-calling-getacl.patch -- 2.47.3