From: Greg Kroah-Hartman Date: Fri, 26 Jun 2015 04:24:02 +0000 (-0700) Subject: 3.10-stable patches X-Git-Tag: v3.10.82~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2f4d8e57308fc0dfd741f5d294ba0883463a8a61;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: pipe-iovec-fix-memory-corruption-when-retrying-atomi-3.14.patch --- diff --git a/queue-3.10/pipe-iovec-fix-memory-corruption-when-retrying-atomi-3.14.patch b/queue-3.10/pipe-iovec-fix-memory-corruption-when-retrying-atomi-3.14.patch new file mode 100644 index 00000000000..855fae96238 --- /dev/null +++ b/queue-3.10/pipe-iovec-fix-memory-corruption-when-retrying-atomi-3.14.patch @@ -0,0 +1,180 @@ +From: Ben Hutchings +Date: Tue, 16 Jun 2015 22:11:06 +0100 +Subject: pipe: iovec: Fix memory corruption when retrying atomic copy + as non-atomic + +From: Ben Hutchings + +pipe_iov_copy_{from,to}_user() may be tried twice with the same iovec, +the first time atomically and the second time not. The second attempt +needs to continue from the iovec position, pipe buffer offset and +remaining length where the first attempt failed, but currently the +pipe buffer offset and remaining length are reset. This will corrupt +the piped data (possibly also leading to an information leak between +processes) and may also corrupt kernel memory. + +This was fixed upstream by commits f0d1bec9d58d ("new helper: +copy_page_from_iter()") and 637b58c2887e ("switch pipe_read() to +copy_page_to_iter()"), but those aren't suitable for stable. This fix +for older kernel versions was made by Seth Jennings for RHEL and I +have extracted it from their update. + +CVE-2015-1805 + +References: https://bugzilla.redhat.com/show_bug.cgi?id=1202855 +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + fs/pipe.c | 55 ++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 32 insertions(+), 23 deletions(-) + +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -117,25 +117,27 @@ void pipe_wait(struct pipe_inode_info *p + } + + static int +-pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len, +- int atomic) ++pipe_iov_copy_from_user(void *addr, int *offset, struct iovec *iov, ++ size_t *remaining, int atomic) + { + unsigned long copy; + +- while (len > 0) { ++ while (*remaining > 0) { + while (!iov->iov_len) + iov++; +- copy = min_t(unsigned long, len, iov->iov_len); ++ copy = min_t(unsigned long, *remaining, iov->iov_len); + + if (atomic) { +- if (__copy_from_user_inatomic(to, iov->iov_base, copy)) ++ if (__copy_from_user_inatomic(addr + *offset, ++ iov->iov_base, copy)) + return -EFAULT; + } else { +- if (copy_from_user(to, iov->iov_base, copy)) ++ if (copy_from_user(addr + *offset, ++ iov->iov_base, copy)) + return -EFAULT; + } +- to += copy; +- len -= copy; ++ *offset += copy; ++ *remaining -= copy; + iov->iov_base += copy; + iov->iov_len -= copy; + } +@@ -143,25 +145,27 @@ pipe_iov_copy_from_user(void *to, struct + } + + static int +-pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len, +- int atomic) ++pipe_iov_copy_to_user(struct iovec *iov, void *addr, int *offset, ++ size_t *remaining, int atomic) + { + unsigned long copy; + +- while (len > 0) { ++ while (*remaining > 0) { + while (!iov->iov_len) + iov++; +- copy = min_t(unsigned long, len, iov->iov_len); ++ copy = min_t(unsigned long, *remaining, iov->iov_len); + + if (atomic) { +- if (__copy_to_user_inatomic(iov->iov_base, from, copy)) ++ if (__copy_to_user_inatomic(iov->iov_base, ++ addr + *offset, copy)) + return -EFAULT; + } else { +- if (copy_to_user(iov->iov_base, from, copy)) ++ if (copy_to_user(iov->iov_base, ++ addr + *offset, copy)) + return -EFAULT; + } +- from += copy; +- len -= copy; ++ *offset += copy; ++ *remaining -= copy; + iov->iov_base += copy; + iov->iov_len -= copy; + } +@@ -395,7 +399,7 @@ pipe_read(struct kiocb *iocb, const stru + struct pipe_buffer *buf = pipe->bufs + curbuf; + const struct pipe_buf_operations *ops = buf->ops; + void *addr; +- size_t chars = buf->len; ++ size_t chars = buf->len, remaining; + int error, atomic; + + if (chars > total_len) +@@ -409,9 +413,11 @@ pipe_read(struct kiocb *iocb, const stru + } + + atomic = !iov_fault_in_pages_write(iov, chars); ++ remaining = chars; + redo: + addr = ops->map(pipe, buf, atomic); +- error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars, atomic); ++ error = pipe_iov_copy_to_user(iov, addr, &buf->offset, ++ &remaining, atomic); + ops->unmap(pipe, buf, addr); + if (unlikely(error)) { + /* +@@ -426,7 +432,6 @@ redo: + break; + } + ret += chars; +- buf->offset += chars; + buf->len -= chars; + + /* Was it a packet buffer? Clean up and exit */ +@@ -531,6 +536,7 @@ pipe_write(struct kiocb *iocb, const str + if (ops->can_merge && offset + chars <= PAGE_SIZE) { + int error, atomic = 1; + void *addr; ++ size_t remaining = chars; + + error = ops->confirm(pipe, buf); + if (error) +@@ -539,8 +545,8 @@ pipe_write(struct kiocb *iocb, const str + iov_fault_in_pages_read(iov, chars); + redo1: + addr = ops->map(pipe, buf, atomic); +- error = pipe_iov_copy_from_user(offset + addr, iov, +- chars, atomic); ++ error = pipe_iov_copy_from_user(addr, &offset, iov, ++ &remaining, atomic); + ops->unmap(pipe, buf, addr); + ret = error; + do_wakeup = 1; +@@ -575,6 +581,8 @@ redo1: + struct page *page = pipe->tmp_page; + char *src; + int error, atomic = 1; ++ int offset = 0; ++ size_t remaining; + + if (!page) { + page = alloc_page(GFP_HIGHUSER); +@@ -595,14 +603,15 @@ redo1: + chars = total_len; + + iov_fault_in_pages_read(iov, chars); ++ remaining = chars; + redo2: + if (atomic) + src = kmap_atomic(page); + else + src = kmap(page); + +- error = pipe_iov_copy_from_user(src, iov, chars, +- atomic); ++ error = pipe_iov_copy_from_user(src, &offset, iov, ++ &remaining, atomic); + if (atomic) + kunmap_atomic(src); + else diff --git a/queue-3.10/series b/queue-3.10/series index 0b1e22d4748..bc53aab1f03 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -1,3 +1,4 @@ crypto-caam-fix-rng-buffer-cache-alignment.patch tracing-have-filter-check-for-balanced-ops.patch drm-mgag200-reject-non-character-cell-aligned-mode-widths.patch +pipe-iovec-fix-memory-corruption-when-retrying-atomi-3.14.patch