Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 674144 (CVE-2018-16864, CVE-2018-16865, CVE-2018-16866) - <sys-apps/systemd-239-r3: multiple vulnerabilities (CVE-2018-{16864,16865,16866})
Summary: <sys-apps/systemd-239-r3: multiple vulnerabilities (CVE-2018-{16864,16865,168...
Alias: CVE-2018-16864, CVE-2018-16865, CVE-2018-16866
Product: Gentoo Security
Classification: Unclassified
Component: Vulnerabilities (show other bugs)
Hardware: All Linux
: High critical (vote)
Assignee: Gentoo Security
Whiteboard: A1 [glsa+ cve]
Depends on:
Reported: 2018-12-31 01:41 UTC by Thomas Deutschmann (RETIRED)
Modified: 2019-03-10 20:48 UTC (History)
3 users (show)

See Also:
Package list:
Runtime testing required: ---
stable-bot: sanity-check+


Note You need to log in before you can comment on or make changes to this bug.
Description Thomas Deutschmann (RETIRED) gentoo-dev 2018-12-31 01:41:58 UTC
Incoming details.
Comment 1 Mike Gilbert gentoo-dev 2019-01-09 19:34:43 UTC

commit 1d4fd9fce1677572f7118cdddb05466d03c4df13
Author: Mike Gilbert <>
Date:   Wed Jan 9 10:28:00 2019 -0500

    sys-apps/systemd: security fixes

    Package-Manager: Portage-2.3.54_p2, Repoman-2.3.12_p42
    Signed-off-by: Mike Gilbert <>

 sys-apps/systemd/Manifest              |   2 +
 sys-apps/systemd/systemd-239-r3.ebuild | 448 ++++++++++++++++++++++++++++++++
 sys-apps/systemd/systemd-240-r3.ebuild | 457 +++++++++++++++++++++++++++++++++
 3 files changed, 907 insertions(+)
Comment 2 Kristian Fiskerstrand (RETIRED) gentoo-dev 2019-01-09 19:36:43 UTC
Report public
Comment 3 Thomas Deutschmann (RETIRED) gentoo-dev 2019-01-09 20:10:11 UTC
Qualys Security Advisory

System Down: A systemd-journald exploit


- Analysis
- Exploitation
- Analysis
- Exploitation
- Analysis
- Exploitation
Combined Exploitation of CVE-2018-16865 and CVE-2018-16866
- amd64 Exploitation
- i386 Exploitation

    Conversion, software version 7.0
        -- System of a Down, "Toxicity"


We discovered three vulnerabilities in systemd-journald

- CVE-2018-16864 and CVE-2018-16865, two memory corruptions
  (attacker-controlled alloca()s);

- CVE-2018-16866, an information leak (an out-of-bounds read).

CVE-2018-16864 was introduced in April 2013 (systemd v203) and became
exploitable in February 2016 (systemd v230). We developed a proof of
concept for CVE-2018-16864 that gains eip control on i386.

CVE-2018-16865 was introduced in December 2011 (systemd v38) and became
exploitable in April 2013 (systemd v201). CVE-2018-16866 was introduced
in June 2015 (systemd v221) and was inadvertently fixed in August 2018.

We developed an exploit for CVE-2018-16865 and CVE-2018-16866 that
obtains a local root shell in 10 minutes on i386 and 70 minutes on
amd64, on average. We will publish our exploit in the near future.

To the best of our knowledge, all systemd-based Linux distributions are
vulnerable, but SUSE Linux Enterprise 15, openSUSE Leap 15.0, and Fedora
28 and 29 are not exploitable because their user space is compiled with
GCC's -fstack-clash-protection.

This confirms
"It should be clear that kernel-only attempts to solve [the Stack Clash]
will necessarily always be incomplete, as the real issue lies in the
lack of stack probing."



    For today we will take the body parts and put them on the wall
        -- System of a Down, "Dreaming"

To leak a stack address or an mmap address from journald:

- First, we send a large native message to /run/systemd/journal/socket;
  journald mmap()s our message, and malloc()ates a large array of iovec
  structures: most of these structures point into our mmap()ed message,
  but some of them point to the stack (in dispatch_message_real()). The
  contents of this iovec array (especially the mmap and stack pointers)
  are preserved in a heap hole after free() (after journald finishes
  processing our message).

- Next, we send a large syslog message to /run/systemd/journal/dev-log;
  to receive our large message (in server_process_datagram()), journald
  realloc()ates its server buffer into the heap hole that previously
  contained the iovec array (and still contains remains of mmap and
  stack pointers).

- Last, we send a large syslog message that exploits CVE-2018-16866;
  journald receives our large message in its server buffer (in the heap
  chunk that previously contained the iovec array), and if we carefully
  choose the size of our message and position its terminating ":" in
  front of a remaining mmap or stack pointer, then we can leak this
  pointer (it is mistakenly read out-of-bounds as the body of our

    From this leaked stack pointer we easily deduce journald's stack pointer

before the alloca() jump, because the distance between the two depends
only on journald's executable.

    From the leaked mmap address we can deduce libc's address, but chunks of

unknown sizes are mmap()ed between the two, and we must therefore adopt
different strategies based on our target architecture (i386 or amd64).

Combined Exploitation of CVE-2018-16865 and CVE-2018-16866

    Don't leave your seats now
    Popcorn everywhere ...
        -- System of a Down, "CUBErt"

amd64 Exploitation

- To deduce libc's address from the leaked mmap address of our native
  message, we arrange for this message to be mmap()ed into the 2MB hole
  between's read-execute and read-only segments: from this hole's
  address we deduce's address, and hence libc's address (with help
  from ldd's output).

- If the resulting stack-to-libc distance is jumpable (if it is shorter
  than 4GB), then we proceed with our "write-what-where"; otherwise, we
  restart journald (we crash it with an alloca() of RLIMIT_STACK -- 8MB
  by default) and try again.

  We have a good chance of obtaining a jumpable stack-to-libc distance
  (and hence a root shell) after 2048 tries * 2 seconds ~= 68 minutes
  (by default, if journald crashes less than 5 times within 10 seconds,
  it is restarted automatically by systemd).

- For the "write-where" part of our "write-what-where", we overwrite
  libc's __free_hook function pointer, whose address modulo 16 is always
  equal to 8 (on every amd64 distribution that we exploited).

- For the "write-what" part of our "write-what-where", we overwrite
  __free_hook with the address of libc's system() function: whenever
  journald free()s data that we control, we achieve arbitrary command

Last-minute note: on CentOS 7, the usual function pointers in libc's
read-write segment (__free_hook, __malloc_hook, etc) are not located at
multiples of 16 plus 8. To circumvent this problem:

- First, we overwrite the "_chain" pointer of stderr's FILE structure
  with the address of our own fake FILE structure (this "_chain" pointer
  is located at a multiple of 16 plus 8, in libc's read-write segment).

- Next, we corrupt one of malloc's internal variables (also in libc's
  read-write segment).

- Last, we force a call to malloc() or free(), which detects the
  corruption of its internal variable and calls abort(), which calls
  _IO_flush_all_lockp(), which follows stderr's overwritten "_chain"
  pointer to our fake FILE structure; we eventually achieve arbitrary
  command execution by calling libc's system() via one of the function
  pointers in our fake FILE structure.

i386 Exploitation

Our i386 exploit is very similar to the amd64 exploit, but:

- The stack-to-libc distance is always jumpable (it is roughly 128MB).

- There is no hole between's read-execute and read-only segments.
  However, libc's address is randomized in a narrow range of 1MB and is
  therefore brute forcible: we have a good chance of correctly guessing
  libc's address after 1MB / 4KB = 256 tries * 2 seconds ~= 8 minutes.

- For the "write-where" part of our "write-what-where", we overwrite
  libc's __malloc_hook function pointer (__free_hook was never located
  at a multiple of 16 plus 8 or 12 on the i386 distributions that we
  exploited, but __malloc_hook always is).

- For the "write-what" part of our "write-what-where", we overwrite
  __malloc_hook with the address of a "mov esp, 0x89fffa5d ; ret" gadget
  (or equivalent stack pivot): since our native message can be as large
  as 768MB, we can mmap() it at 0x89fffa5d, take control of the stack,
  and return into libc's execve().
Comment 4 Thomas Deutschmann (RETIRED) gentoo-dev 2019-01-10 02:01:43 UTC
x86 stable
Comment 5 Mikle Kolyada (RETIRED) archtester Gentoo Infrastructure gentoo-dev Security 2019-01-10 09:51:01 UTC
amd64 stable
Comment 6 Mart Raudsepp gentoo-dev 2019-01-11 00:36:44 UTC
arm64 stable
Comment 7 Sergei Trofimovich (RETIRED) gentoo-dev 2019-01-16 22:50:09 UTC
ia64 stable
Comment 8 Sergei Trofimovich (RETIRED) gentoo-dev 2019-01-17 19:58:59 UTC
ppc stable
Comment 9 Sergei Trofimovich (RETIRED) gentoo-dev 2019-01-17 20:01:33 UTC
ppc64 stable
Comment 10 Matt Turner gentoo-dev 2019-01-22 07:16:02 UTC
alpha stable
Comment 11 Ben Kohler gentoo-dev 2019-01-23 21:25:57 UTC
sparc stable
Comment 12 Markus Meier gentoo-dev 2019-01-30 18:49:21 UTC
arm stable, all arches done.
Comment 13 GLSAMaker/CVETool Bot gentoo-dev 2019-03-10 20:48:18 UTC
This issue was resolved and addressed in
 GLSA 201903-07 at
by GLSA coordinator Aaron Bauman (b-man).