# DF-4887 VERDICT

**Status: untested** (device-gated; the audit guest has no AMD GPU —
`pciconf -l` shows no AMD/ATI device, env.txt). Identical treatment to the
just-filed twins DF-4843 (tonga_ih.c) and DF-4854 (vega10_ih.c): the
defect's data source is device DMA into host memory, which no guest
without the hardware can produce.

## Certain by inspection

1. **wptr source is the writeback buffer, same as tonga — this is the
   third instance of the family, not a different shape.**
   `cik_ih_get_wptr` (cik_ih.c:190) reads
   `adev->wb.wb[adev->irq.ih.wptr_offs]`; `use_bus_addr` is false for CIK
   (cik_ih.c:321), so only the wb path exists. Returned with nothing but
   `wptr & adev->irq.ih.ptr_mask` (cik_ih.c:205) — **no 16-byte alignment
   validation**.
2. **The consumer walk steps rptr strictly 16 bytes.** `amdgpu_ih_process`
   (amdgpu_ih.c:154-157) loops `while (ih->rptr != wptr)`; cik advances
   rptr by exactly 16 in both `prescreen_iv` (cik_ih.c:255) and
   `decode_iv` (cik_ih.c:287). A wptr with phase != 0 (mod 16) and no
   overflow bit can never equal rptr → **permanent ithread spin**: 4096
   IVs re-dispatched per lap of the 64 KiB ring, `ih->lock` held
   (amdgpu_ih.c:144), `restart_ih` re-reading the same wptr
   (amdgpu_ih.c:163-165). One CPU pegged, all GPU interrupt delivery dead.
   (Note: if the overflow bit IS set, the recovery transfers the wptr's
   phase into rptr, and after at most one full lap rptr does reach wptr —
   the unbounded spin specifically needs the no-overflow misaligned case,
   same as DF-4843.)
3. **OOB aggravator (DF-4854 shape, 12-byte variant, zero-slack BO).**
   Overflow recovery (cik_ih.c:192-204) computes
   `rptr = (wptr + 16) & 0xFFFF` (cik_ih.c:200) from the *unaligned* wptr.
   With wptr' in [0xFFE4..0xFFEF] (phase 4..15, overflow set), rptr lands
   in [0xFFF4..0xFFFF]; `prescreen_iv`/`decode_iv` then read
   `ring[ring_index .. ring_index+3]`, `ring_index = rptr>>2` up to 0x3FFF
   (cik_ih.c:243-246, 274-277) → dwords 0x4000..0x4002 = **up to 12 bytes
   past the 64 KiB ring**. The CIK ring is a `amdgpu_bo_create_kernel`
   GTT BO of exactly `ring_size` (amdgpu_ih.c:80-88) — no `+8` slack
   (that slack exists only in the `use_bus_addr` coherent path,
   amdgpu_ih.c:61-68). The 12 OOB bytes are decoded as an IV, forwarded to
   `amdgpu_amdkfd_interrupt` (amdgpu_irq.c:170) and dispatched; dispatch
   indices are separately bounds-checked in amdgpu_irq.c, so the blast
   radius is the OOB read + a bogus dispatch (worst case: adjacent mapped
   page data influencing which handler runs, or a fault on unmapped
   vmalloc space → panic).

## Batch questions answered

- wb vs direct reg: **wb** (cik_ih.c:190) — same as tonga; cik_ih never
  reads `mmIH_RB_WPTR` for polling.
- same RB_OVERFLOW path: **yes** — cik_ih.c:192-204, `+16` recovery like
  tonga (`+32` on vega10's 32-byte grid).
- doorbell: **none for CIK IH** — funcs table (cik_ih.c:462-467) has no
  doorbell member of interest; `set_rptr` uses `mmIH_RB_RPTR`
  (cik_ih.c:297-300).
- prescreen/pasid/idr (cik_ih.c:238-257): same `amdgpu_vm_pasid_fault_credit`
  call as tonga (amdgpu_vm.c:3370-3397, idr_find under pasid_lock); the
  credit-drop path advances rptr by 16 — consistent with the walk; no
  cik-unique defect. `!pasid` → process (kernel-context fault), matching
  tonga/upstream.
- process-loop count cap: none in the shared walk (amdgpu_ih.c:154) —
  inherited by all ASICs; already covered by DF-4843's cap recommendation;
  fix.diff here keeps to this file's get_wptr plus the shared-loop cap.

## Why Low / not uid0

The corrupted wptr must come from device DMA (hostile or faulting GPU /
PCIe fault). No unprivileged local software path writes the wb slot. The
OOB read is ≤ 12 bytes, read-only, and its content only steers existing
IRQ handlers whose own indices are validated. Impact ceiling: permanent
GPU-interrupt-thread spin (DoS) + tiny OOB read → Low, consistent with
DF-4843/DF-4854.

## Fix

`fix.diff`: align-normalize the wptr after overflow-bit clear
(`wptr &= ~0xF` with a dev_warn on mismatch, and derive the recovery rptr
from the aligned value), plus a per-invocation entry cap in the shared
walk so no bad wptr can hard-spin the ithread.

## Fix validation

Not possible on this guest (no CIK hardware) — `fix_status: not_testable`;
the diff is authored against the read-only `sys/` tree and never applied
there.

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