# DF-4001 — Unclamped VBIOS SCLK/MCLK DPM counts overflow fiji SMC state tables incl. a 384-byte STACK MC-arb table

**File:** `sys/dev/drm/amd/powerplay/smumgr/fiji_smumgr.c`
**Class:** kernel heap + stack OOB write (memcorrupt) — DF-4000 (iceland) / DF-3908/3939/3940 family, fiji variant
**Severity:** High · **Confidence:** certain (source) · runtime hardware-gated

## Build / Run / Expected (on the DragonFly audit guest)

```
./build.sh     # cc -O2 -Wall -I /usr/src/sys/dev/drm/amd/powerplay/inc -o fiji_walks trigger_analysis.c
./run.sh       # ./fiji_walks
```

Expected (see `run.log`): the demonstrator compiles the kernel's own packed
headers (`smu73.h`, `smu73_discrete.h`) so `sizeof`/offsets are the kernel's,
then reproduces the walks with attacker-chosen VBIOS counts (sclk=12, mclk=6):

```
DF-4001a ... sclk_count=12: 4 OOB level writes, 176 bytes past GraphicsLevel[8]
DF-4001b ... mclk_count=6 (Fiji SMU73 bound is 4!): 2 OOB writes, 48 bytes past MemoryLevel[4]
DF-4001c ... sclk=12 mclk=6: 26 PAST the 32-entry table (max linear entry 49 of 32)
            deepest write offset 600B into a 384B stack object -> 216 bytes into the caller frame
```

## Why it is real (source chain, attacker = crafted vBIOS / eGPU flash)

1. VBIOS PowerPlay table (v1) `ucNumEntries` (u8 ≤ 255) is stored verbatim as the
   dependency-table count: `process_pptables_v1_0.c:389` (mclk), `:436` (sclk).
2. Fiji is pinned to this parser: `hwmgr.c:86` (PP_TABLE_V1 default) + `hwmgr.c:127`
   (CHIP_FIJI → fiji_smu_funcs; only CI/TOPAZ drop to PP_TABLE_V0).
3. `smu7_hwmgr.c:783-810` dedups the dep tables into `dpm_table.sclk_table.count` /
   `mclk_table.count` — unclamped against the fixed `dpm_levels[8]` (DF-1166, pass 1).
4. `fiji_populate_all_graphic_levels` (`fiji_smumgr.c:1026-1036`) walks
   `count` entries into `levels[i]` = `smc_state_table.GraphicsLevel[SMU73_MAX_LEVELS_GRAPHICS=8]`
   (`smu73_discrete.h:249`); `[count-1]` store at `:1042`; `pcieDpmLevel` loops `:1055-1057`,
   `:1080-1081`. `struct fiji_smumgr` is a single `kzalloc` (`fiji_smumgr.c:339`) → heap OOB write
   past the object for count > ~45 (GraphicsLevel sits at DpmTable+236 of 1632B).
5. `fiji_populate_all_memory_levels` (`:1238-1247`, `[0]` fixups `:1250/:1257`, `[count-1]` `:1265`)
   into `MemoryLevel[SMU73_MAX_LEVELS_MEMORY=4]` (`smu73_discrete.h:251`) — **count 5 already overflows**.
6. `fiji_program_memory_timing_parameters` (`:1533`) declares
   `SMU73_Discrete_MCArbDramTimingTable arb_regs;` **on the stack** (384 B,
   `entries[8][4]`, `smu73_discrete.h:154-157`) and the nested loops `:1537-1546`
   write `entries[i][j]` for i<sclk_count, j<mclk_count — with 255/255 the walk
   runs to 15,300 B past a 384-byte kernel-stack object (return-address direction;
   write content is VBIOS-derived register values).
7. The clock-stretcher DDT walk additionally READS `GraphicsLevel[j]` for
   j<GraphicsDpmLevelCount (`:1792-1795`) — OOB read of the same count.

Sinks are reached from `fiji_init_smc_table` (`:1964`, `:1988`) during
`pp_hwmgr` init (device attach / resume) — privileged-time execution of
attacker-controlled VBIOS bytes (malicious vBIOS flash or hostile eGPU).

## Fix

`fix.diff` clamps every walk to the SMU73 array bounds (and clamps the level
counts handed to the SMC); compile-validated by full `nativekernel` rebuild
(see `fix_build.log`).
