# DF-5528 — fwohci_pci_detach() swallows child-detach failure, force-deletes the firewire child, and returns unconditional success

File: `sys/bus/firewire/fwohci_pci.c` (pass 2, GLM 5.3 re-audit)
Class: driver lifecycle / error-handling (CWE-754, latent CWE-672 downstream)
Severity: Low — latent trigger, requires FireWire OHCI hardware + privileged unload (or CardBus surprise removal)

## TL;DR

`fwohci_pci_detach()` (sys/bus/firewire/fwohci_pci.c:341-386) discards the return
value of `bus_generic_detach(self)` (line 350), unconditionally force-deletes the
firewire child device (lines 351-354), and always `return 0` (line 385). If any
device on the fwohci→firewire→{sbp,fwe,dcons_crom} chain ever vetoes detach
(returns EBUSY), the parent nonetheless releases the IRQ, unmaps the BAR and
frees the OHCI DMA rings while the firewire child remains DS_ATTACHED and
orphaned with live callouts — a use-after-free / page-0-MMIO-write panic chain,
and `kldunload` reports success with live references left behind.

**Latent today:** in this tree no firewire-bus child can currently veto
(`sbp_detach` sys/dev/disk/sbp/sbp.c:2016-2058, `fwe_detach`
sys/dev/netif/fwe/if_fwe.c:284-295 and `dcons_crom_detach`
sys/dev/misc/dcons/dcons_crom.c:190-207 all `return 0` unconditionally;
`fwdev_destroydev` sys/bus/firewire/fwdev.c:809-817 likewise). The defect is a
structural trap, not a live regression — hence Low/untested.

## How to run / what "reproducing" would mean

1. Requires a machine with a real FireWire OHCI PCI/CardBus controller
   (PCI class 0c/10/10) — there is no such device in the QEMU guest
   (see run.log: `pciconf -l` shows only i440fx/virtio devices).
2. Build the fwohci + firewire + sbp KLDs, attach storage over FireWire so an
   sbp target exists, then make `sbp_detach()` return EBUSY (upstream FreeBSD
   versions of sbp had such guards; this tree does not — add one to test).
3. `kldunload if_fwohci.ko` → observe: "detached" reported, unload completes,
   firewire watchdog callout (firewire.c:375-376, stopped only inside the
   never-completed `firewire_detach` at firewire.c:468-471) fires and executes
   `OWRITE()` through the zeroed `sc->bst/sc->bsh` (fwohci_pci.c:378-379) →
   kernel page-0 write → panic.
4. With the fix (fix.diff), the unload fails with the child's error code and
   nothing is torn down.

`run.sh` documents the hardware-gating check performed on the audit guest.

## Artifacts

- `lifecycle_trace.md` — line-cited callgraph of both the veto and non-veto paths
- `check_guest.sh` / `run.sh` + `run.log` — proof the audit guest has no OHCI device
- `fix.diff` — git-apply-able fix (propagate `bus_generic_detach` error; never
  force-delete a child that vetoed; do not report unconditional success)
- `verdict.json` — machine verdict (status `untested`, hardware-gated)
