New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.
Starred by 1 user

Issue metadata

Status: WontFix
Owner:
Last visit > 30 days ago
Closed: May 2014
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Chrome
Pri: 2
Type: Bug-Security



Sign in to add a comment

exploitable linux kernel (3.4+) write bug in net/compat.c:compat_sys_recvmmsg under CONFIG_X86_X32_ABI

Reported by pagee...@gmail.com, Jan 28 2014 Back to list

Issue description

UserAgent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0

Steps to reproduce the problem:
Having recently run the sparse-like gcc plugin (available as the checker plugin in PaX) on linux 3.13 turned up the following gem in $subject:

asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
                                    unsigned int vlen, unsigned int flags,
                                    struct compat_timespec __user *timeout)
{
        int datagrams;
        struct timespec ktspec;

        if (flags & MSG_CMSG_COMPAT)
                return -EINVAL;

        if (COMPAT_USE_64BIT_TIME)
                return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                                      flags | MSG_CMSG_COMPAT,
                                      (struct timespec *) timeout);
/*...*/

The timeout pointer parameter is provided by userland (hence the __user annotation) but for x32 syscalls it's simply cast to a kernel pointer and is passed to __sys_recvmmsg which will eventually directly dereference it for both reading and writing. Other callers to __sys_recvmmsg properly copy from userland to the kernel first.

The impact is a sort of arbitrary kernel write-where-what primitive by unprivileged users where the to-be-written area must contain valid timespec data initially (the first 64 bit long field must be positive and the second one must be < 1G).

The bug was introduced by commit http://git.kernel.org/linus/ee4fa23c4b (other uses of COMPAT_USE_64BIT_TIME seem fine) and should affect all kernels since 3.4 (and perhaps vendor kernels if they backported x32 support along with this code). Note that CONFIG_X86_X32_ABI gets enabled at build time and only if CONFIG_X86_X32 is enabled and ld can build x32 executables.

Suggested fix:
Signed-off-by: PaX Team <pageexec@freemail.hu>

--- a/net/compat.c  2014-01-20 12:36:54.372997752 +0100
+++ b/net/compat.c      2014-01-28 02:06:59.265506171 +0100
@@ -780,22 +780,25 @@
        if (flags & MSG_CMSG_COMPAT)
                return -EINVAL;

-       if (COMPAT_USE_64BIT_TIME)
-               return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
-                                     flags | MSG_CMSG_COMPAT,
-                                     (struct timespec *) timeout);
-
        if (timeout == NULL)
                return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                                      flags | MSG_CMSG_COMPAT, NULL);

-       if (get_compat_timespec(&ktspec, timeout))
+       if (COMPAT_USE_64BIT_TIME) {
+               if (copy_from_user(&ktspec, timeout, sizeof(ktspec)))
+                       return -EFAULT;
+       } else if (get_compat_timespec(&ktspec, timeout))
                return -EFAULT;

        datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                                   flags | MSG_CMSG_COMPAT, &ktspec);
-       if (datagrams > 0 && put_compat_timespec(&ktspec, timeout))
-               datagrams = -EFAULT;
+       if (datagrams > 0) {
+               if (COMPAT_USE_64BIT_TIME) {
+                       if (copy_to_user(timeout, &ktspec, sizeof(ktspec)))
+                               datagrams = -EFAULT;
+               } else if (put_compat_timespec(&ktspec, timeout))
+                       datagrams = -EFAULT;
+       }

        return datagrams;
 }

What is the expected behavior?

What went wrong?
The many eyeballs.

Did this work before? N/A 

Chrome version:   Channel: n/a
OS Version: 3.13
Flash Version: 

If this bug proves real and eligible for a bug bounty then I'd like to request the payment to be made to Emese Revfy <re.emese@gmail.com> as she's already done the paperwork with Google and it is therefore the easiest way for us.
 
Great bug.

Comment 2 by meacer@chromium.org, Jan 28 2014

Cc: jln@chromium.org
@jln: I believe this should go to Chrome OS queue, could you assess?

Comment 3 by jln@chromium.org, Jan 28 2014

Cc: wad@chromium.org
Labels: -OS-Linux OS-Chrome
Owner: keescook@chromium.org
Status: Assigned
Very nice one pipacs!

We will already prevent exploitation from Chrome and other sandboxed process via seccomp-bpf (we forbid X32 entirely), but I don't think we otherwise disable X32 on Intel machines.

Kees, do you want to handle this one? If not, feel free to assign to me.


Comment 4 by pagee...@gmail.com, Jan 28 2014

So I couldn't help it and created a simple PoC trigger based on the example in the manpage. As it is, it'll just trigger a null-deref oops on the read side:

BUG: unable to handle kernel NULL pointer dereference at 0000000000000009
IP: [<ffffffff82a333cb>] __sys_recvmmsg+0x3b/0x310

By passing an appropriate value for the timeout pointer one can trigger the write side too. By the way, this also allows scanning the kernel address space and even reveal KASLR (try every 2MB, if no oops -> found the kernel), no doubt to Kees' delight :).
recvmmsg.c
1.9 KB Download
Labels: Cr-OS-Kernel
Chrome OS does not currently build with CONFIG_X86_X32, but I'm sure it won't stay that way forever.

And, FWIW, Chrome OS panics on Oops, so you only get 1 try to find kASLR offset using that mechanism.

Comment 7 by pagee...@gmail.com, Jan 29 2014

This has been assigned CVE-2014-0038 in the meantime.

Also given the lack of responses/objections from linux-distros and the kernel security lists and that Google doesn't seem to be affected per se, what shall be the timeline for releasing the fix? We'd like to sit on this less and less by each passing day... so please advise ;).

Comment 8 by pagee...@gmail.com, Feb 1 2014

The fix is upstream: https://git.kernel.org/linus/2def2ef2ae5f3990aab and Ubuntu released new kernels as well, stable backports are in progress (I already got an email for 3.8, the rest is probably/hopefully coming in short order).
@pageexec: thanks again for being awesome.

Give that we don't compile x32 into Chrome OS, I'm not sure this will pass the bar for a Chromium Security Reward.

_However_, and much more positively, I've nominated this discovery in the sandbox escapes category of the Internet Bug Bounty: https://hackerone.com/sandbox, and I'm hopeful to hear back soon.
This got $3000 under the Internet Bug Bounty: https://hackerone.com/reports/960

@pageexec: please keep up research for bugs in the Linux kernel. For ones that trigger _inside_ the seccomp sandbox, there's a good chance of rewards from multiple different places ;-)
Status: WontFix
Flipping to "won't fix" since it isn't an issue for Chrome OS.
Project Member

Comment 12 by ClusterFuzz, Aug 26 2014

Labels: -Restrict-View-SecurityTeam
Bulk update: removing view restriction from closed bugs.
Project Member

Comment 13 by sheriffbot@chromium.org, Oct 1 2016

This bug has been closed for more than 14 weeks. Removing security view restrictions.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Project Member

Comment 14 by sheriffbot@chromium.org, Oct 2 2016

This bug has been closed for more than 14 weeks. Removing security view restrictions.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Labels: allpublic

Sign in to add a comment