# DF-2297 — VERDICT

**Status: REPRODUCED (impact: panic — kernel-mode integer-divide fault from
an ioctl-reachable, unvalidated userspace value). Confidence: certain.**

## Reachability trace (production code, this tree, today)

1. `fwdev.c:504-506` — `case FW_SSTBUF:` `bcopy(ibufreq, &d->bufreq,
   sizeof(d->bufreq))`: the whole `struct fw_isobufreq` (`firewire.h:50-56`;
   `unsigned int nchunk, npacket, psize` per direction) is copied from the
   ioctl buffer with **no validation**. Any open of `/dev/fwU.S`
   (0660 root:operator, `fwdev.c:173-175`) can set arbitrary ints.
2. `fwdev.c:447-461` — `case FW_STSTREAM:` finds a free `it` queue and calls
   `fwdev_allocbuf(fc, it, &d->bufreq.tx)`.
3. `fwdev.c:107` — `b->psize = roundup2(b->psize, sizeof(u_int32_t))`:
   `roundup2(0,4) == 0`; `roundup2(0x80000000,4) == 0x80000000`.
4. `fwdev.c:108-109` — `q->buf = fwdma_malloc_multiseg(fc, sizeof(u_int32_t),
   b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK)`: `psize` reaches
   `fwdma.c` as `int esize` verbatim.
5. `fwdma.c:153-161` — no `esize` validation:
   * `esize == 0`: `esize > PAGE_SIZE` false → `ssize = rounddown(PAGE_SIZE,
     esize)`; `rounddown(x,y)` is `(((x)/(y))*(y))` (`sys/param.h:400`) →
     **`4096 / 0` → integer-divide fault**.
   * `esize == INT_MIN` (psize ≥ 0x80000000): branch still false →
     `ssize = (4096/INT_MIN)*INT_MIN = 0` (no trap: divisor ≠ 0) →
     `nseg = howmany(n, ssize/esize)`; `ssize` is `bus_size_t` (u64), so
     `0 / (u64)INT_MIN = 0`, then `howmany(n, 0)` = `((n)+(0)-1))/(0)`
     (`sys/param.h:396`) → **`/ 0` → integer-divide fault**.

## What was run

KLD harness `df229x.ko` (this pack) with the **unmodified production**
`firewire.c + fwdma.c + fwdev.c` #included (DF-5613 pattern), synthetic
`fc`/queue/cdev state, driving the real `fw_ioctl`:

* **test 3** (`psize=0`): `Fatal trap 18: integer divide fault while in
  kernel mode` … `Stopped at dfw_dma_malloc_multiseg+0x139: idivl %esi,%eax`
  (panic.txt / run.log). Guest dead in DDB (`db>`), ssh hung mid-sysctl —
  the exact "device dies on ioctl" DoS.
* **test 1** (`psize=0x80000000`, the negative-`esize` variant named in the
  finding summary): same fatal trap at `dfw_dma_malloc_multiseg+0x153:
  divq %rsi,%eax` (panic_psize80000000.txt / run_variantB.log) — the *other*
  division site, confirming both cited lines trap.

The two distinct faulting instructions map 1:1 to the two cited lines:
`idivl` (32-bit `PAGE_SIZE/esize`) = fwdma.c:159; `divq` (64-bit
`ssize/esize` after integer promotion of `ssize`) = fwdma.c:160.

## Reconciliation with the pass-2 negative note

Pass 2 did **not** claim unreachability — it declined to re-file because the
negative-`esize` path is "the same crash site/class as DF-2297". Verified:
both variants are reachable today from `FW_SSTBUF` on unmodified production
code; both trap fatally. Not a false positive, not already fixed.

## Fix validation (fix.diff, applied to guest /usr/src, module rebuilt)

* `psize=0` → `STSTREAM err=22 (EINVAL)`, no trap — `fwdev_allocbuf` now
  rejects `psize==0` before the call (`fwdev.c` hunk).
* `psize=0x80000000` → `err=22`, no trap (rejected by the `psize >
  0x7fffffff` arm).
* Direct guard probe (`fwdma_malloc_multiseg(esize=0 / -4096 / n=0)`) →
  `NULL` for all three, no trap (`fwdma.c` hunk is the hard boundary).
* Regression: legit `{nchunk=4, npacket=8, psize=2048}` still allocates and
  streams (`STSTREAM=0 fw_write=0`).
* Guest alive after the full suite (fix_run.log).

## Impact

Unprivileged-but-device-authorized local user (operator group) → instant
kernel panic of the whole machine, on demand, via one `ioctl` pair. DoS
only — no memory corruption on this path (the trap fires before any
allocation is used). Severity High stands (CVSS AV:L/AC:L/PR:L/A:H as
filed).

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