# DF-2304 — Double-free / UAF in fwohci_pci_add_child error path

Verification pack for finding DF-2304 (`sys/bus/firewire/fwohci_pci.c:446-447`).
Medium / memcorrupt. Claim: when `device_probe_and_attach(child)` fails,
`fwohci_pci_add_child` calls `fwohci_pci_detach(parent)` (which deletes
`sc->fc.bdev == child` via `device_delete_child` at fwohci_pci.c:352, freeing
the child), and then calls `device_delete_child(parent, child)` AGAIN at
fwohci_pci.c:447 on the freed pointer.

## Verdict (short)

REPRODUCED on the verbatim-interposition harness (kernel-compiled,
`fwohci_pci.c` TU-included unmodified): with `device_probe_and_attach`
interposed to fail exactly at its fwohci_pci.c:442 call inside a REAL
`fwohci_pci_attach` run, the REAL chain

```
fwohci_pci_attach -> fwohci_init (real, emulated OHCI regs+PHY)
-> bus_generic_probe -> firewire identify (bus_generic_identify)
-> BUS_ADD_CHILD -> fwohci_pci_add_child (the verbatim function)
-> device_add_child("firewire")   [REAL new-bus child]
-> [interposed] device_probe_and_attach FAIL (ENXIO)
-> fwohci_pci_detach(parent)      [device_delete_child #1, from :352]
-> device_delete_child(parent, child)   #2, from :447 -- FREED POINTER
```

panics the INVARIANTS kernel: `panic: Bad link elm 0xfffff8011769c6a0
prev->next != elm` inside the second `device_delete_child`, backtrace
`fwohci_pci_add_child+0xfd <- bus_generic_identify <- bus_generic_probe`.
Both deletes were logged by the pure logging wrapper with the same freed
child pointer (see run.log / panic.txt).

**Reachability is honestly latent**: the error branch requires
`device_probe_and_attach` of the firewire child to fail, but the child is
created BY the firewire driver's own identify method (so its probe always
matches: `firewire_probe`, firewire.c:313-317, returns 0 unconditionally),
and `firewire_attach` (firewire.c:383-416) has no failure return. All
allocation steps below it use M_INTWAIT (cannot fail). No unprivileged
or remote input reaches this branch. The defect is real memory corruption
in the code, demonstrated mechanically; it is NOT currently reachable
through natural inputs, hence no privesc.

## Rig

`fwpci_harness.c` (this pack) #includes the unmodified
`sys/bus/firewire/fwohci_pci.c`; interposes exactly three call sites
(`device_probe_and_attach`, `bus_dma_tag_create`, and a pure logging
wrapper on `device_delete_child`); fabricates the PCI externalities with
a real kobj bus class (bus/pci methods: read_ivar, alloc/release_resource,
setup/teardown_intr, read/write_config). The fake fwohci device shell
carries the real "fwohci" devclass (from the verbatim DRIVER_MODULE) and a
kobj class whose bus_add_child method IS the verbatim fwohci_pci_add_child,
so the stock `bus_generic_probe` inside the stock attach dispatches the
real identify chain. OHCI externalities (register file + PHY emulation)
come from the DF-2300 fwohci_harness.c rig, also installed. Root-only
control device `/dev/fwpcictl0`.

## Files

* `fwpci_harness.c/h` — kernel rig (verbatim TU + interposition + PCI fabrications)
* `fwohci_harness.c/h` — the DF-2300 rig, extended to export `fh_regs`
* `fwpcictl.c` — userland driver
* `fwpci_prep.sh`, `build_kernel.sh`, `build_fix.sh` — guest prep + builds
* `run2304.sh` — the trigger (root): `fwpcictl attach dpafail`
* `run.log` — full trigger output (note: ssh session dies at the panic)
* `panic.txt` — serial-console panic + backtrace (the decisive evidence)
* `run_fixed.log` — fixed-kernel A/B
* `fix.diff` — combined 3-hunk fix (hunk 3 removes the :447 delete)
* `env.txt`, `build.log`, `manifest.json`, `verdict.json`

## Reproduce

```
# on the host, from this pack:
scp -F dfbsd-qemu/config * dfbsd:/root/fwo/
vm.sh run_root 'sh /root/fwo/fwpci_prep.sh && sh /root/fwo/build_kernel.sh'
vm.sh down && vm.sh up
vm.sh run_root 'sh /root/fwo/run2304.sh'   # guest panics; capture with vm.sh log
```
Expected: console shows both delete log lines (fwohci_pci.c:352 then :447,
same child pointer), then `panic: Bad link elm ... prev->next != elm`.

Fixed kernel: `vm.sh run_root 'sh /root/fwo/build_fix.sh'`, reboot, re-run
run2304.sh: attach returns 0, exactly ONE delete (line 354 post-patch), no
panic, resources balanced.
