# DF-3866 — `emu_intr_unregister` unvalidated index → OOB write cluster at `ihandler[-1]`

**File:** `sys/dev/sound/pci/emu10kx.c:948-978` (+ unchecked callers in `sys/dev/sound/pci/emu10kx-pcm.c`)

## Build

On the DragonFly guest (module `snd_emu10kx` + /usr/src present — this repo's QEMU image):

```sh
cd findings/poc/DF-3866
./build.sh        # builds: rec_cycle (userland trigger tail) + kmod/lay.ko (layout proof)
```

## Run

```sh
./run.sh          # 1) hardware gate  2) kernel layout proof  3) would-be trigger
```

## Expected output

1. **Hardware gate** — on a guest without Creative Labs (0x1102) PCI audio:
   ```
   GATE: no Creative Labs PCI device present
   GATE: cannot open /dev/dsp0: No such file or directory
   GATE: target device absent -> trigger impossible on this guest (no emu10kx hw)
   ```
2. **Kernel layout proof** (needs no hardware — compiles the verbatim field
   prefix of `struct emu_sc_info` against the running kernel ABI):
   ```
   DF3866: sizeof(struct emu_intr_handler)=24
   DF3866: offsetof(reg)=280 irq=288 ih=296 ihandler=304
   DF3866: ihandler[-1] spans [280,304)
   DF3866: PROVEN: ihandler[-1] overlays {reg, irq, ih} ...
   ```
3. On **real hardware**, after root-side slot exhaustion (kldload/kldunload
   cycling of `snd_emu10kx`, which leaks one ihandler slot per pcm child),
   a record-channel START returns -1 and the next STOP feeds
   `emu_intr_unregister(sc, -1)` → OOB read of `ihandler[-1].inte_mask`
   (high dword of `sc->irq`, nonzero → passes the guard) → four NULL OOB
   writes NULL `sc->reg`, `sc->irq`, `sc->ih` → panic at next
   `bus_release_resource`/`bus_teardown_intr` (emu10kx.c:3524-3527).

## Artifacts

- `rec_cycle.c` — userland rec START/STOP cycle (the trigger tail)
- `layout_proof.c` + `kmod/` — kernel module printing the true offsets
- `build.sh` / `run.sh`, `build.log` / `run.log` — recorded guest session
- `fix.diff` — bounds check + caller guards + slot-leak fix (NOT applied; sys/ is read-only)
- `VERDICT.md`, `manifest.json`, `verdict.json`
