# DF-5520 VERDICT — reproduced

**Bottom line:** `isa_dmadone()` trusts its `nbytes` argument when copying
DMA results back out of the bounce buffer. KLD harness (root context, free
channel 1, 64-byte bounce installed via `isa_dma_init`) called
`isa_dmastart(READ, 64, 1)` then `isa_dmadone(READ, out, N, 1)`:

- N=0x800: 0x800 bytes copied from beyond the 64-byte chunk (in-page, silent)
  — `run.log` + `leak_sample.txt`.
- N=0x11000 and N=0x20000: bcopy walked past the mapped low-arena window →
  **Fatal trap 12 (supervisor read) in memmove from isa_dmadone**, fault VA
  0xffffffff82604000, reproducible on two independent boots — `panic.txt`,
  `run.2.log`.

## Root cause (path:line)

- sys/bus/isa/x86_64/isa_dma.c:351-357 — `bcopy(dma_bouncebuf[chan], addr,
  nbytes)` with no clamp against `dma_bouncebufsize[chan]`; asymmetric with
  the strict start-side check at isa_dma.c:241-244.
- sys/bus/isa/x86_64/isa_dma.c:170-178 — `isa_dma_release()` clears
  `dma_busy` but deliberately leaves `dma_bounced` set (in-code XXX admits
  it); a release/re-acquire without dmadone arms the stale-bounce copy for
  the *next* transfer's dmadone.
- In-tree callers keep sizes paired (fd.c:1844-1864, 1918-1921, 1955-1958,
  1995-1998, 2011-2013; ppc.c:1594-1608, 1697-1727), so the bug is latent —
  an API contract violation away from a panic/leak, including via the stale
  dma_bounced bit.

## Impact

Demonstrated: kernel panic (unbounded read, 2/2 deterministic) and a silent
OOB read of the ISA low-memory DMA arena into a driver buffer (contents on
this guest: fresh-page zeros; the primitive returns whatever previously
occupied that low memory — other drivers' DMA buffers / bus_dma low-address
pools). Gated on a driver contract slip; no unprivileged in-tree trigger.
Low severity / certain confidence.

## Fix validation

`fix.diff` (applies alone or stacked with DF-5519's diff — same file):
- dmadone clamps to the installed bounce size and warns;
- release clears the stale `dma_bounced` bit.
Patched nativekernel rerun: `isa_dmadone: count 2048 exceeds bounce buffer
size 64, clamping` printed, outbuf stays zero past byte 64, guest alive with
the fatal-size variant too — no panic (`fix_run.log`).

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