# DF-1133 — VERDICT

**Verdict: CONFIRMED via source-trace + userspace harness. On-guest: INCONCLUSIVE (HW-gated — no AMD GPU; amdgpu only in LINT64, not GENERIC).**

## Root-cause confirmation
Two distinct defects in `gfx_v8_0_init_microcode()`:

**(A) Integer-overflow -> heap OOB write (CWE-787 + CWE-190).**
`adev->gfx.rlc.reg_list_format_size_bytes` and `reg_list_size_bytes` are both `u32`
(`amdgpu_gfx.h:76-77`). The allocation at `gfx_v8_0.c:1106-1108`,
`kmalloc(fmt + lst, M_DRM, GFP_KERNEL)`, evaluates `fmt + lst` in **32-bit
arithmetic** (both operands `u32`) and only then promotes the (wrapped) result to
`size_t`. With e.g. `0x80000000 + 0x80000008` the sum wraps to `0x8`, allocating an
8-byte buffer. The copy loop at `gfx_v8_0.c:1117-1118` then writes
`(fmt >> 2) = 0x20000000` dwords into it — a massive heap OOB write with
firmware-controlled content.

**(B) Unvalidated array offset -> heap OOB read (CWE-125).**
`tmp = (u32*)((u8*)rlc_hdr + reg_list_format_array_offset_bytes)` (`gfx_v8_0.c:1115`,
offset read straight from the firmware header) is never bounds-checked against
`fw->datasize`; a crafted offset makes `tmp[i]` read past the firmware blob into
adjacent kernel heap. `amdgpu_ucode_validate()` (`amdgpu_ucode.c:251-260`) only checks
`fw->datasize == hdr->size_bytes` and does not validate either the reg-list sizes or
the array offsets.

## Evidence
- `harness.c` (run as unprivileged `maxx`) shows (A) `0x80000000+0x80000008 -> 0x8`
  (8-byte alloc) vs a loop writing `0x80000000` bytes, and a realistic variant
  `0xffffff00+0x208 -> 0x108` (264-byte alloc) vs a loop writing ~4.29 GB; and (B) an
  unchecked `array_offset=0x40000000` reading ~1 GB past a 4096-byte firmware blob.

## Exploit chain / impact
This is a **write** primitive (A) plus a read primitive (B). On the default GENERIC
kernel it cannot be reached (amdgpu not compiled in); on a system with the amdgpu
driver + a malicious `rlc` firmware, (A) is a kernel heap OOB write with
attacker-shaped content — realistically a **panic** on INVARIANTS-ON GENERIC (slab
poisoning / guard page) and a corruption/code-exec primitive on a non-INVARIANTS
build. No `uid=0` chain was developed because the path is unreachable on this guest
(no AMD GPU / amdgpu absent from GENERIC). The realistic GENERIC-on-real-HW ceiling
is **panic** (or info leak via (B)).

## Fix validation
`fix.diff` casts both sizes to `size_t` before adding (kills the wrap) and validates
`offset + size <= fw->datasize` for both register-list arrays (kills the OOB read),
returning `-EINVAL`.
- `git apply --check -p1` => OK (applies alongside DF-1134 to the same file with no conflict).
- Compiles in the amdgpu module: targeted `make gfx_v8_0.o` built `gfx_v8_0.o`
  (116648 B, `-Werror` clean) with BOTH DF-1133 and DF-1134 fixes applied; full
  `nativekernel` rc=0.
- Harness "WITH FIX" pass: size_t add yields `0x100000008` (huge alloc -> ENOMEM,
  no OOB); offset validation REJECTS the OOB read.
- `fix_status: not_testable` (HW-gated runtime; apply-check + compile + harness fix-demo + trace all pass).

## PoC changes
Evidence pack authored from scratch: `harness.c` (+ WITH-FIX pass), `build.sh`,
`run.sh`, `fix.diff`, `VERDICT.md`, `manifest.json`, logs.

## Kernel refs (confirmed during verification)
`sys/dev/drm/amd/amdgpu/gfx_v8_0.c:1101`, `:1106`, `:1115`, `:1117`;
`sys/dev/drm/amd/amdgpu/amdgpu_gfx.h:76`; `sys/dev/drm/amd/amdgpu/amdgpu_ucode.c:251`;
`sys/dev/drm/amd/amdgpu/amdgpu_ucode.h:91`-`93`.
