]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 23 May 2017 18:36:15 +0000 (20:36 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 23 May 2017 18:36:15 +0000 (20:36 +0200)
added patches:
drivers-char-mem-check-for-address-space-wraparound-with-mmap.patch
nfsd-check-for-oversized-nfsv2-v3-arguments.patch

queue-3.18/drivers-char-mem-check-for-address-space-wraparound-with-mmap.patch [new file with mode: 0644]
queue-3.18/nfsd-check-for-oversized-nfsv2-v3-arguments.patch [new file with mode: 0644]
queue-3.18/series

diff --git a/queue-3.18/drivers-char-mem-check-for-address-space-wraparound-with-mmap.patch b/queue-3.18/drivers-char-mem-check-for-address-space-wraparound-with-mmap.patch
new file mode 100644 (file)
index 0000000..8935d6b
--- /dev/null
@@ -0,0 +1,40 @@
+From b299cde245b0b76c977f4291162cf668e087b408 Mon Sep 17 00:00:00 2001
+From: Julius Werner <jwerner@chromium.org>
+Date: Fri, 12 May 2017 14:42:58 -0700
+Subject: drivers: char: mem: Check for address space wraparound with mmap()
+
+From: Julius Werner <jwerner@chromium.org>
+
+commit b299cde245b0b76c977f4291162cf668e087b408 upstream.
+
+/dev/mem currently allows mmap() mappings that wrap around the end of
+the physical address space, which should probably be illegal. It
+circumvents the existing STRICT_DEVMEM permission check because the loop
+immediately terminates (as the start address is already higher than the
+end address). On the x86_64 architecture it will then cause a panic
+(from the BUG(start >= end) in arch/x86/mm/pat.c:reserve_memtype()).
+
+This patch adds an explicit check to make sure offset + size will not
+wrap around in the physical address type.
+
+Signed-off-by: Julius Werner <jwerner@chromium.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/mem.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/char/mem.c
++++ b/drivers/char/mem.c
+@@ -329,6 +329,11 @@ static const struct vm_operations_struct
+ static int mmap_mem(struct file *file, struct vm_area_struct *vma)
+ {
+       size_t size = vma->vm_end - vma->vm_start;
++      phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT;
++
++      /* It's illegal to wrap around the end of the physical address space. */
++      if (offset + (phys_addr_t)size < offset)
++              return -EINVAL;
+       if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
+               return -EINVAL;
diff --git a/queue-3.18/nfsd-check-for-oversized-nfsv2-v3-arguments.patch b/queue-3.18/nfsd-check-for-oversized-nfsv2-v3-arguments.patch
new file mode 100644 (file)
index 0000000..338e52b
--- /dev/null
@@ -0,0 +1,176 @@
+From 51f567777799c9d85a778302b9eb61cf15214a98 Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Thu, 6 Apr 2017 22:36:31 -0400
+Subject: nfsd: check for oversized NFSv2/v3 arguments
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: J. Bruce Fields <bfields@redhat.com>
+
+commit 51f567777799c9d85a778302b9eb61cf15214a98 upstream.
+
+A client can append random data to the end of an NFSv2 or NFSv3 RPC call
+without our complaining; we'll just stop parsing at the end of the
+expected data and ignore the rest.
+
+Encoded arguments and replies are stored together in an array of pages,
+and if a call is too large it could leave inadequate space for the
+reply.  This is normally OK because NFS RPC's typically have either
+short arguments and long replies (like READ) or long arguments and short
+replies (like WRITE).  But a client that sends an incorrectly long reply
+can violate those assumptions.  This was observed to cause crashes.
+
+So, insist that the argument not be any longer than we expect.
+
+Also, several operations increment rq_next_page in the decode routine
+before checking the argument size, which can leave rq_next_page pointing
+well past the end of the page array, causing trouble later in
+svc_free_pages.
+
+As followup we may also want to rewrite the encoding routines to check
+more carefully that they aren't running off the end of the page array.
+
+Reported-by: Tuomas Haanpää <thaan@synopsys.com>
+Reported-by: Ari Kauppi <ari@synopsys.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfsd/nfs3xdr.c          |   23 +++++++++++++++++------
+ fs/nfsd/nfsxdr.c           |   13 ++++++++++---
+ include/linux/sunrpc/svc.h |    3 +--
+ 3 files changed, 28 insertions(+), 11 deletions(-)
+
+--- a/fs/nfsd/nfs3xdr.c
++++ b/fs/nfsd/nfs3xdr.c
+@@ -334,8 +334,11 @@ nfs3svc_decode_readargs(struct svc_rqst
+       if (!p)
+               return 0;
+       p = xdr_decode_hyper(p, &args->offset);
+-
+       args->count = ntohl(*p++);
++
++      if (!xdr_argsize_check(rqstp, p))
++              return 0;
++
+       len = min(args->count, max_blocksize);
+       /* set up the kvec */
+@@ -349,7 +352,7 @@ nfs3svc_decode_readargs(struct svc_rqst
+               v++;
+       }
+       args->vlen = v;
+-      return xdr_argsize_check(rqstp, p);
++      return 1;
+ }
+ int
+@@ -536,9 +539,11 @@ nfs3svc_decode_readlinkargs(struct svc_r
+       p = decode_fh(p, &args->fh);
+       if (!p)
+               return 0;
++      if (!xdr_argsize_check(rqstp, p))
++              return 0;
+       args->buffer = page_address(*(rqstp->rq_next_page++));
+-      return xdr_argsize_check(rqstp, p);
++      return 1;
+ }
+ int
+@@ -564,10 +569,14 @@ nfs3svc_decode_readdirargs(struct svc_rq
+       args->verf   = p; p += 2;
+       args->dircount = ~0;
+       args->count  = ntohl(*p++);
++
++      if (!xdr_argsize_check(rqstp, p))
++              return 0;
++
+       args->count  = min_t(u32, args->count, PAGE_SIZE);
+       args->buffer = page_address(*(rqstp->rq_next_page++));
+-      return xdr_argsize_check(rqstp, p);
++      return 1;
+ }
+ int
+@@ -585,6 +594,9 @@ nfs3svc_decode_readdirplusargs(struct sv
+       args->dircount = ntohl(*p++);
+       args->count    = ntohl(*p++);
++      if (!xdr_argsize_check(rqstp, p))
++              return 0;
++
+       len = args->count = min(args->count, max_blocksize);
+       while (len > 0) {
+               struct page *p = *(rqstp->rq_next_page++);
+@@ -592,8 +604,7 @@ nfs3svc_decode_readdirplusargs(struct sv
+                       args->buffer = page_address(p);
+               len -= PAGE_SIZE;
+       }
+-
+-      return xdr_argsize_check(rqstp, p);
++      return 1;
+ }
+ int
+--- a/fs/nfsd/nfsxdr.c
++++ b/fs/nfsd/nfsxdr.c
+@@ -257,6 +257,9 @@ nfssvc_decode_readargs(struct svc_rqst *
+       len = args->count     = ntohl(*p++);
+       p++; /* totalcount - unused */
++      if (!xdr_argsize_check(rqstp, p))
++              return 0;
++
+       len = min_t(unsigned int, len, NFSSVC_MAXBLKSIZE_V2);
+       /* set up somewhere to store response.
+@@ -272,7 +275,7 @@ nfssvc_decode_readargs(struct svc_rqst *
+               v++;
+       }
+       args->vlen = v;
+-      return xdr_argsize_check(rqstp, p);
++      return 1;
+ }
+ int
+@@ -360,9 +363,11 @@ nfssvc_decode_readlinkargs(struct svc_rq
+       p = decode_fh(p, &args->fh);
+       if (!p)
+               return 0;
++      if (!xdr_argsize_check(rqstp, p))
++              return 0;
+       args->buffer = page_address(*(rqstp->rq_next_page++));
+-      return xdr_argsize_check(rqstp, p);
++      return 1;
+ }
+ int
+@@ -400,9 +405,11 @@ nfssvc_decode_readdirargs(struct svc_rqs
+       args->cookie = ntohl(*p++);
+       args->count  = ntohl(*p++);
+       args->count  = min_t(u32, args->count, PAGE_SIZE);
++      if (!xdr_argsize_check(rqstp, p))
++              return 0;
+       args->buffer = page_address(*(rqstp->rq_next_page++));
+-      return xdr_argsize_check(rqstp, p);
++      return 1;
+ }
+ /*
+--- a/include/linux/sunrpc/svc.h
++++ b/include/linux/sunrpc/svc.h
+@@ -326,8 +326,7 @@ xdr_argsize_check(struct svc_rqst *rqstp
+ {
+       char *cp = (char *)p;
+       struct kvec *vec = &rqstp->rq_arg.head[0];
+-      return cp >= (char*)vec->iov_base
+-              && cp <= (char*)vec->iov_base + vec->iov_len;
++      return cp == (char *)vec->iov_base + vec->iov_len;
+ }
+ static inline int
index 262b56595a767cbeb53bea41b6ac6d2196def9af..0d7edce63d4b12d373938fc4d8479b384499ae4c 100644 (file)
@@ -55,3 +55,5 @@ osf_wait4-fix-infoleak.patch
 tracing-kprobes-enforce-kprobes-teardown-after-testing.patch
 pci-fix-pci_mmap_fits-for-have_pci_resource_to_user-platforms.patch
 pci-freeze-pme-scan-before-suspending-devices.patch
+nfsd-check-for-oversized-nfsv2-v3-arguments.patch
+drivers-char-mem-check-for-address-space-wraparound-with-mmap.patch