{
  "finding_id": "DF-5520",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "isa_dmadone() (isa_dma.c:351-357) bcopy()s the caller-supplied nbytes out of the channels bounce buffer without any clamp against dma_bouncebufsize[chan] -- the mirror of the strict start-side check at isa_dma.c:241-244. KLD proof on the stock kernel with a 64-byte bounce on channel 1: nbytes=0x800 copied 0x800 bytes from beyond the chunk into the modules buffer (silent in-page OOB read; guest alive); nbytes=0x11000 and 0x20000 walked past the mapped low-arena window -> Fatal trap 12 supervisor READ in memmove called from isa_dmadone at 0xffffffff82604000, deterministic across independent boots (2/2). isa_dma_release() also deliberately leaves the stale dma_bounced bit set (XXX comment isa_dma.c:170-178), which arms the same unclamped copy for a later transfers dmadone after a release/re-acquire without dmadone. In-tree callers (fd.c, ppc.c) pass paired sizes today, so this is a latent API-contract defect: any driver size mismatch or lifecycle slip becomes a kernel panic or an info leak of low-memory DMA-arena contents into a driver buffer. Low severity, certain confidence.",
  "exploit_chain": "isa_dma_init(1,64) -> isa_dmastart(READ,64,1) arms dma_bounced -> isa_dmadone(READ,out,N,1) with N>>64 performs the unclamped bcopy: within the mapped page it silently discloses neighboring low-memory DMA-arena contents into the driver buffer; across the mapped window edge it faults the kernel (captured). Gated on a driver contract slip (size mismatch or missing dmadone before release); no unprivileged in-tree trigger.",
  "evidence": "run.log (0x800 silent run with leak dump + primed 0xE7 residue); panic.txt (0x11000: Fatal trap 12, supervisor read, VA 0xffffffff82604000, Stopped at memmove+0x10a from isa_dmadone); run.2.log (0x20000: identical fault address, second boot); leak_sample.txt; fix_run.log (isa_dmadone: count 69632 exceeds bounce buffer size 64, clamping -- no panic, guest alive).",
  "kernel_refs": [
    "sys/bus/isa/x86_64/isa_dma.c:170-178",
    "sys/bus/isa/x86_64/isa_dma.c:241-244",
    "sys/bus/isa/x86_64/isa_dma.c:333-359",
    "sys/dev/disk/fd/fd.c:1844-1864",
    "sys/dev/misc/ppc/ppc.c:1594-1608",
    "sys/dev/misc/ppc/ppc.c:1697-1727"
  ],
  "poc_changes": "Seeded concept only; wrote the harness, discovered the bounce chunk sits at the mapped low-arena edge (0x11000/0x20000 both fault at 0xffffffff82604000) so the fatal size doubles as determinism evidence, added an in-page 0x800 silent variant with a freed-chunk residue primer, added sys/bus.h include + generated isa_if/bus_if/device_if headers.",
  "attempts": 4,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "runtime_sec": 3300,
  "guest_dirty": 0,
  "build_cmd": "cd /root/poc && make -f Makefile.20 && make -f Makefile.20f",
  "run_cmd": "kldload /root/poc/df5520.ko; kldunload df5520; kldload /root/poc/df5520f.ko",
  "code_hash": "df5520.c sha256=70e61b2a31e57a7fa9c7ef949846ef0f6cae459a5e2672a8d77dcf9a68a5c72d",
  "notes": "Impact recorded as panic (deterministic demonstration); the same primitive is an info leak whenever the overread stays mapped (contents on this guest were fresh-page zeros; any prior occupant of that low-memory page -- other drivers DMA buffers, bus_dma low-address pools -- would be returned). One harness artifact during fix validation: re-initializing the same channel in one boot trips the fixs intentional FreeBSD-style double-init panic (isa_dma_init: impossible request) -- documented in fix_run.log Boot A.",
  "recommended_fix": "Clamp isa_dmadones bounce readback to dma_bouncebufsize[chan] (warn on clamp) and clear the stale dma_bounced bit in isa_dma_release().",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Patched nativekernel (fix.diff applied in guest /usr/src, stacked with DF-5519s validation in the same file): the 0x800 run printed isa_dmadone: count 2048 exceeds bounce buffer size 64, clamping with nothing copied past the bounce buffer, and the previously-fatal 0x11000 run printed the clamp (69632 -> 64) with NO panic and the guest stayed up.",
  "fix_evidence": "findings/poc/DF-5520/fix_run.log (boot A + boot B sections); kernel #1 Tue Oct 6 20:57:57 UTC 2026"
}