# DF-2305 VERDICT — bus_dma_tag_create failure path leaks BAR, IRQ, handler

* finding: DF-2305, fwohci_pci.c:320-324 (fwohci_pci_attach)
* status: **reproduced** (forced-failure interposition at exactly the
  fwohci_pci.c:300 bus_dma_tag_create call; resource accounting captured
  against the real attach/detach code)
* impact: leak (permanent PCI memory-BAR + IRQ resource leak, interrupt
  handler left registered on a softc that new-bus frees after the failed
  attach; device can never attach again)
* confidence: certain (defect + behavior); trigger probability low (see
  reachability)

## Line-accurate comparison (stock tree)

* :267-272 MEM BAR alloc fail -> return ENXIO (nothing else held: OK)
* :278-284 IRQ alloc fail -> **fwohci_pci_detach(self)** -> return ENXIO
* :287-298 bus_setup_intr fail -> **fwohci_pci_detach(self)** -> return ENXIO
* :300-324 bus_dma_tag_create fail -> `return (ENOMEM);` with NO detach —
  at this point sc->bsr, sc->irq_res and the registered sc->ih are all held
* :326-332 fwohci_init fail -> **fwohci_pci_detach(self)** -> return EIO

The :320 path is the only one that skips cleanup.

## Mechanical reproduction (this run)

Rig accounting is built into the fabricated pci bus methods the stock
driver dispatches to (bus_alloc_resource / release_resource /
setup_intr / teardown_intr counters; a rman-style BAR-conflict model:
a still-outstanding BAR refuses the next allocation).

* A (the bug): `fwpcictl attach dmatagfail` -> real attach, tag creation
  fails at :300/:320. Output: rc=12 (ENOMEM), deltas MEM 1/0 IRQ 1/0,
  setup 1 / teardown 0, live_handlers=1. Console: "fwohci_pci_attach:
  Could not allocate DMA tag - error 12" followed by NOTHING (no release
  lines). LEAKED.
* C (what the missing call would do): rig-only `fwohci_pci_detach` with
  the leaked pointers still in the softc -> teardown_intr ok,
  release_resource(IRQ) ok, release_resource(MEM) ok; counters 1/1 1/1,
  live=0. The cleanup is exactly one call away.
* D (sibling comparison): `fwpcictl attach irqfail` -> irq alloc fails at
  :280 -> the sibling path runs detach: deltas MEM 1/1, IRQ 0/0, balanced.
* B (permanence): fresh leak, then a clean re-attach attempt ->
  bus_alloc_resource(MEM) refused ("BAR 0xf0000000 still outstanding:
  rman conflict"), "fwohci0: Could not map memory", rc=6/ENXIO; and the
  failed re-attach assigns sc->bsr = NULL (fwohci_pci.c:267), orphaning
  the BAR — not even a manual detach can recover it afterwards.

## Additional impact note (softc lifetime)

On the real failure, new-bus finishes the failed attach with
`device_set_driver(dev, NULL)` (subr_bus.c:2121), which kfree()s the
driver softc (subr_bus.c device_set_driver). The still-registered
fwohci_intr handler therefore points at freed memory: on shared-IRQ
hardware every interrupt on that line dispatches into a freed softc
(interrupt-context UAF; mitigated only by fwohci_intr early-returning
when the (freed) sc->intmask reads zero). The BAR/IRQ leak alone already
permanently prevents re-attach, as demonstrated.

## Reachability honesty

Requires (a) real OHCI-1394 PCI hardware (none on this guest; the PCI
side is fabricated, the audited code is stock), and (b) a failing
bus_dma_tag_create: on x86_64 the tag kmalloc is M_INTWAIT (cannot
fail), but with lowaddr=BUS_SPACE_MAXADDR_32BIT on a host with >4GB RAM
the tag is marked BUS_DMA_BOUNCE_LOWADDR and, with BUS_DMA_ALLOCNOW,
`alloc_bounce_zone`/`alloc_bounce_pages` can return ENOMEM under real
memory pressure (sys/platform/pc64/x86_64/busdma_machdep.c:820-860) —
i.e. exactly the machines this driver targets. Probability per boot is
low; the code defect and its consequence are deterministic.

## Fix validation (A/B)

fix.diff hunk 2 adds `fwohci_pci_detach(self);` before the ENOMEM return
(mirroring the sibling paths). Fixed kernel (run_fixed.log):
* `attach dmatagfail` -> rc=12 still, but deltas MEM 1/1 IRQ 1/1,
  teardown 1, live_handlers=0 — balanced.
* immediate re-attach probe (`attach irqfail`): MEM 1/1 with ZERO
  conflicts — the BAR was released, re-attach is unblocked (reaches the
  irq step, "Could not allocate irq", sibling path handles it).
Baseline vs fixed: leak + permanent conflict vs balanced + unblocked.

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