# DF-5519 — isa_dma.c: DMA channel validation is DIAGNOSTIC-only → OOB static writes / forged bounce pointer / `1<<chan` wrap

**File:** `sys/bus/isa/x86_64/isa_dma.c` (pass 2)
**Verdict:** reproduced (see `verdict.json`, `VERDICT.md`)
**Kernel:** DragonFly 6.5-DEVELOPMENT `X86_64_GENERIC` (no `options DIAGNOSTIC` — the panics at isa_dma.c:99/141/163/192/218/337 are compiled out)

## What was proven on the running production kernel

1. **`1 << chan` wraps for chan ≥ 32** — `isa_dma_acquire(34)` returns `EBUSY`
   while channel 2 is acquired (x86 32-bit `shl` masks the count to 5 bits);
   `isa_dma_release(34)` then **clears channel 2's `dma_inuse` bit**, i.e. a
   bogus channel number frees a live driver's channel.
2. **chan ≥ 8 silently accepted** — `isa_dma_acquire(9)` returns 0.
3. **OOB write forges another channel's bounce pointer** (`.bss` layout
   confirmed with `nm /boot/kernel/kernel`:
   `dma_bouncebufsize[8]` at 0xffffffff819fb260, `dma_bouncebuf[8]` at
   0xffffffff819fb280, `ram_devclass` at 0xffffffff819fb2c0):
   `isa_dma_init(8, 0x1000)` writes `dma_bouncebufsize[8]` onto the **low 32
   bits of `dma_bouncebuf[0]`**, and `dma_bouncebuf[8]` (an 8-byte kernel
   heap pointer) onto **`ram_devclass`** (a `devclass_t`). The follow-up
   `isa_dmastart(WRITE, hibuf, 256, chan=0)` bounce-path `bcopy` then writes
   to the forged pointer — captured panic:

   ```
   fault virtual address = 0xffffffff00001000     <- original ptr high32 | bouncebufsize param (0x1000)
   fault code = supervisor write data, page not present
   Stopped at memmove+0x2b: movq %rdx,(%rdi)      <- bcopy in isa_dmastart
   ```

   The fault address contains **exactly the attacker-supplied
   `bouncebufsize` parameter in its low 32 bits** — proof that the OOB write,
   not the legitimate allocation, chose the write destination.

## Reachability (honest)

The `chan` argument is driver-supplied. In-tree callers take it from
`rman_get_start(res_drq)` (fd.c:620, ppc.c:1891); `isa_set_resource`
validates only the rid count, never the DRQ **value** (isa_common.c:890-902).
PnP masks are byte-wide so PnP yields 0..7; kernel hints, PnP-BIOS tables and
KLDs are root/loader-controlled. So the demonstrated corruption requires a
misconfigured or buggy driver/module — the in-tree unprivileged paths on this
guest (no fdc/ppc in X86_64_GENERIC) do not reach it. Severity Medium:
full kernel-memory-corruption primitive once a chan>7 reaches the API.

## Files

- `df5519.c` / `df5519_panic.c` — KLD harnesses (clean / fatal)
- `build.sh`, `run.sh` — exact build & run
- `run.log` — clean-run serial output
- `panic.txt` — forged-pointer wild-write panic
- `env.txt` — uname, symbol map, config checks
- `fix.diff` — unconditional chan validation (all 8 entry points)
- `VERDICT.md`, `manifest.json`, `verdict.json`
