diff mbox

[3.13.y-ckt,stable] Patch "[stable-only] pipe: Fix buffer offset after partially failed read" has been added to the 3.13.y-ckt tree

Message ID 1459349434-17884-1-git-send-email-kamal@canonical.com
State New
Headers show

Commit Message

Kamal Mostafa March 30, 2016, 2:50 p.m. UTC
This is a note to let you know that I have just added a patch titled

    [stable-only] pipe: Fix buffer offset after partially failed read

to the linux-3.13.y-queue branch of the 3.13.y-ckt extended stable tree 
which can be found at:

    http://kernel.ubuntu.com/git/ubuntu/linux.git/log/?h=linux-3.13.y-queue

This patch is scheduled to be released in version 3.13.11-ckt38.

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.13.y-ckt tree, see
https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable

Thanks.
-Kamal

---8<------------------------------------------------------------

From b0e567ed6df68d2facf1b96f13d1f26792ff2813 Mon Sep 17 00:00:00 2001
From: Ben Hutchings <ben@decadent.org.uk>
Date: Sat, 13 Feb 2016 02:34:52 +0000
Subject: [stable-only] pipe: Fix buffer offset after partially failed read

Quoting the RHEL advisory:

> It was found that the fix for CVE-2015-1805 incorrectly kept buffer
> offset and buffer length in sync on a failed atomic read, potentially
> resulting in a pipe buffer state corruption. A local, unprivileged user
> could use this flaw to crash the system or leak kernel memory to user
> space. (CVE-2016-0774, Moderate)

The same flawed fix was applied to stable branches from 2.6.32.y to
3.14.y inclusive, and I was able to reproduce the issue on 3.2.y.
We need to give pipe_iov_copy_to_user() a separate offset variable
and only update the buffer offset if it succeeds.

References: https://rhn.redhat.com/errata/RHSA-2016-0103.html
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
---
 fs/pipe.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

--
2.7.4
diff mbox

Patch

diff --git a/fs/pipe.c b/fs/pipe.c
index 47f79ac..c281867 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -407,6 +407,7 @@  pipe_read(struct kiocb *iocb, const struct iovec *_iov,
 			void *addr;
 			size_t chars = buf->len, remaining;
 			int error, atomic;
+			int offset;

 			if (chars > total_len)
 				chars = total_len;
@@ -420,9 +421,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)) {
@@ -438,6 +440,7 @@  redo:
 				break;
 			}
 			ret += chars;
+			buf->offset += chars;
 			buf->len -= chars;

 			/* Was it a packet buffer? Clean up and exit */