DF-5789 / verdict.json
{ "finding_id": "DF-5789", "status": "reproduced", "verdict": "devclass_delete_driver() (sys/kern/subr_bus.c:888-897) detaches a multi-unit drivers devices one at a time and returns on the first detach veto, after having irreversibly destroyed the bindings of every earlier unit (softc freed by device_set_driver(dev,NULL) at subr_bus.c:2150->1944, sysctl tree freed at 2151, devclass entry dropped at 2146-2147). Verified live: a two-unit driver whose unit 1 vetoes leaves unit 0 permanently dead (state=DS_NOTPRESENT, driver=NULL, softc=NULL, dev.dfveto.0 sysctl tree gone, zombie visible to unprivileged hw.bus.devices readers) while the kld stays loaded and every unload retry fails - the dead unit cannot re-attach because bus_generic_driver_added (subr_bus.c:3007-3016) only re-probes on new-driver registration. Wedge lasts as long as the veto (open umass device / mounted fs / DF-5544-class driver bug) persists; persistent vetoes require reboot. Driver-module unload is root-only, but unprivileged users can hold the veto open. No memory corruption in this path itself.", "reproduced": true, "impact": "dos", "confidence": "certain", "exploit_chain": "kldload rig.ko (dfveto0 detachable + dfveto1 veto) -> kldunload rig -> devclass_delete_driver detaches dfveto0 irreversibly, then dfveto1 returns EBUSY -> unload fails with module still loaded -> dfveto0 dead (state=0/driver=0/softc=0, dev.dfveto.0 gone) -> unpriv walker shows zombie -> every kldunload retry fails -> hardware unit lost until veto clears AND module is manually reloaded; persistent veto => reboot", "evidence": "run5789.log (kldunload Device busy + dev.dfveto.0 subtree gone + walker zombie [110] dfveto0 state=NOTPRESENT); rig.txt dmesg (dfveto0: detached then dfveto1: DETACH VETO, then DF5789: dfveto0 state=0 driver=0 softc=0); fixrun5789.log (patched kernel: same EBUSY but dfveto0 back to state=3 with driver bound)", "kernel_refs": [ "sys/kern/subr_bus.c:888", "sys/kern/subr_bus.c:893", "sys/kern/subr_bus.c:1944", "sys/kern/subr_bus.c:2128", "sys/kern/subr_bus.c:2146", "sys/kern/subr_bus.c:2150", "sys/kern/subr_bus.c:3007" ], "poc_changes": "PoC authored fresh (no seed): KLD with two drivers on nexus (dfveto: identify adds wired units via BUS_ADD_CHILD so nexus_print_child gets its ivars - a raw device_add_child panicked nexus_print_child, which is a nexus.c assumption, not the target bug; dfleak: 8192-byte softc for DF-5790); walker.c reproduces libdevctls hw.bus.devices walk for the unprivileged zombie view; kernel-thread not needed since this path does not self-deadlock.", "attempts": 3, "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", "runtime_sec": 840, "guest_dirty": 0, "build_cmd": "cd /root/df5789 && make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC && cc -O -o walker walker.c", "run_cmd": "cd /root/df5789 && sh run5789.sh", "code_hash": "376cd004b0eed058cce2f3f12a3bf3436ddacfba583102218f7680f222fefc90", "notes": "Recovery semantics verified: after the veto clears and the module finally unloads, reloading the module revives the dead unit (bus_generic_driver_added re-probe), so permanent = for the duration of the veto. Second reserved-ID rig run also validated the DF-5790 fix on the same kernel build. Guest reset to clean-source snapshot after validation.", "recommended_fix": "devclass_delete_driver(): snapshot dcs device list with devclass_get_devices() and on the first device_detach() veto re-probe (device_probe_and_attach) the units already detached before returning the error; see fix.diff", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": true, "fix_verdict": "fix.diff applied to guest /usr/src, quickkernel built (#1 Mon Oct 12 18:33:11 UTC 2026), installed, rebooted: kldunload still correctly fails Device busy but the previously-killed unit returns to DS_ATTACHED with its driver bound and sysctl node present (fixrun5789.log); baseline kernel showed the unit dead with no sysctl node. Bad behavior gone.", "fix_evidence": "fixrun5789.log vs run5789.log; kbuild.log/kinstall.log; dmesg DF5789: dfveto0 ... state=3 driver=0xffffffff82600880 on patched kernel vs state=0 driver=0 softc=0 on stock" } |