# DF-1296 — VERDICT

**Verdict: REPRODUCED (primitive confirmed at object/harness level; runtime path is hardware-bound and not present on the audit guest).**

## Mechanism (source trace)

The CIK (Bonaire/Hawaii) `powerplay` SMU manager populates the SMC discrete DPM
table from the VBIOS-derived clock/voltage dependency tables.

1. **Attacker-controlled count** — `ci_smumgr.c:1525`:
   ```c
   table->UvdLevelCount = (uint8_t)(uvd_table->count);
   ```
   `uvd_table->count` is `uint8_t` (`hwmgr.h:138`) copied verbatim from the VBIOS
   `ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table.numEntries` at
   `processpptables.c:1097` — no cap against `SMU7_MAX_LEVELS_UVD`.

2. **Fixed-size sink** — `ci_smumgr.c:1527-1528`:
   ```c
   for (count = 0; count < table->UvdLevelCount; count++)
       table->UvdLevel[count].VclkFrequency = uvd_table->entries[count].vclk;
   ```
   `UvdLevel` is `SMU7_Discrete_UvdLevel UvdLevel[SMU7_MAX_LEVELS_UVD]` =
   `UvdLevel[8]` (`smu7_discrete.h:328`, `smu7.h:45`, 16 bytes/entry).

3. **Twins** — `ci_populate_smc_vce_level` (`:1566` → `VceLevel[8]`,
   `SMU7_Discrete_ExtClkLevel`, 8 bytes/entry) and `ci_populate_smc_acp_level`
   (`:1598` → `AcpLevel[8]`). `vce_table->count` `uint8_t` (`hwmgr.h:184`),
   `acp_table->count` `uint32_t` (`hwmgr.h:148`) — both uncapped.

`count > 8` writes past the fixed array into the following `SMU7_Discrete_DpmTable`
fields (`VceLevel`, `AcpLevel`, `SamuLevel`, `Ulv`, `SclkStepSize`, `Smio[]`,
boot-level fields, …) with attacker/VBIOS-shaped content (`VclkFrequency`,
`DclkFrequency`, `MinVddc`, dividers). In the broader object layout these are
followed by `power_tune_defaults`-derived pointers/data that are subsequently
dereferenced — a corruption → controlled-deref chain.

## Primitive characterization

- **Write size:** up to `(count - 8) * 16` bytes (UVD) past `UvdLevel[8]`, with
  attacker-shaped 32-bit `VclkFrequency`/`DclkFrequency` fields.
- **Target:** the `SMU7_Discrete_DpmTable` heap object; overflow corrupts sibling
  level arrays and downstream tunable pointers.

## Harness proof

`harness.c` builds a `SMU7_Discrete_DpmTable` slice (`UvdLevel[8]` + adjacent
`VceLevel[8]` + a guard) and replays the loop with VBIOS `numEntries = 40`.
Output (`run.log`):
```
[DF-1296] attacker VBIOS UVD numEntries=40 (max array=8)
[DF-1296] BUG CONFIRMED: loop wrote UvdLevel[0..39] -> 32 entries (512 bytes) overflow past UvdLevel into VceLevel/AcpLevel/SamuLevel/Ulv/Smio/...
[DF-1296] adjacent VceLevel[0] corrupted: YES (overflow into sibling field)
```
(GCC independently flags the OOB with `-Waggressive-loop-optimizations` during the
harness build — the compiler itself detects the out-of-bounds write.)

## Why not a live in-kernel reproduction (valid hard blocker)

The CIK `powerplay` path runs only on AMD Sea Islands GPUs. `pciconf -l` on the
audit guest shows `vgapci0 chip=0x11111234` (QEMU std-vga), **not** an AMD GPU; the
amdgpu/ci driver never attaches, so `ci_populate_smc_uvd_level` never runs here.
Live trigger conditions: a system with a CIK AMD GPU whose on-card VBIOS power
table has `numEntries > 8` (malicious/corrupt VBIOS, or a crafted image on a
passed-through GPU). Primitive proven at the object/harness level. Escalation to
`uid=0` requires the primitive to fire in a running kernel — not demonstrable on
this guest because the GPU driver never attaches. Honest reported impact: the heap
corruption primitive itself.

## Fix

`fix.diff` clamps each level count to its fixed array size before the loop:
```c
table->UvdLevelCount = (uvd_table->count > SMU7_MAX_LEVELS_UVD) ?
    SMU7_MAX_LEVELS_UVD : (uint8_t)(uvd_table->count);
```
(and likewise `VceLevelCount`/`SMU7_MAX_LEVELS_VCE`, `AcpLevelCount`/`SMU7_MAX_LEVELS_ACP`).
**Validated:** `patch -p1` succeeds (all 3 hunks); `ci_smumgr.c` compiles cleanly
under `-Werror` and the **full `amdgpu.ko` module links** in-tree (the link command
includes `ci_smumgr.o`). Supersedes any pre-verification proposal by covering all
three twins (UVD/VCE/ACP).

## Fix-validation status

`not_testable` for a *live* before/after (PoC path cannot run on the guest — no AMD
GPU). Evidence the fix is correct: (1) harness before/after shows the clamp keeps
the loop in `UvdLevel[0..7]`; (2) `ci_smumgr.c` with the fix compiles under
`-Werror` and `amdgpu.ko` links in-tree.
