mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
61 lines
2.1 KiB
Diff
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 */
|