⬢ DragonFlyBSD Kernel Audit
DF-2304 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2304",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "Forced-branch mechanical reproduction on the verbatim-interposition harness: the real fwohci_pci_attach chain (bus_generic_probe -> firewire identify -> BUS_ADD_CHILD -> the verbatim fwohci_pci_add_child -> real device_add_child) ran with device_probe_and_attach interposed to fail exactly at fwohci_pci.c:442. The stock error path called fwohci_pci_detach(parent), whose device_delete_child at fwohci_pci.c:352 freed the child (kobj_delete/kfree, subr_bus.c:1306), and add_child then called device_delete_child(parent, child) again at fwohci_pci.c:447 on the same freed pointer. The INVARIANTS kernel panicked inside the second delete: panic Bad link elm prev->next != elm, backtrace fwohci_pci_add_child+0xfd <- bus_generic_identify <- bus_generic_probe, 553 MB dump. On a non-INVARIANTS kernel the stale-pointer TAILQ_REMOVEs (parent children list and the global bus_data_devices list) and the kobj_delete/kfree double free execute silently. REACHABILITY IS HONESTLY LATENT: the branch requires device_probe_and_attach of the firewire child to fail, but the child is created by the firewire drivers own identify method, firewire_probe returns 0 unconditionally (firewire.c:313-317), firewire_attach has no failure return (firewire.c:383-416), and the underlying allocations are M_INTWAIT. The branch runs at configuration time only (boot/kldload); no unprivileged or remote input reaches it. Not privesc-class today; it is a real latent heap double-free that fires if firewire attach ever grows a failure path.",
  "exploit_chain": "",
  "evidence": "panic.txt: the two logged deletes share child=0xfffff8011769c6a0 (FROM fwohci_pci.c:352 then FROM fwohci_pci.c:447) followed by panic Bad link elm and the fwohci_pci_add_child backtrace. run.log: full trigger output ending at the panic (ssh died). run_fixed.log: fixed kernel, same forced branch, exactly one delete (line 354 post-patch), no panic, resources balanced.",
  "kernel_refs": [
    "sys/bus/firewire/fwohci_pci.c:446-447",
    "sys/bus/firewire/fwohci_pci.c:439",
    "sys/bus/firewire/fwohci_pci.c:351-353",
    "sys/kern/subr_bus.c:1284-1310",
    "sys/kern/subr_bus.c:1306",
    "sys/kern/subr_bus.c:2793",
    "sys/bus/firewire/firewire.c:313-317",
    "sys/bus/firewire/firewire.c:383-416"
  ],
  "poc_changes": "No seeded PoC existed; the rig was built fresh for this batch, extending the DF-2300 verbatim-interposition design to fwohci_pci.c (second TU: fwohci_pci.c TU-included with three call-site interposition macros; fabricated kobj PCI-bus parent + fake fwohci device shell carrying the real fwohci devclass; emulated OHCI regs/PHY reused from fwohci_harness.c). Fixed during bring-up: OHCI_VERSION value (mver bits 16-23 must be 1-9), bootverbose extern (already declared), sys/device.h include, BSD sed -i syntax, and softc resource-pointer preservation between rig runs.",
  "attempts": 3,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #2: Sun Oct 18 14:03:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/FWO x86_64",
  "runtime_sec": 2400,
  "guest_dirty": 1,
  "build_cmd": "sh /root/fwo/fwpci_prep.sh && sh /root/fwo/build_kernel.sh (nativekernel KERNCONF=FWO) ; cc -O -Wall -o fwpcictl fwpcictl.c",
  "run_cmd": "sh /root/fwo/run2304.sh   (fwpcictl attach dpafail as root)",
  "code_hash": "fe15a597dd10cab0a921f14900768d16933a756bac1fad238730ce4d93396ac5",
  "notes": "Guest had no OHCI hardware: the PCI side is fabricated kobj machinery, the audited code is byte-identical stock. The panic is the INVARIANTS catch of the stale link pointers; the double kfree behind it is subr_bus.c:1306 via the second kobj_delete. Fix validation on the same rig: hunk 3 of fix.diff removes the second delete; A/B captured in run_fixed.log. Reachability quantified in VERDICT.md.",
  "recommended_fix": "Remove the device_delete_child(parent, child) call at fwohci_pci.c:447; fwohci_pci_detach at :446 already deletes sc->fc.bdev (the same child) and NULLs it."
}