⬢ DragonFlyBSD Kernel Audit
DF-4454 / fix_iter1_panic.txt
← back to finding ↓ download raw
FIX VALIDATION ITERATION 1 — patched-kernel panic (author's fix bug, NOT the original bug)

The first version of fix.diff had a use-after-free of the *client* in
evdev_dtor(): it called evdev_unref(client->ec_evdev) AFTER kfree(client),
reading the ec_evdev field from freed client memory. Closing the stale fd
(kill -9 of the PoC) panicked:

Fatal user address access from kernel mode from evdev_uaf at ffffffff809cc5e0
Fatal trap 12: page fault while in kernel mode
cpuid = 2; lapic id = 2
fault virtual address	= 0x2b0
fault code		= supervisor read data, page not present
instruction pointer	= 0x8:0xffffffff809cc5e0
stack pointer	        = 0x10:0xfffff8011868d600
frame pointer	        = 0x10:0xfffff8011868d618
code segment		= base 0x0, limit 0xfffff, type 0x1b
processor eflags	= interrupt enabled, resume, IOPL = 0
current process		= 894
kernel: type 12 trap, code=0
Stopped at      evdev_unref:    movl    0x2b0(%rdi),%eax

(0x2b0 is offsetof(struct evdev_dev, ev_refs); rdi==NULL because the freed
client block read back zeros.)

Fix iteration 2 captures `struct evdev_dev *evdev = client->ec_evdev`
BEFORE kfree(client). The positive result of this iteration: on the patched
kernel the stale write(2) aborted immediately with ENODEV after device_del
(baseline: full 64 MB write succeeded through the dangling pointer), and no
magic events crossed to the re-added device (the reader blocked with zero
events, baseline: 2-19 magic events per run).