# DF-5544 — VERDICT

**Status: reproduced (panic, deterministic under the harness trigger) —
fix validated (fixed). Confidence: certain.**

## The finding

`uhci_pci_detach()` (`sys/bus/u4b/controller/uhci_pci.c:369-412`) calls
`device_delete_children(self)` at **:374 and discards the return value**.
When a child device vetoes detach — `device_delete_children` →
`device_delete_child` → `device_detach(child)` returning `EBUSY` or a
driver error (`sys/kern/subr_bus.c:885-890`, `2128-2145`) — the function
nevertheless:

- stops and resets the controller under the bus lock (:380-387),
- tears down the interrupt (:390-399),
- releases IRQ (:400-403) and I/O (:404-408),
- frees all USB DMA memory and destroys the bus DMA tags
  (`usb_bus_mem_free_all`, :409 → usb_controller.c:1011-1021),
- returns **0** (:411).

`device_detach()` in `sys/kern/subr_bus.c` then completes the "successful"
detach: prints `uhci0: detached`, sets `DS_NOTPRESENT`, and
`device_set_driver(dev, NULL)` **kfrees `dev->softc`** and NULLs it.
The vetoing child is left attached to a driverless parent with freed
IRQ/IO/DMA and freed softc — every subsequent interaction is a NULL-deref
or use-after-free, and the caller (`devclass_delete_driver`, kldunload,
PCI hot-unplug) is told the unload succeeded.

## Verification (guest, real QEMU UHCI)

`-device piix3-usb-uhci` → `uhci0: <Intel 82371SB (PIIX3) USB
controller> port 0xc080-0xc09f irq 10 at device 3.0 on pci0`, healthy
`usbus0`/`uhub0`/`ugen0.1` at boot.

Harness `veto.ko` (this directory): attaches a child device `veto0` to
`uhci0` whose detach method returns `EBUSY` while the uhci driver is
bound — a stand-in for the newbus detach contract — plus a worker
thread that calls `device_detach(uhci0)` (exactly what
`devclass_delete_driver()` at subr_bus.c:897 does) on
`sysctl hw.df5544=1`. v1 of the harness triggered from the sysctl
handler itself and self-deadlocked on the per-CPU `gd_sysctllock`
(handlers run under it; the usb teardown calls `device_sysctl_fini`)
— a harness artifact, documented, not the finding; v2/v3 use the
worker thread.

Observed (run.log, panic.txt — raw serial in panic.txt):

```
usbus0: detached                                <- child 1 deletes cleanly
veto0: DETACH VETO: returning EBUSY             <- child 2 vetoes
uhci0: detached                                 <- swallowed; full teardown
DF5544: device_detach(uhci0) returned 0         <- the lie
DF5544: post: uhci0 driver=(none) state=0
DF5544: uhci0 STILL has 1 child device(s): veto0(attached=1)
[sysctl hw.df5544=2 -> touch parent ctx via orphan]
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0x5458                 <- NULL softc + field offset
Stopped at df5544_thread+0x2a1: movq 0x5458(%rax),%rcx
db>                                            <- guest dead
```

The panic address 0x5458 is `device_get_softc(uhci0)` (NULL, kfree'd by
`device_set_driver`) + the softc field offset — the orphan's only path
to its parent context is freed memory.

## Fix validation (fix.diff)

One-line semantic fix: check and propagate. Applied in guest `/usr/src`,
`make quickkernel` + `make installkernel`, reboot (kernel `#1: Wed Oct 7
09:02:16 UTC 2026`), same harness, same trigger:

- **R1 (veto active)**: `uhci0: child device failed to detach (16);
  refusing controller teardown`; `device_detach returned 16`; post-state
  `driver=uhci state=3`; `pframes_pc.buffer=0xfffff8008df7b000`
  (**unchanged** — DMA intact); **guest alive** after the exact touch
  that panicked the baseline.
- **R2 (retry after child cooperates)**: clean complete detach,
  `uhci0 STILL has 0 child device(s)`, return 0 — honest success,
  guest alive (run.fix.log).

fix_status: **fixed** (baseline reproduced / patched behavior correct).

## Honest scope / severity calibration

The veto child is synthetic: **no in-tree u4b child detach returns
nonzero today** (`usb_detach` returns 0 unconditionally,
usb_controller.c:242), and `device_busy()` propagates `DS_BUSY` up the
tree (subr_bus.c:1846-1857) so a busy child makes `device_detach(uhci0)`
fail before the glue runs. The defect is the violated newbus detach
contract plus its proven consequence (deterministic teardown under a
live child → freed softc/IRQ/IO/DMA with reported success). Trigger
requires the privileged detach paths (kldunload / PCI hot-unplug /
rescan) plus a vetoing child — hence **Low** severity, matching the
same-class precedents DF-5528 (fwohci_pci.c, this pass) and DF-4558
(atapi-cam.c). Code inherited verbatim from FreeBSD (uhci_pci_detach
also ignores the return there).

## Negative results recorded during this pass-2 (not reported)

- **DF-5394 attach-race family**: the attach-error unwind entry
  (:357-359) is dead code on this driver — `uhci_init` returns 0
  unconditionally (uhci.c:653) and `usb_attach` returns 0 unconditionally
  (usb_controller.c:182), so `device_probe_and_attach` cannot fail here;
  the remaining DF-5394 windows (kldunload/hot-unplug of a healthy uhci)
  belong to the usb_controller.c finding.
- **DF-5509 interrupt-arming class**: no UHCI analog — UHCI_INTR=0 is
  written at :281 *before* the handler is armed at :331, the handler
  reads the correct register through tag/handle latched at :276-277 and
  acknowledges everything (uhci.c:1438-1484), never touches
  `sc_bus.bdev` (uhci.c:1420-1422 comment), and iterates an
  `intr_q` that `usb_bus_mem_alloc_all` TAILQ_INIT'd (usb_controller.c:971).
- **LEGSUP/PIRQ/SMI handoff (:351, :84-89)**: single atomic config write
  clearing SMI enables + setting USBPIRQDEN; no park loop, no window.
- **Suspend/resume (:419-420)**: properly wired through
  `uhci_set_hw_power_sleep` → `uhci_suspend`/`uhci_resume`
  (uhci.c:3216-3226, 657-697).
- **`usb_bus_mem_alloc_all` failure path (:261-264)**: self-cleans
  including `lockuninit` (usb_controller.c:989-991); `device_detach`'s
  `DS_ATTACHED` guard (subr_bus.c:2135-2136) prevents any later
  `uhci_pci_detach` on the unattached device — no double free.
- **`ksprintf(sc->sc_vendor…)` (:304-314)**: max 8 bytes into
  `char sc_vendor[16]` (uhci.h:241) — safe.
- **DF-1105** (bdev-NULL crash in `uhci_reset`'s
  `device_printf(sc->sc_bus.bdev, …)` at uhci.c:349/366) and **DF-5296**
  (unvalidated BAR size) — known, not re-reported.

## 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.
