Additional fixes for CVE-2011-4131 (rhbz 822874 822869)
This commit is contained in:
parent
5a13292239
commit
d1a2aa668f
12
kernel.spec
12
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
|
||||
|
@ -727,6 +727,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
|
||||
|
||||
Patch12016: disable-i8042-check-on-apple-mac.patch
|
||||
|
@ -1343,6 +1347,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
|
||||
|
@ -2235,6 +2242,9 @@ fi
|
|||
# and build.
|
||||
|
||||
%changelog
|
||||
* Fri May 18 2012 Josh Boyer <jwboyer@redhat.com>
|
||||
- Additional fixes for CVE-2011-4131 (rhbz 822874 822869)
|
||||
|
||||
* Thu May 17 2012 Josh Boyer <jwboyer@redhat.com>
|
||||
- Fix rtlwifi async firmware load race condition (rhbz 822120)
|
||||
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
From 5794d21ef4639f0e33440927bb903f9598c21e92 Mon Sep 17 00:00:00 2001
|
||||
From: Sachin Prabhu <sprabhu@redhat.com>
|
||||
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 <sprabhu@redhat.com>
|
||||
Reported-by: Jian Li <jiali@redhat.com>
|
||||
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
|
||||
---
|
||||
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
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
From 5a00689930ab975fdd1b37b034475017e460cf2a Mon Sep 17 00:00:00 2001
|
||||
From: Sachin Prabhu <sprabhu@redhat.com>
|
||||
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 <sprabhu@redhat.com>
|
||||
Reported-by: Jian Li <jiali@redhat.com>
|
||||
[Trond: Fixed a size_t vs unsigned int printk() warning]
|
||||
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
|
||||
---
|
||||
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
|
||||
|
Loading…
Reference in New Issue