Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date: Sat, 6 Jun 2015 14:30:57 +0300
From: Solar Designer <solar@...nwall.com>
To: oss-security@...ts.openwall.com
Subject: CVE-2015-1805 Linux kernel: pipe: iovec overrun leading to memory corruption

Hi,

This is a Linux kernel bug fixed upstream about a year ago, with its
security impact discovered by Red Hat recently:

https://bugzilla.redhat.com/show_bug.cgi?id=1202855

Per Red Hat's own statement, all of RHEL 5, 6, and 7 are affected, and
so far only an update for RHEL5 has been released:

https://rhn.redhat.com/errata/RHSA-2015-1042.html

Also per Red Hat, this is a "high" severity issue, and the fix is
"Important".

There's also a "testing" update for OpenVZ/RHEL5:

https://openvz.org/Download/kernel/rhel5-testing/028stab119.1

The OpenVZ/RHEL5 branch was previously EOL'ed in Feb 2015, but its EOL
appears to have been updated to Feb 2018 (a smart move, given the easy
to include yet critical security fixes still coming from Red Hat):

https://openvz.org/Releases

(If they didn't do it, I would likely be porting the fix myself now.)

Reviewing the upstream commits:

http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=f0d1bec9d58d4c038d0ac958c9af82be6eb18045
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=637b58c2887e5e57850865839cc75f59184b23d1

it appears that the issue is that pipe_iov_copy_from_user() and
pipe_iov_copy_to_user() updated iov->iov_base and iov->iov_len, as well
as a local variable called len, yet the caller maintained its own
variables offset + addr and chars, which weren't similarly updated
between retries.  (Also, it appears that the code will retry at most
once, and as non-atomic, but maybe this makes sense if it assumes the
caller is at fault for the fault.)

In pipe_write(), this appears to allow for a read of wrong-offset data
and an over-read of data from userspace.  This may have security impact
if the condition is triggerable by other than the caller (and other than
the caller's other threads, which are trusted).  I don't immediately see
how this may be the case, or what else I might have overlooked.

In pipe_read(), this similarly appears to allow for a write of
wrong-offset data and an out of bounds write to the userspace buffer.
This may similarly have (worse?) security impact if the condition is
triggerable by other than the caller or their threads, but again it's
unclear to me whether that is the case.

In both cases, the out of bounds data accesses appear to be to userspace
addresses, and going via copy_from_user() / copy_to_user().  So impact
looks limited, and it is unclear if the issue is at all triggerable by a
party untrusted by the one attacked.  This aspect might be non-security.

However, it's trickier than that, since iov traverses over the multiple
struct iovec's and may eventually be what wasn't actually a struct iovec
in the caller.  This requires that iov->iov_len become exactly zero at
least one extra time.  If iov->iov_len becomes zero on
"iov->iov_len -= copy;" then pipe_iov_copy_to_user() either returns
success or proceeds to the next iteration of the loop.  In the former
case, there's no fault at this time.  In the latter case, there might be
a fault on the next iteration, in which case the caller will retry
pipe_iov_copy_to_user() with the original iov pointer.  The function
will then hit an extra !iov->iov_len (that's been zeroed by its previous
invocation) and perform iov++ an extra time.

The possibility of "struct iovec *iov" going out of range and the
subsequent out of bounds metadata accesses feel much more severe than
the out of bounds accesses to actual data in the userspace.
"iov->iov_base += copy;" and "iov->iov_len -= copy;" might then be
corrupting kernel memory.  It feels relatively unimportant what the
resulting values of iov_base and iov_len will be for their intended
purpose, since we use copy_from_user() / copy_to_user() on them anyway.
It feels more important that these "+=" and "-=" operators directly
modify individual words in kernel memory, albeit only slightly(?) out of
bounds of the original iov array.  So maybe it's this risk that needs
to be evaluated further.

I have quite possibly overlooked the elephant.

Red Hat's description includes the usual wording:

"A local, unprivileged user could use this flaw to crash the system
or, potentially, escalate their privileges on the system."

I'd like to know how.  "Crash the system" will do.  Thanks.

Alexander

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.