# DF-5789 VERDICT — REPRODUCED (DoS / kernel state corruption, root- or transient-veto-triggered)

## What was run

Rig KLD `rig.ko` on DragonFly 6.5-DEVELOPMENT (stock kernel #0 Thu Jul 2
06:02:54 UTC 2026, guest `dfbsd`, QEMU/KVM). Driver `dfveto` registered
on nexus via `DRIVER_MODULE`; its identify method adds two children:
unit 0 (detach succeeds) and unit 1 (detach returns EBUSY until
`hw.df5789.cooperate=1`). This is exactly what
`devclass_delete_driver()` sees when any device of a multi-unit driver
vetoes during `kldunload` (or PCI hot-unplug).

## Baseline result (stock kernel) — bug reproduced

`run5789.log` + `rig.txt` (dmesg):

1. `kldload ./rig.ko` → dfveto0 + dfveto1 attach
   (`dev.dfveto.0.%desc` / `dev.dfveto.1.%desc` both present).
2. `kldunload rig` → `kldunload: can't unload file: Device busy`.
   dmesg sequence: `dfveto0: detaching OK` / `dfveto0: detached` **then**
   `dfveto1: DETACH VETO (EBUSY): devclass_delete_driver() already
   killed dfveto0`.
3. In-kernel status (sysctl read): `dfveto0=0xfffff80117494cc0 state=0
   driver=0 nameunit='dfveto0' softc=0` — the device is dead
   (DS_NOTPRESENT, driver unbound, softc freed, sysctl tree freed) while
   the module is STILL LOADED (`sys/kern/subr_bus.c:888-897` returned
   error after the destructive detach of unit 0).
4. Unprivileged view (`./walker`, uses the same hw.bus.devices walk as
   devd): `[110] dfveto0 drv= state=NOTPRESENT parent=0xfffff8008bb7f800`
   — zombie device permanently in the tree.
5. `kldunload` retry #2 fails identically — the unload is wedged for as
   long as the veto persists; unit 0 is skipped forever
   (`dev->driver == NULL` fails the loop condition).
6. Recovery semantics characterized honestly: after clearing the veto
   (`cooperate=1`) the module unloads; reloading it revives dfveto0 via
   `bus_generic_driver_added`. So the damage is *permanent for the
   duration of the veto*; with a persistent veto (open umass device,
   mounted filesystem — things an unprivileged user can hold open) it is
   reboot-class.

## Impact

Availability/DoS: transient detach vetoes during driver unload
(kldunload, PCI/CardBus hot-removal) irreversibly kill every
earlier-numbered unit of the driver while wedging the unload. An
unprivileged user can *cause* the veto half (holding a device open) while
root triggers the unload half. No memory corruption demonstrated; the
proven DF-5544/5562/5635 driver bugs stack on top of this same
non-transactional cascade.

## Fix validation — FIXED

`fix.diff` (authored after verification, never applied to the repo's
`sys/`): `devclass_delete_driver()` snapshots the devclass device list
(`devclass_get_devices`) and, on the first detach veto, re-probes the
units it already detached (`device_probe_and_attach`) before returning
the error.

Applied inside the guest's `/usr/src`, `make quickkernel
KERNCONF=X86_64_GENERIC` → kernel #1 Mon Oct 12 18:33:11 UTC 2026,
`installkernel`, reboot (`kbuild.log`, `kinstall.log`).

Fixed-kernel run (`fixrun5789.log`):
* `kldunload` still fails with `Device busy` (veto honored);
* **dfveto0 is alive**: `dev.dfveto.0.%driver: dfveto`,
  `dev.dfveto.0.%parent: nexus0`, in-kernel `state=3 driver=0xffffffff82600880
  softc=0xfffff80117ac7ac0` — no dead unit, no zombie, no wedge damage;
* final cooperative unload completes cleanly.

Baseline (dead unit + zombie + sysctl tree gone) vs patched (unit alive,
proper EBUSY): fix confirmed.

## Guest

Reset to the clean-source snapshot after validation (`vm.sh reset
with-src`); guest left up, kernel #0 stock.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
