# DF-5519 VERDICT — reproduced

**Bottom line:** on the stock production kernel (X86_64_GENERIC, DIAGNOSTIC
off), every channel-number check in `sys/bus/isa/x86_64/isa_dma.c` is
compiled out. A KLD harness (root context, mirroring what any driver,
hint-parsed config or third-party module supplies) demonstrated all three
consequences: (a) `1<<34` aliases bit 2 — `isa_dma_acquire(34)` returned
EBUSY and `isa_dma_release(34)` cleared a live channel's `dma_inuse` bit;
(b) `isa_dma_acquire(9)`/`isa_dma_init(9,…)` accept chan ≥ 8 with no error;
(c) the `isa_dma_init(8, 0x1000)` OOB static writes — `dma_bouncebufsize[8]`
(at `&dma_bouncebuf[0]`-low32 per the .bss layout) and `dma_bouncebuf[8]`
(at `&ram_devclass`) — forged channel 0's bounce pointer, and the subsequent
`isa_dmastart` bounce `bcopy` wrote kernel data to the forged address
`0xffffffff00001000` (panic captured in `panic.txt`). The fault VA's low 32
bits equal the `bouncebufsize` parameter — the write destination was chosen
by the OOB write, not by any allocation.

## Why it happens (path:line)

- isa_dma.c:98-104, 140-143, 162-168, 191-194, 217-227, 336-342 — every
  `chan & ~VALID_DMA_MASK` check is `#ifdef DIAGNOSTIC`.
- isa_dma.c:127-128 (`dma_bouncebufsize[chan]`, `dma_bouncebuf[chan]`),
  242-243, 288 (`dmapageport[chan]` OOB read → wild `outb`) — unchecked
  static-array indexing.
- isa_dma.c:145/149/170/180/225/239/258/344/348/351/435/441/485/488 —
  `1 << chan` on `u_int8_t` masks / int shift: undefined/wrapping for
  chan ≥ 32.
- isa_dmastatus (isa_dma.c:428) and isa_dmastop (isa_dma.c:483) had **no**
  validation at all, not even DIAGNOSTIC.
- Channel provenance in-tree: fd.c:620 / ppc.c:1891 (`rman_get_start` of
  DRQ); isa_common.c:884-908 `isa_set_resource` never bounds the DRQ value;
  isavar.h:174-182 exports the KPI to any KLD.

## Exploit chain (demonstrated to the wild-write step)

1. `isa_dma_init(0, 1024)` — legitimate victim channel with real bounce buffer.
2. `isa_dma_init(8, V)` — OOB write `dma_bouncebufsize[8] = V` lands on
   `dma_bouncebuf[0]`'s low 32 bits (array-adjacency verified via `nm`);
   OOB write `dma_bouncebuf[8] = <heap ptr>` clobbers `ram_devclass`
   (devclass_t — a type-confusion target for later devclass walks).
3. `isa_dmastart(ISADMA_WRITE, buf, n, 0)` with a >16MB buffer → bounce path
   trusts the forged pointer → `bcopy(buf, forged, n)` → **kernel write to a
   semi-controlled address** (low 32 bits = caller-chosen `V`; captured
   supervisor-write panic).
4. `1<<chan` wrap additionally allows freeing/clearing a live channel's
   state (`release(34)` cleared chan 2's inuse bit — captured).

Full uid0 escalation was **not** pursued: the trigger is gated on privileged
configuration/buggy-driver input (no unprivileged in-tree path supplies
chan>7 on this guest — no fdc/ppc devices in X86_64_GENERIC; PnP masks are
byte-wide so PnP yields 0..7). The primitive (parameter-controlled pointer
forgery + 8-byte heap-pointer write onto `ram_devclass`) is real
memory corruption; the honest ceiling is "kernel memory corruption available
to whatever context can name a DMA channel" — root/loader today, any future
driver that forwards user-influenced DRQ values tomorrow.

## Fix validation

`fix.diff` makes the bounds check unconditional in all 8 entry points
(`EINVAL` / early return / `-1` as fits each signature; keeps the
double-init "impossible request" panic, matching FreeBSD's unconditional
checks). Patched-kernel rerun: `acquire(9)`/`acquire(34)` → EINVAL with
"out of range" on the console, no aliasing, `init(8,…)` → EINVAL, no
forged-pointer panic (`fix_run.log`). Validated on a `nativekernel` build of
X86_64_GENERIC with fix applied (combined with DF-5520's clamp — same file).

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