From: Greg Kroah-Hartman Date: Tue, 23 May 2017 18:36:15 +0000 (+0200) Subject: 3.18-stable patches X-Git-Tag: v3.18.55~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=45daa3a2f529eed6983fcd18ab94178534b4f155;p=thirdparty%2Fkernel%2Fstable-queue.git 3.18-stable patches added patches: drivers-char-mem-check-for-address-space-wraparound-with-mmap.patch nfsd-check-for-oversized-nfsv2-v3-arguments.patch --- 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 index 00000000000..8935d6b6297 --- /dev/null +++ b/queue-3.18/drivers-char-mem-check-for-address-space-wraparound-with-mmap.patch @@ -0,0 +1,40 @@ +From b299cde245b0b76c977f4291162cf668e087b408 Mon Sep 17 00:00:00 2001 +From: Julius Werner +Date: Fri, 12 May 2017 14:42:58 -0700 +Subject: drivers: char: mem: Check for address space wraparound with mmap() + +From: Julius Werner + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..338e52b1650 --- /dev/null +++ b/queue-3.18/nfsd-check-for-oversized-nfsv2-v3-arguments.patch @@ -0,0 +1,176 @@ +From 51f567777799c9d85a778302b9eb61cf15214a98 Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" +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 + +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ää +Reported-by: Ari Kauppi +Signed-off-by: J. Bruce Fields +Signed-off-by: Greg Kroah-Hartman + +--- + 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 diff --git a/queue-3.18/series b/queue-3.18/series index 262b56595a7..0d7edce63d4 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -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