# DF-1305 — kv_init_graphics_levels heap OOB write/read (radeon DPM)

## Verdict
**NOT TESTABLE AT RUNTIME on this guest — confirmed real latent vulnerability in source.**

## Mechanism (confirmed by source trace)
`sys/dev/drm/radeon/kv_dpm.c:2344` `kv_init_graphics_levels()` programs the
graphics DPM levels from `rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk`.

- Line 2355: `for (i = 0; i < table->count; i++) { ... }` where
  `table->count` is `ucNumEntries` parsed from VBIOS (a `u8`, 0–255) — see
  `r600_dpm.c` `radeon_atom_get_voltage_dependency_table`.
- Inside the loop, indices flow into two fixed arrays in `struct kv_power_info`
  (`kv_dpm.h:106`):
  - `kv_set_divider_value` / `kv_set_vid` / `kv_set_at` write
    `pi->graphics_level[i]` (`SMU7_Fusion_GraphicsLevel graphics_level[SMU__NUM_SCLK_DPM_STATE]`,
    `SMU__NUM_SCLK_DPM_STATE` = **8** at `kv_dpm.h:26`/`ci_dpm.h:28`).
  - `kv_set_at(rdev, i, pi->at[i])` (line 2366) **reads** `pi->at[i]` where
    `at` is `u32 at[SUMO_MAX_HARDWARE_POWERLEVELS]` and
    `SUMO_MAX_HARDWARE_POWERLEVELS` = **5** (`sumo_dpm.h:28`).
- So `count > 5` → **OOB read** of `at[i]`; `count > 8` → **OOB write** of
  `graphics_level[i]` (corrupting whatever follows it in `kv_power_info`, e.g.
  `acpi_level`, `uvd_level[]`, etc.).  The `high_voltage_t` early-break guard is
  `kzalloc`'d to 0 and does not bound `count`.
- The `else` branch (line 2375) has the same shape with
  `sumo_sclk_voltage_mapping_table.entries[SUMO_MAX_HARDWARE_POWERLEVELS=5]`.

## Why it does not reproduce on this guest
- radeon is **not** in `X86_64_GENERIC`; only the loadable `radeon.ko`, **not
  loaded**.
- No AMD GPU present (`vgapci0` = QEMU std-VGA `1234:1111`).  radeon never
  attaches; the DPM init path (called from `kv_dpm_enable`/`kv_dpm_hw_init`)
  never runs.  (Case d.)

## Severity / realistic ceiling
On a host with an affected Kaveri/Kabini/Mullins APU (radeon KV family) whose
VBIOS reports >8 SCLK/voltage entries, this is a kernel heap OOB write in the
DPM bring-up path → heap corruption / panic; attacker-shaped entries (clock +
voltage from VBIOS) partially control the written bytes.  Firmware-data-driven,
so realistic vector is a malformed/malicious VBIOS.

## Fix (see fix.diff)
1. Bound the if-branch loop to `i < SMU__NUM_SCLK_DPM_STATE` (prevents the
   `graphics_level` OOB write).
2. Guard the `pi->at[i]` read with `i < SUMO_MAX_HARDWARE_POWERLEVELS`.
3. Bound the else-branch loop to `SUMO_MAX_HARDWARE_POWERLEVELS` (covers the
   `entries[]` array).
Compile-validated (radeon module build).  Runtime not exercisable on GPU-less
guest.
