# DF-5302 VERDICT

**Reproduced: YES — kernel panic (NULL write) via the production code path; fix validated.**

## Narrative

`fwohci_db_init()` builds the DMA descriptor ring for an OHCI channel. When
`dbch->ndb == 0` the per-entry loop (`fwohci.c:1229-1252`) is skipped, so
`dbch->db_trq` stays empty, and the ring-closure statement

```c
STAILQ_LAST(&dbch->db_trq, fwohcidb_tr,link)->link.stqe_next
        = STAILQ_FIRST(&dbch->db_trq);           /* fwohci.c:1253-1254 */
```

dereferences `STAILQ_LAST()` of an empty queue, which DragonFly's
`sys/sys/queue.h` defines as `NULL`. The store then writes 8 bytes of
`STAILQ_FIRST(...)` (also NULL here, but any value would fault the same way)
to address `NULL + offsetof(struct fwohcidb_tr, link)` = **0x0**.

`ndb` is fully user-controlled with no validation anywhere on the path:

* `fwdev.c:504-506` — `FW_SSTBUF` bcopies the user's `fw_isobufreq` into
  `d->bufreq` verbatim (`rx.nchunk`, `rx.npacket`, `rx.psize` unchecked).
* `fwdev.c:108-109` — `fwdev_allocbuf()` calls
  `fwdma_malloc_multiseg(..., b->nchunk * b->npacket)`. With `npacket == 0`
  (or the product == 0 mod 2^32, e.g. 65536×65536) this passes `n = 0`;
  `fwdma.c:153-161` computes `nseg = howmany(0, k) = 0`, allocates nothing,
  and returns a **valid** `am` — so `q->buf != NULL` and `FWXFERQ_EXTBUF`
  is set (`fwdev.c:134`): the allocation "succeeds".
* `fwdev.c:495` — `FW_SRSTREAM` then calls `fc->irx_enable()`.
* `fwohci.c:1606-1608` — `dbch->ndb = ir->bnpacket * ir->bnchunk` (= 0),
  `dbch->ndesc = 2`, `fwohci_db_init(sc, dbch)` → panic.

The TX entry (`FW_STSTREAM` + first `write()` → `fwohci_itxbuf_enable`,
`fwohci.c:1485-1487`) has the identical defect.

## Verification (QEMU guest, DragonFly 6.5-DEVELOPMENT #0, no FireWire hardware)

The file is hardware-gated (no FW controller on the guest), so the evidence
class is a KLD harness in the DF-5230 style: the module `#include`s the
**unmodified** production `fwohci.c` (globals `-D`-renamed against the
kernel-resident copy) and calls the production `fwohci_irx_enable()` with
exactly the `fw_xferq` state the ioctl path produces. Only the bus_space
window (`MEM` tag + a plain kernel-memory block — on x86_64 that is a direct
memory store, `bus_dma.h:186-196`) and the bus itself are synthetic.

Baseline (`run.log`, `panic.txt`):

```
DF5302: calling production fwohci_irx_enable() with bnpacket*bnchunk = 0*8 = 0 ...
Fatal trap 12: page fault while in kernel mode
fault virtual address  = 0x0
fault code             = supervisor write data, page not present
Stopped at  fwohci_db_init.cold.11: movq    $0,0
```

`supervisor write data` at `0x0` inside `fwohci_db_init` — the exact store at
`fwohci.c:1253`. The panic is deterministic; reproduced on a fresh
`vm.sh reset with-src` boot (guest `down` at `db>` afterwards).

## Exploitability

The primitive is a **write of a NULL pointer value to the fixed address 0x0**
(not attacker-redirectable, not content-controlled) → local denial of service
only. Reachable by any user permitted to open `/dev/fwN.M` (operator group on
classic layouts — same preconditions as the already-filed DF-2293/DF-2300 in
this driver family) with three syscalls. No escalation path identified (the
fault virtual address is fixed at 0, which is not mappable from user space on
this platform).

## Fix validation

`fix.diff` (3 hunks):

1. `fwohci_db_init()`: refuse `ndb == 0` (defense in depth; leaves
   `FWOHCI_DBCH_INIT` clear so both callers return their existing `ENOMEM`).
2. `fwohci_irx_enable()`: validate `ndb == 0` → `kprintf` + `EINVAL`.
3. `fwohci_itxbuf_enable()`: same for the TX side.

Applied to the guest's `/usr/src`, module rebuilt against the patched
production source, identical trigger (`fix_run.log`, `fix_build.log`):

```
fwohci: invalid iso rx buffer spec (bnpacket=0 bnchunk=8)
DF5302: SURVIVED fwohci_irx_enable, returned 22 (baseline expects panic; fixed kernel expects EINVAL)
```

Guest stays up. Baseline panic present, patched panic gone, clean error
returned — **fix_status: fixed**.

## Bottom line

Real, trivially reachable, deterministic local kernel-panic DoS in production
code, reproducible on the audit guest through the production function, with a
validated three-hunk fix. Not memory-corruption-exploitable (fixed NULL
address, NULL content).

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