DivestOS/Patches/Linux_CVEs/CVE-2016-0774/1.patch

61 lines
2.1 KiB
Diff

From 4bb62b96dc3d2ef4943d3b78b9db160f545a631f Mon Sep 17 00:00:00 2001
From: Jeff Vander Stoep <jeffv@google.com>
Date: Wed, 23 Mar 2016 15:32:14 -0700
Subject: [PATCH] pipe: iovec: Fix OOB read in pipe_read()
Previous upstream *stable* fix 14f81062 was incomplete.
A local process can trigger a system crash with an OOB read on buf.
This occurs when the state of buf gets out of sync. After an error in
pipe_iov_copy_to_user() read_pipe may exit having updated buf->offset
but not buf->len. Upon retrying pipe_read() while in
pipe_iov_copy_to_user() *remaining will be larger than the space left
after buf->offset e.g. *remaing = PAGE_SIZE, buf->len = PAGE_SIZE,
buf->offset = 0x300.
This is fixed by not updating the state of buf->offset until after the
full copy is completed, similar to how pipe_write() is implemented.
For stable kernels < 3.16.
Bug: 27721803
Change-Id: Iefffbcc6cfd159dba69c31bcd98c6d5c1f21ff2e
Signed-off-by: Jeff Vander Stoep <jeffv@google.com>
---
fs/pipe.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/pipe.c b/fs/pipe.c
index 3e7ab278bb0c0..14b58f9f26f2e 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -400,7 +400,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
const struct pipe_buf_operations *ops = buf->ops;
void *addr;
size_t chars = buf->len, remaining;
- int error, atomic;
+ int error, atomic, offset;
if (chars > total_len)
chars = total_len;
@@ -414,9 +414,10 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
atomic = !iov_fault_in_pages_write(iov, chars);
remaining = chars;
+ offset = buf->offset;
redo:
addr = ops->map(pipe, buf, atomic);
- error = pipe_iov_copy_to_user(iov, addr, &buf->offset,
+ error = pipe_iov_copy_to_user(iov, addr, &offset,
&remaining, atomic);
ops->unmap(pipe, buf, addr);
if (unlikely(error)) {
@@ -432,6 +433,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
break;
}
ret += chars;
+ buf->offset += chars;
buf->len -= chars;
/* Was it a packet buffer? Clean up and exit */