# DF-5303 VERDICT

**Reproduced: YES — panic inside the production `dump_db()` via the OOB `ir[32]`
index; static chain from the ioctl is airtight; fix correct by inspection
(end-to-end ioctl validation not possible without FireWire hardware).**

## Narrative

The `DUMPDMA` debug ioctl validates the channel number with
`*dmach <= OHCI_MAX_DMA_CH` (`fwohci.c:372`). `OHCI_MAX_DMA_CH` (0x44,
`fwohcireg.h:88`) is a *count* (4 async + 32 IT + 32 IR), so the last valid
index is 0x43; `ch == 0x44` is accepted and both helpers run with it:

* `dump_dma(sc, 0x44)` computes `off = OHCI_IRCTL(0x20) = 0x800` and performs
  `OREAD()`s at 0x800..0x810 — past the end of the 2 KB OHCI register block
  (`struct ohci_registers` spans 0x000-0x7ff, `fwohcireg.h:220-328`).
* `dump_db(sc, 0x44)` computes `dbch = &sc->ir[0x20]` — one past the
  `ir[OHCI_DMA_IRCH]` array (`fwohci.c:2261-2263`). Because `ir[]` is not
  the last member of `fwohci_softc`, the phantom `fwohci_dbch` overlaps the
  softc tail: `ndb` = `maxrec` (non-zero after reset: `speed+8`,
  `fwohci.c:521`), `db_trq.stqh_first` = `sid_buf`, `top` =
  `sid_dma.dma_map` (a live `bus_dmamap_t`), etc. `dump_db()` therefore
  *always* enters its descriptor walk (`fwohci.c:2275-2303`) with
  `dbch->top` pointing at `bus_dmamap_impl` internals instead of an
  `fwohcidb_tr`, and `print_db()` formats whatever memory it lands on
  (`fwohci.c:2347-2402`) — kernel heap contents printed to the console/log
  when it does not fault first.

## Verification

Guest has no FireWire controller, so `fwohci_ioctl()`'s
`devclass_get_softc(firewire_devclass, unit)` cannot resolve a softc
(`fwohci.c:344-347`) — the ioctl entry itself is unreachable on this VM.
The harness (shared with DF-5302; `kern.df5302_mode=2`) calls the
**production** `dump_db()` directly with `ch = OHCI_MAX_DMA_CH` and the
softc tail fields set to their post-`fwohci_init()` shapes (`maxrec=10`,
`sid_dma.dma_map=(void *)0x10` to make the first hop fault at a
recognizable address):

```
DF5303: phantom dbch->ndb(=maxrec)=10 phantom->top(=sid_dma.dma_map)=0x10
Fatal trap 12: page fault while in kernel mode
fault virtual address  = 0x10
fault code             = supervisor read data, page not present
Stopped at  dump_db+0x58:   movq    (%rax),%r9     <- STAILQ_NEXT(pp, link)
```

This proves the OOB index executes and that the walk dereferences the
aliased tail fields unvalidated. `panic.first.txt` records an earlier run
where the phantom `ndb` aliased to 0 and the fault landed in the
`device_printf(fc->dev, "No DB is attached...")` branch — the same OOB index,
faulting one branch earlier.

Two harness iterations were needed to characterize the alias correctly
(`STAILQ_HEAD` is 16 bytes, so `top` lands on `sid_dma.dma_map`, not
`sid_dma.v_addr`/`dma_tag`) — the intermediate non-panicking runs are part
of `attempts`.

## Exploitability

Preconditions: open `/dev/fwN.M` (operator-group on classic layouts — same
preconditions as DF-2300 documented for this driver) on a machine with a
FireWire controller, then `ioctl(fd, DUMPDMA, &(u_int32_t){0x44})`.
Impact: kernel panic (DoS) or, when the walk survives, console/log disclosure
of kernel heap memory through `print_db()` output. Not an arbitrary-read
primitive (walk shape is fixed by the aliased fields). Severity Low.

## Fix validation

`fix.diff`: `<=` → `<` at `fwohci.c:372`. End-to-end re-run of the ioctl is
impossible on this guest (hardware-gated as above), so fix_status is
`not_testable`; the change is provably correct by inspection (valid channel
range 0..0x43), it was compiled into the fixed-module build of the DF-5302
validation cycle (applied at `fwohci.c:372`, see DF-5302 `fix_build.log`),
and `dump_db`/`dump_dma` themselves are only reachable through this check.

## Bottom line

Genuine off-by-one OOB array indexing on a user-reachable ioctl path with a
demonstrated wild-pointer walk in the production function; Low severity
(panic/console-leak ceiling, FireWire hardware required).

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