# DF-1167 — smu7_setup_dpm_tables_v0 NULL-deref + OOB read

## Finding

`smu7_setup_dpm_tables_v0()` at `sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:666`
reads `std_voltage_table = hwmgr->dyn_state.cac_leakage_table` (line 673-674) and
then, in the loop at lines 716-721, indexes `std_voltage_table->entries[i]`
bounded by `allowed_vdd_sclk_table->count` — **not** by `std_voltage_table->count`
and **without** a NULL check.

`cac_leakage_table` is set to `NULL` at
`sys/dev/drm/amd/powerplay/hwmgr/processpptables.c:1470` and only assigned a
value when `ptable5->usCACLeakageTableOffset != 0` (line 1472). A PowerPlay
table that omits the CAC leakage table therefore leaves the pointer NULL, and
the next call into `smu7_setup_dpm_tables_v0` dereferences NULL at line 718 →
**kernel panic**.

If the table is present but shorter than `vddc_dependency_on_sclk`, the loop
also performs an **out-of-bounds read** past the allocated `cac_leakage_table`.

## Affected code

`sys/dev/drm/amd/powerplay/hwmgr/smu7_hwmgr.c:673-674, 716-721`

## Reproducibility on this audit guest

The `amdgpu` / `powerplay` driver is **optional** (`optional amdgpu drm` in
`sys/conf/files`); it is **not compiled into `X86_64_GENERIC`** and the QEMU
guest has **no AMD GPU**. The bug therefore cannot be triggered live on the
audit guest. The reproducibility proof is:

1. **Source-level trace** confirming the data flow NULL → deref
   (`processpptables.c:1470` NULL assignment, no NULL check at `smu7_hwmgr.c:718`).
2. **Userspace harness** (`harness.c`) that reconstructs the same struct layout
   and the same loop, demonstrates the NULL-deref crash (SIGSEGV at offset 0),
   and the OOB read when the table is shorter than the sclk table.

## How to run the harness

```
./build.sh
./run.sh            # demonstrates both the NULL-deref and the OOB-read cases
```

Expected output (Linux/DragonFly userspace):

```
[case 1] std_voltage_table=NULL, sclk_count=3  -> reproducing kernel loop...
  BUG: dereferencing std_voltage_table->entries[0].Leakage with std_voltage_table=NULL
  harness: SIGSEGV (signal 11) at address (nil)   [kernel: NULL-deref panic]
[case 2] std_voltage_table->count=1, sclk_count=8 -> OOB read of entries[1..7]
  BUG: kernel would read 7 entries past cac_leakage_table->entries[0]
```

## Threat model

The PowerPlay table is parsed from the GPU VBIOS / ACPI `powerplay` table at
driver attach time. An attacker who can supply a crafted VBIOS (e.g. a
re-flashed GPU, a malicious PCI device, or a hypervisor/emulator presenting a
forged AMD GPU) can trigger an immediate kernel panic at boot or driver load.

On DragonFlyBSD the `amdgpu` driver is not in GENERIC, so this is a
**Medium** severity, defense-in-depth issue for the default kernel, but a
**High** DoS for any system that loads `amdgpu` (Radeon Southern Islands +
Vega/Arctic Islands APU setups).

## Recommended fix

Add a NULL check and bound the loop by the smaller of the two table counts.
See `fix.diff`.
