# DF-1166 — Heap overflow: unvalidated VBIOS dependency-table count in `smu7_setup_dpm_tables_v0/v1` (amdgpu smu7_hwmgr.c)

## Verdict
**REPRODUCED (code-level / harness), latent at runtime on this guest.** The bug
is a genuine unbounded-copy-into-fixed-array heap OOB write, confirmed by
source trace and a userspace harness. It is the same class as DF-1141/DF-1150
(VBIOS dep-table count overflow) but in amdgpu powerplay (SMU7 hardware
manager). amdgpu is NOT in `X86_64_GENERIC` and the guest has no AMD GPU, so
the path is **runtime-unreachable** (valid hard blocker). No `exploit.c`: not a
userspace-reachable primitive.

## Mechanism (trigger → primitive → effect)
- **Source array:** `struct smu7_single_dpm_table { u32 count; struct smu7_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER]; }`, `MAX_REGULAR_DPM_NUMBER = 8` (`sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.h:95,99-100`). `smu7_dpm_table` holds sclk/mclk/pcie/vddc/vddci/mvdd tables (`smu7_hwmgr.h:103-109`).
- **Attacker-controlled count:** the dep-table counts (`allowed_vdd_sclk_table->count`, `allowed_vdd_mclk_table->count` in v0; `dep_sclk_table->count`, `dep_mclk_table->count` in v1) come from the VBIOS PowerPlay PP table `ucNumEntries` (u8 up to 255) with only a `!=0` / `>=1` lower-bound check in `process_pptables`.
- **Unbounded loops:**
  - `smu7_setup_dpm_tables_v0` (`smu7_hwmgr.c:666`): sclk dedup `:691`, mclk dedup `:705`, vddc direct-index `:716` (**also OOB-reads `std_voltage_table->entries[i]`**) + `.count` `:723`, vddci `:728` + `.count` `:732`, mvdd `:742` + `.count` `:746`.
  - `smu7_setup_dpm_tables_v1` (`smu7_hwmgr.c:752`): sclk dedup `:784`, mclk dedup `:800`.
- **Effect:** with a crafted PP table (count>8) the writes run off each 8-entry `dpm_levels[]` into the next `smu7_single_dpm_table`, past `smu7_dpm_table`, into the heap-allocated `smu7_hwmgr` (`golden_dpm_table`, `odn_dpm_table`).

## Evidence (harness)
`harness.c` models v0 (5 loops) and v1 (2 loops) with a crafted count of 255.
Result: **v0 = 1235 OOB writes, v1 = 494 OOB writes, total 1729.** With the fix
(`&& i < MAX_REGULAR_DPM_NUMBER`), 0 remain. (Full output in `run.log`.)

## Threat model / reachability
- **Attacker:** malicious/reflashed VBIOS / PP table, or a malicious PCIe AMD GPU; on some configs a root sysfs `pp_table` write. Reached at DPM table setup (`smu7_setup_dpm_tables_v0`/`v1`).
- **On this guest:** NOT reachable. amdgpu not in GENERIC; only QEMU std VGA. Realistic ceiling on physical AMD HW: kernel heap corruption → panic / DoS.

## Exploit chain
None — valid hard blocker (HW-gated; amdgpu absent). No unprivileged guest
syscall injects a PP table.

## PoC changes
Authored from scratch. Deliverables: `harness.c`, `fix.diff`, `build.sh`,
`run.sh`, `VERDICT.md`, `manifest.json`, `env.txt`, `build.log`, `run.log`.

## Recommended fix
`fix.diff` adds `&& i < MAX_REGULAR_DPM_NUMBER` to all seven loops (v0 `:691/:705/:716/:728/:742`, v1 `:784/:800`) and clamps the three v0 `.count` assignments (`:723/:732/:746`) to at most `MAX_REGULAR_DPM_NUMBER`. This **matches the finding proposal** ("cap each loop at MAX_REGULAR_DPM_NUMBER").

## Fix validation (Phase 8)
- `fix.diff` applies cleanly (`git apply --check` OK; 6 hunks, 7 clamps).
- Incremental `amdgpu.ko` build (warm obj): `cd /usr/src/sys/dev/drm/amd && make` → **rc=0**, `smu7_hwmgr.o` (71192 B) rebuilt & re-linked, 0 errors under `-Werror`.
- `fix_status: not_testable` for runtime: amdgpu not in GENERIC, no AMD GPU. Validated at apply + compile level.

## Kernel references (confirmed)
- `sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.h:95` — `MAX_REGULAR_DPM_NUMBER 8`
- `sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.h:100` — `dpm_levels[MAX_REGULAR_DPM_NUMBER]`
- `sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:666` — `smu7_setup_dpm_tables_v0`
- `sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:691,705,716,728,742` — v0 unbounded loops
- `sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:752` — `smu7_setup_dpm_tables_v1`
- `sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:784,800` — v1 unbounded loops
