⬢ DragonFlyBSD Kernel Audit
DF-5544 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5544",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "uhci_pci_detach() discards device_delete_children()s return at sys/bus/u4b/controller/uhci_pci.c:374 and unconditionally stops the controller, tears down the interrupt, releases IRQ+I/O, frees all USB DMA memory and returns 0 (:411). Demonstrated live on the QEMU guest with a real PIIX3 UHCI: with one child vetoing detach, device_detach(uhci0) reported complete success (uhci0: detached), left the vetoing child ATTACHED to the now-driverless uhci0 whose softc had been kfreed/NULLed by device_set_driver(dev,NULL) \u2014 the next touch of the parent context through the orphan was a Fatal trap 12 page fault (NULL softc + 0x5458 field offset), guest dead in DDB. The vetoing child is a KLD stand-in for the newbus detach contract (no in-tree u4b child detach returns nonzero today; usb_detach returns 0 unconditionally at usb_controller.c:242) \u2014 same latent-API-hazard posture as DF-5528 (fwohci_pci.c) and DF-4558 (atapi-cam.c), but here proven end-to-end including the panic consequence. Root-context trigger (kldunload/PCI hot-unplug) => Low severity; mechanics certain. fix.diff (check + propagate) validated on a rebuilt guest kernel: identical trigger now returns EBUSY with resources fully intact and no panic; a later retry after the child cooperates completes a clean 0-children detach.",
  "exploit_chain": "privileged: kldunload uhci / PCI hot-unplug -> devclass_delete_driver -> device_detach(uhci0) -> uhci_pci_detach -> device_delete_children fails (child veto) -> return value discarded -> IRQ/IO released, usb_bus_mem_free_all frees frame list + QH/TD pools, returns 0 -> device_set_driver(NULL) kfrees softc -> still-attached child operates on freed/NULL parent state -> supervisor page fault (observed) / UAF on kfreed M_BUS softc and freed DMA pages (e.g. cached pointers). Not reachable by an unprivileged user through this file.",
  "evidence": "panic.txt (raw serial: veto -> uhci0: detached -> returned 0 -> veto0(attached=1) -> Fatal trap 12, Stopped at df5544_thread+0x2a1 movq 0x5458(%rax)); run.log (baseline transcript + root-cause chain); run.fix.log + fix_serial_console_full.log (patched: child device failed to detach (16); refusing controller teardown, returned 16, driver=uhci state=3, pframes buffer unchanged, guest alive; retry clean with 0 children); veto.c/Makefile/build.sh/run.sh (harness); env.txt; fix.diff",
  "kernel_refs": [
    "sys/bus/u4b/controller/uhci_pci.c:374",
    "sys/bus/u4b/controller/uhci_pci.c:411",
    "sys/bus/u4b/controller/uhci_pci.c:409",
    "sys/kern/subr_bus.c:885",
    "sys/kern/subr_bus.c:2131",
    "sys/kern/subr_bus.c:897",
    "sys/bus/u4b/controller/usb_controller.c:242"
  ],
  "poc_changes": "v1 triggered device_detach from the sysctl handler and self-deadlocked on the per-CPU gd_sysctllock (usb teardown calls device_sysctl_fini); v2/v3 moved the trigger into a module-owned kernel thread and made the veto child cooperate on demand (hw.df5544=5) so the fixs retry path could be demonstrated. Also: guest booted with QEMU_EXTRA=-device piix3-usb-uhci (vm.sh default has no USB), uhci is compiled into X86_64_GENERIC so the real kldunload path was driven via device_detach() from the harness, identical to devclass_delete_driver().",
  "attempts": 4,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (baseline; fix validated on #1: Wed Oct  7 09:02:16 UTC 2026)",
  "runtime_sec": 1140,
  "guest_dirty": 0,
  "build_cmd": "cd /root/df5544 && make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC",
  "run_cmd": "kldload /root/df5544/veto.ko; sysctl hw.df5544=1; sysctl hw.df5544=2",
  "code_hash": "0710af78ee179ffbe1dda779d586d1ea3859c2eaa23cd9d540a87573d4ba702b",
  "notes": "Pass-2 negatives recorded (VERDICT.md): DF-5394 unwind entry dead on this driver (uhci_init usb usb_attach return 0 unconditionally); no DF-5509 analog (INTR masked at :281 before arming at :331, handler ACKs and never touches bdev, uhci.c:1420-1484); LEGSUP handoff single atomic write; suspend/resume wired via uhci_set_hw_power_sleep; alloc_all failure self-cleans and DS_ATTACHED guard prevents later detach; sc_vendor ksprintf bounded. Known not re-reported: DF-1105, DF-5296. Guest reset to with-src after the run.",
  "recommended_fix": "Check device_delete_children(self) at uhci_pci.c:374 and return the error before touching controller resources, so a child veto leaves IRQ/IO/DMA/softc fully intact and the caller retries later.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "fix.diff (check + propagate device_delete_children return) applied to guest /usr/src, quickkernel + installkernel + reboot; identical trigger returns 16 with refusing controller teardown, driver bound, state DS_ATTACHED, DMA buffers unchanged, no panic on the touch that killed the baseline; retry after the child cooperates completes a clean 0-children detach. Bad behavior gone.",
  "fix_evidence": "run.fix.log; fix_serial_console_full.log; guest kernel #1 Wed Oct 7 09:02:16 UTC 2026"
}