# DF-4172 VERDICT — unvalidated device-fed completion index in iir_intr

**Status: untested on this guest (hardware-gated). Bug existence: certain from code trace.**

## Reproduced?

No runtime reproduction was possible: the DragonFly audit guest
(`DragonFly dfbsd 6.5-DEVELOPMENT #0 Thu Jul  2 06:02:54 UTC 2026 … X86_64_GENERIC`)
has no Intel/ICP RAID controller — `gate_check.log` shows `/dev/iir` absent,
no PCI device with vendor 0x1119 / Intel 0x0600, and the only CAM SIMs are
QEMU's `ata`/`ahci`. `iir_intr` cannot be entered without the card, and even
with the card the malformed value must be written by the *device*, not by any
syscall. The gate itself is proven by `gate_check.log`.

## Code trace (why the bug is certain)

1. `gdt_mpr_get_status()` returns the **raw** `GDT_MPR_EDOOR` doorbell byte
   (sys/dev/raid/iir/iir_pci.c:402-407). This is device-controlled memory-mapped state.
2. `gdt_mpr_intr()` (iir_pci.c:410-449) clears only bit 0x80
   (`ctx->istatus &= ~0x80`, line 418-419) — the remaining value is fully
   device-chosen, range [0, 127].
3. `iir_intr()` (iir.c:1522-1645) special-cases only `GDT_ASYNCINDEX`(0) and
   `GDT_SPEZINDEX`(1) (iir.c:1562, 1568) and then, with **no range check**:

       gccb = &gdt->sc_gccbs[ctx.istatus - 2];      /* iir.c:1580 */

4. `sc_gccbs` is `kmalloc(sizeof(struct gdt_ccb) * GDT_MAXCMDS)` with
   `GDT_MAXCMDS == 124` (iir.c:250-251, iir.h:77). Driver-generated command
   indices are `i + 2` for i ∈ [0,123] → valid istatus ∈ [2,125]
   (iir.c:256-258). A device-fed istatus of 126 or 127 yields array index
   124/125 — up to 2 × ~390 bytes past the end of a ~47.6 KB kmalloc block.
5. Consequences on the OOB `gccb`:
   - `gc_flags` is read OOB (iir.c:1583).
   - If it reads as `GDT_GCF_UNUSED`(0): `gdt_free_ccb()` runs `SLIST_REMOVE`
     of a non-list-member (iir.c:661) → the SLIST walk runs off the end
     (NULL deref) or corrupts the free list, and writes `gc_flags = 0` OOB
     (iir.c:660).
   - If it reads as `GDT_GCF_IOCTL`(4): `ucmd = gccb->gc_ucmd` (OOB pointer,
     iir.c:1600) is written through (`ucmd->status/info/complete_flag`,
     iir.c:1608-1610) and up to `param_size` (≤3072) bytes are `bcopy`ed to
     `ucmd->data` (iir.c:1613-1627) → wild kernel write.
   - Otherwise (`default`, iir.c:1637-1639): `gdt_sync_event` dereferences the
     garbage `gccb->gc_ccb` — `callout_stop(ccb->ccb_h.timeout_ch)`
     (iir.c:1804) and `xpt_done(ccb)` (iir.c:1859) on a wild pointer.

## Why not false-positive

The two-element overflow window is small but real, and the driver itself
documents (via `gc_cmd_index = i+2`) that indices up to 125 are the only legal
ones — there is simply no enforcement at the consumption site. FreeBSD's
descendant of this code (gd_th) gained exactly this check.

## Impact ceiling

Malicious/compromised RAID controller or PCIe peer → kernel memory corruption
in interrupt context (list corruption + wild writes). Not reachable by
unprivileged or even privileged *software* alone. Severity Low per the
audit rubric ("requires specific hardware"); bucket: memcorrupt.

## Fix validation

fix.diff authored post-trace; `git apply --check` passes. A kernel
build+boot validation is not possible on this guest (no hardware to trigger
the corrected path); fix_status = not_testable.

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