|
Message-ID: <a172617e-fd76-8f64-9af6-fca53c10a4f4@canonical.com> Date: Mon, 18 Feb 2019 17:41:56 +0100 From: Chris Coulson <chris.coulson@...onical.com> To: oss-security@...ts.openwall.com Subject: CVE-2019-6454: systemd (PID1) crash with specially crafted D-Bus message Hi, I recently discovered a way for an unprivileged user to crash PID1 by sending it a specially crafted D-Bus message on the system bus and causing the stack pointer to jump the stack guard pages, leaving it pointing to an unmapped page. Details of the issue follow: ---- bus_process_object() in src/libsystemd/sd-bus/bus-objects.c allocates a buffer on the stack large enough to temporarily store the object path specified in the incoming message: assert(m->path); assert(m->member); pl = strlen(m->path); do { => char prefix[pl+1]; bus->nodes_modified = false; r = object_find_and_run(bus, m, m->path, false, &found_object); As the length of this is attacker controlled, it is possible for a malicious unprivileged local user to send a message which results in the stack pointer moving outside of the bounds of the currently mapped stack region, jumping over the stack guard pages. According to the dbus specification, the path "may be of any length" (with the length being represented on the wire by a uint32), but systemd seems to limit the size of incoming messages to 128MB (BUS_MESSAGE_SIZE_MAX). From testing on Ubuntu 18.10, it seems that the real limit is actually much less than this - dbus-daemon drops the connection when I try to send a message with an object path greater than about 32MB. The effect of this is that the stack pointer always lands in an unmapped page and it doesn't seem to be possible to make it land in another mapped page. Running a simple script that sends a message with a long enough path to org.freedesktop.systemd1 on Ubuntu 18.10 (systemd v239) and CentOS 7.6 (systemd v219) results in an easily reproducible crash (and subsequent kernel panic) on both x86 and x86-64, with a stack trace that looks like this: Program received signal SIGSEGV, Segmentation fault. bus_process_object (bus=0x56085041a6a0, m=0x5608504d4d00) at ../src/libsystemd/sd-bus/bus-objects.c:1378 1378 ../src/libsystemd/sd-bus/bus-objects.c: No such file or directory. (gdb) bt #0 bus_process_object (bus=0x56085041a6a0, m=0x5608504d4d00) at ../src/libsystemd/sd-bus/bus-objects.c:1378 #1 0x00007f4a4e373b37 in process_message (m=0x5608504d4d00, bus=0x56085041a6a0) at ../src/libsystemd/sd-bus/sd-bus.c:2663 #2 process_running (ret=0x0, priority=0, hint_priority=false, bus=0x56085041a6a0) at ../src/libsystemd/sd-bus/sd-bus.c:2705 #3 bus_process_internal (bus=bus@...ry=0x56085041a6a0, hint_priority=hint_priority@...ry=false, priority=priority@...ry=0, ret=ret@...ry=0x0) at ../src/libsystemd/sd-bus/sd-bus.c:2924 #4 0x00007f4a4e373d9c in sd_bus_process (bus=bus@...ry=0x56085041a6a0, ret=ret@...ry=0x0) at ../src/libsystemd/sd-bus/sd-bus.c:2951 #5 0x00007f4a4e373e68 in io_callback (s=<optimized out>, fd=<optimized out>, revents=<optimized out>, userdata=<optimized out>, s=<optimized out>, fd=<optimized out>, revents=<optimized out>, userdata=<optimized out>) at ../src/libsystemd/sd-bus/sd-bus.c:3304 #6 0x00007f4a4e34fa10 in source_dispatch (s=s@...ry=0x560850433590) at ../src/libsystemd/sd-event/sd-event.c:3103 #7 0x00007f4a4e34fcff in sd_event_dispatch (e=e@...ry=0x56085036a090) at ../src/libsystemd/sd-event/sd-event.c:3516 #8 0x00007f4a4e34fec8 in sd_event_run (e=0x56085036a090, timeout=18446744073709551615) at ../src/libsystemd/sd-event/sd-event.c:3573 #9 0x000056084e579453 in manager_loop (m=0x5608503675d0) at ../src/core/manager.c:2814 #10 invoke_main_loop (m=0x5608503675d0, ret_reexecute=0x7fff92a0076a, ret_retval=0x7fff92a0076c, ret_shutdown_verb=<optimized out>, ret_fds=0x7fff92a00770, ret_switch_root_dir=0x7fff92a00798, ret_switch_root_init=0x7fff92a00790, ret_error_message=0x7fff92a00780) at ../src/core/main.c:1630 #11 0x000056084e4da610 in main (argc=<optimized out>, argv=0x7fff92a00a48) at ../src/core/main.c:2415 (gdb) p $_siginfo $1 = {si_signo = 11, si_errno = 0, si_code = 1, _sifields = {_pad = {-1867007032, 32767, 0 <repeats 26 times>}, _kill = {si_pid = -1867007032, si_uid = 32767}, _timer = {si_tid = -1867007032, si_overrun = 32767, si_sigval = {sival_int = 0, sival_ptr = 0x0}}, _rt = {si_pid = -1867007032, si_uid = 32767, si_sigval = {sival_int = 0, sival_ptr = 0x0}}, _sigchld = {si_pid = -1867007032, si_uid = 32767, si_status = 0, si_utime = 0, si_stime = 0}, _sigfault = {si_addr = 0x7fff90b7bbc8, _addr_lsb = 0, _addr_bnd = {_lower = 0x0, _upper = 0x0}}, _sigpoll = {si_band = 140735621348296, si_fd = 0}}} (gdb) disassemble Dump of assembler code for function bus_process_object: ...... 0x00007f4a4e387aae <+238>: mov %r13,%rsi 0x00007f4a4e387ab1 <+241>: mov %r12,%rdi 0x00007f4a4e387ab4 <+244>: mov %rsp,%rbx => 0x00007f4a4e387ab7 <+247>: callq 0x7f4a4e386280 <object_find_and_run> You can see that %rsp points to an unmapped page: (gdb) info registers rax 0x1e84810 32000016 rbx 0x7fff90b7bbd0 140735621348304 rcx 0x0 0 rdx 0x7f4a48dbe028 139957026676776 rsi 0x5608504d4d00 94593706970368 rdi 0x56085041a6a0 94593706206880 rbp 0x7fff92a00430 0x7fff92a00430 rsp 0x7fff90b7bbd0 0x7fff90b7bbd0 r8 0x7fff92a003f7 140735653348343 r9 0x1 1 r10 0x1 1 r11 0x9690b4ffdb710482 -7597373560382749566 r12 0x56085041a6a0 94593706206880 r13 0x5608504d4d00 94593706970368 r14 0x7fff92a003f7 140735653348343 r15 0x7f4a4e465be0 139957117541344 rip 0x7f4a4e387ab7 0x7f4a4e387ab7 <bus_process_object+247> eflags 0x10202 [ IF RF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) info proc mappings process 1 Mapped address spaces: Start Addr End Addr Size Offset objfile ...... 0x7f4a4e76f000 0x7f4a4e770000 0x1000 0x29000 /lib/x86_64-linux-gnu/ld-2.28.so 0x7f4a4e770000 0x7f4a4e771000 0x1000 0x0 0x7fff929e0000 0x7fff92a01000 0x21000 0x0 [stack] 0x7fff92ac8000 0x7fff92acb000 0x3000 0x0 [vvar] Given the constraint that it doesn't appear to be possible to make the stack pointer land in another mapped page, this bug is classified as denial-of-service. ---- There are 3 patches required to resolve this, provided by Red Hat Product Security and attached to this message. The first patch enforces a sensible size limit on D-Bus object paths, dropping messages when the path is too long. The second patch removes usage of variable-size stack allocations for object paths. The third patch stops the system bus connection from being terminated when an invalid message is received. I would like to thank Riccardo Schirone, Lennart Poettering and Red Hat Product Security for their help with this issue. Regards, - Chris View attachment "0001-Refuse-dbus-message-paths-longer-than-BUS_PATH_SIZE_.patch" of type "text/x-patch" (1848 bytes) View attachment "0002-Allocate-temporary-strings-to-hold-dbus-paths-on-the.patch" of type "text/x-patch" (6660 bytes) View attachment "0003-sd-bus-if-we-receive-an-invalid-dbus-message-ignore-.patch" of type "text/x-patch" (1991 bytes) Download attachment "signature.asc" of type "application/pgp-signature" (489 bytes)
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.