Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 9 Aug 2018 16:21:03 +0200
From: Andrey Konovalov <>
Cc: Kostya Serebryany <>, Dmitry Vyukov <>, 
	Alexander Potapenko <>, Kees Cook <>
Subject: Re: Linux kernel: CVE-2017-18344: arbitrary-read vulnerability in the
 timer subsystem

On Thu, Aug 2, 2018 at 8:57 PM, Andrey Konovalov <> wrote:
> Hi!
> Syzkaller/syzbot found a global-out-of-bounds bug in the timer
> subsystem of the Linux kernel [1], that is exploitable and can be used
> to gain an arbitrary-read primitive. This allows to access kernel
> memory and leak keys, credentials or other sensitive information that
> is stored there (so the bug has a similar impact to Meltdown). I'll
> share a PoC exploit in a week.
> The bug was introduced in commit 57b8015e ("posix-timers: Show
> sigevent info in proc file") [2] in 3.10 and fixed by commit cef31d9a
> ("posix-timer: Properly check sigevent->sigev_notify") [3] in
> 4.15-rc4. The bug only affects kernels that have CONFIG_POSIX_TIMERS
> and CONFIG_CHECKPOINT_RESTORE enabled, which is done by a lot of
> modern distros.
> This bug has been fixed in Ubuntu 16.04 [7], but still affects at
> least CentOS 7 at this moment (at least 3.10.0-862.9.1.el7.x86_64 that
> I've checked). I haven't checked the other distros.
> I've contacted linux-distros@ today and was asked to post to
> oss-security@ right away, since the issue is already public (and has
> been for the last 8 months, see the timeline below).
> ======
> Description from MITRE [4]:
> The timer_create syscall implementation in kernel/time/posix-timers.c
> in the Linux kernel before 4.14.8 doesn't properly validate the
> sigevent->sigev_notify field, which leads to out-of-bounds access in
> the show_timer function (called when /proc/$PID/timers is read). This
> allows userspace applications to read arbitrary kernel memory (on a
> ======
> I thought it would be quite interesting to see when some Linux distros
> fixed this bug, since there was no CVE requested and assigned until
> recently.
> Initially I was only looking at Ubuntu 16.04, here's the related timeline:
> * Nov 30, 2017 - the bug reported by syzbot [5]
> * Dec 15, 2017 - the fix committed upstream [3]
> * Feb 17, 2018 - the fix backported to the 4.4 stable kernel branch [6]
> * Mar 15, 2018 - the fix added to the Ubuntu Xenial 4.4 kernel branch [7]
> * Jul 25, 2018 - CVE requested
> * Aug 2, 2018 - notified linux-distros@
> * Aug 2, 2018 - announcement on oss-security@
> In this particular case of a somewhat "scary" bug there was a window
> of 3.5 months between the bug being reported and the fixing commit
> reaching the Ubuntu Xenial 4.4 kernel branch. This gives some insight
> into how much time it usually takes for a fix to travel from upstream
> through stable into a distro kernel when there's no CVE. Compared to
> the 14 days, that distros are usually given to fix a security bug
> reported through linux-distros@, that seems rather long.
> Then I decided to take a look at the CentOS kernel. I was quite
> surprised to find out that this bug hasn't been fixed there at all. I
> was under the impression that most Linux distros either follow stable
> kernel branches or monitor upstream commits for security related fixes
> themselves. It seems that this is not the case. Perhaps this fix was
> missed because CentOS 7 kernel is based on the 3.10 kernel version,
> and the 3.10 stable kernel release stopped being supported in November
> 2017.
> This is just one bug though. Right now there are 700+ fixed bugs
> reported by syzbot [8] and 200+ more, which are still not fixed [9].
> Almost none of them have CVEs (if anybody want to practice requesting
> CVEs, go for it). There are also ~9000 fixes backported to 4.4 stable
> kernel. Some of them are security relevant and don't have CVEs. On top
> of that apparently there are ~700 fixes that are missing in the 4.4
> stable kernel [10].
> It seems that a CVE is required for a particular security related fix
> to end up in distro kernels, but there are no CVEs requested for most
> of the bugs that are being fixed. So there's this inconsistency
> between the Linux kernel community that just fixes the bugs without
> bothering about CVEs and the distros, which require CVEs to apply
> fixes to their kernels.
> Just some thoughts :)
> Thanks!
> ======
> [1]
> [2]
> [3]
> [4]
> [5]
> [6]
> [7]
> [8]
> [9]
> [10]

I've uploaded the exploit:

The exploit allows to read arbitrary virtual or physical (within the
physmap) memory, to dump virtual memory that belongs to a particular
process by its pid and to search the physical memory for a pattern
(only the start of each page though, but that's enough to locate at
least /etc/shadow). See the comment in the exploit source code for a
usage example that shows how to read /etc/shadow on Ubuntu xenial
4.13.0-38-generic. The exploit bypasses KASLR and SMEP, but doesn't
bypass SMAP.

The bug is that the timer_create syscall doesn't validate the
sigevent->sigev_notify value and then uses it to address a global
array of strings in show_timer() when /proc/PID/timers is read. By
providing a large sigev_notify value we can cause a
global-out-of-bounds access that results in nstr[notify &
~SIGEV_THREAD_ID] overflowing 8 bytes and ending up in the userspace.
We can then mmap the accessed userspace page and put an arbitrary
address there, which allows us to read arbitrary kernel memory. Since
the kernel accesses the userspace here, the exploit attempt would be
caught by SMAP.

Since kernel image location is randomized due to KASLR we can't know
in advance which page exactly we should mmap. However since the kernel
usually lies in a known address range [0xffffffff81000000, ...), we
can mmap a huge chunk of userspace memory that would catch the access
wherever the kernel image is placed. We can then bisect the exact
location by filling half of the mapped memory with one pointer and the
other half with another and reading /proc/PID/timers to see which one
got accessed. At this point we know the exact address in the userspace
where we can place a pointer to read kernel data.

We could now calculate the kernel location based on this userspace
address, but instead for whatever reason I leak the first IDT entry
(which is divide_error) and calculate kernel image address based on
that. The location of physmap is also randomized due to KASLR on some
kernels (where CONFIG_RANDOMIZE_MEMORY=y), so we read the
page_offset_base global variable value to find out the physmap
location. It should be possible to find the location of all required
kernel symbols heuristically instead of hard coding offsets, but I
haven't really explored this.

Now we can read arbitrary physical memory through physmap. The
/etc/shadow content always seems to be page aligned, so we can search
the beginning of each page for something like 'root:!:' and locate it
in the physical memory. We can also walk the list of running tasks
starting with init_task and dump memory that belongs to a particular
tasks by walking the page tables that belong to it. Dumping and
inspecting memory for gnome-keyring-daemon for example allows us to
find out user password.


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.