diff --git a/kernel.spec b/kernel.spec index 3d1398a30..9f2d1f3e3 100644 --- a/kernel.spec +++ b/kernel.spec @@ -54,7 +54,7 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 4 +%global baserelease 5 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -717,6 +717,10 @@ Patch4113: NFS-optimise-away-unnecessary-setattrs-for-open-O_TRUNC.patch Patch4114: NFSv4-fix-open-O_TRUNC-and-ftruncate-error-handling.patch Patch4115: NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch +#rhbz 822874 +Patch4116: nfs-Avoid-reading-past-buffer-when-calling-GETACL.patch +Patch4117: nfs-Avoid-beyond-bounds-copy-while-caching-ACL.patch + # patches headed upstream Patch10000: fs-proc-devtree-remove_proc_entry.patch @@ -1398,6 +1402,9 @@ ApplyPatch NFS-optimise-away-unnecessary-setattrs-for-open-O_TRUNC.patch ApplyPatch NFSv4-fix-open-O_TRUNC-and-ftruncate-error-handling.patch ApplyPatch NFSv4-Rate-limit-the-state-manager-for-lock-reclaim-.patch +ApplyPatch nfs-Avoid-reading-past-buffer-when-calling-GETACL.patch +ApplyPatch nfs-Avoid-beyond-bounds-copy-while-caching-ACL.patch + # USB # WMI @@ -2429,6 +2436,9 @@ fi # '-' | | # '-' %changelog +* Fri May 18 2012 Josh Boyer +- Additional fixes for CVE-2011-4131 (rhbz 822874 822869) + * Thu May 17 2012 Josh Boyer - Fix rtlwifi async firmware load race condition (rhbz 822120) - Enable cpu_idle drivers for ppc64/pseries (requested by Ben Herrenschmidt) diff --git a/nfs-Avoid-beyond-bounds-copy-while-caching-ACL.patch b/nfs-Avoid-beyond-bounds-copy-while-caching-ACL.patch new file mode 100644 index 000000000..2798b0d1d --- /dev/null +++ b/nfs-Avoid-beyond-bounds-copy-while-caching-ACL.patch @@ -0,0 +1,85 @@ +From 5794d21ef4639f0e33440927bb903f9598c21e92 Mon Sep 17 00:00:00 2001 +From: Sachin Prabhu +Date: Tue, 17 Apr 2012 14:36:40 +0100 +Subject: [PATCH] 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 +Reported-by: Jian Li +Signed-off-by: Trond Myklebust +--- + fs/nfs/nfs4proc.c | 12 +++++------- + 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 f5f125f..2ce0698 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -3628,16 +3628,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) +@@ -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, +@@ -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); +@@ -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; +diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c +index 9312dd7..203c096 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, + 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; + } +-- +1.7.7.6 + diff --git a/nfs-Avoid-reading-past-buffer-when-calling-GETACL.patch b/nfs-Avoid-reading-past-buffer-when-calling-GETACL.patch new file mode 100644 index 000000000..7122e3b9a --- /dev/null +++ b/nfs-Avoid-reading-past-buffer-when-calling-GETACL.patch @@ -0,0 +1,120 @@ +From 5a00689930ab975fdd1b37b034475017e460cf2a Mon Sep 17 00:00:00 2001 +From: Sachin Prabhu +Date: Tue, 17 Apr 2012 14:35:39 +0100 +Subject: [PATCH] Avoid reading past buffer when calling GETACL + +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 +--- + fs/nfs/nfs4proc.c | 16 ++++++++++------ + fs/nfs/nfs4xdr.c | 18 +++++++++++------- + 2 files changed, 21 insertions(+), 13 deletions(-) + +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index 60d5f4c..f5f125f 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -3684,19 +3684,23 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu + 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) +diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c +index 77fc5f9..9312dd7 100644 +--- a/fs/nfs/nfs4xdr.c ++++ b/fs/nfs/nfs4xdr.c +@@ -4902,11 +4902,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, + 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) +@@ -4916,28 +4924,24 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, + 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 %zu > page_len %u\n", ++ attrlen, page_len); + return -EINVAL; + } + xdr_read_pages(xdr, attrlen); +-- +1.7.7.6 +