# DF-4187 — VERDICT

**Status: REPRODUCED (logic-level harness; kernel-level repro hardware-gated)**
**Impact: kernel page-fault panic at drm attach / DPM enable**
**Confidence: certain**

## Root cause

`sumo_parse_pplib_non_clock_info()` sets `rdev->pm.dpm.boot_ps = rps` **only**
when a VBIOS power state carries `ATOM_PPLIB_CLASSIFICATION_BOOT`
(`sumo_dpm.c:1424-1427`). Nothing validates that any state has that class, and
`sumo_parse_power_table()` still returns 0 (`sumo_dpm.c:1526-1527`), so
`sumo_dpm_init()` succeeds with `boot_ps == NULL`.

The failure is then amplified by the family hub bug DF-4162
(`radeon_pm.c:1448` discards `radeon_dpm_init()`'s return), but **even without
the swallow** a BOOT-less table alone is sufficient:
`radeon_pm_init_dpm()` (`radeon_pm.c:1453`) calls `radeon_dpm_enable()` →
`sumo_dpm_enable()` unconditionally ends with

```c
sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps);   /* sumo_dpm.c:1235 */
```

→ `sumo_get_ps(NULL)` (`sumo_dpm.c:1186` via `:77-79`) loads
`NULL->ps_priv` at offset 40 (`radeon.h:1342-1356`) → **page-fault panic**
*after* DPM has already been started (`sumo_start_dpm`, `:1228`) — the GPU is
left with DPM enabled and half-programmed state.

The disable-side twin is also live: with a warm-reset box whose hardware
already reports `DPM_SCLK_ENABLE`, `sumo_dpm_enable()` early-returns -EINVAL at
`:1209-1210` (no crash), and the later `sumo_dpm_disable()` proceeds to
`sumo_update_current_ps(rdev, boot_ps)` at `:1280` — same NULL deref at
suspend/unload.

## Trigger / threat model

Crafted or truncated VBIOS AtomBios PowerPlayInfo table on a Sumo/Ontario
(SUMO/SUMO2), Palm or Wrestler APU with `radeon.dpm` enabled (default for
IGP): a power table whose states all lack the BOOT classification bit.
Attacker-controlled VBIOS = flashed card / replaced OPROM / VM GPU ROM
passthrough. Result: deterministic kernel panic at driver load (or at first
suspend for the disable path).

## Harness proof (mode 4187)

Verbatim replica of `sumo_parse_power_table`, `sumo_parse_pplib_*`,
`sumo_patch_boot_state`, `sumo_update_current_ps`, `sumo_get_ps` and the
`sumo_dpm_enable` skeleton (register-only sub-programming stubbed — see
harness.c header). Crafted 16 KB VBIOS image with one PERFORMANCE-classified
state:

```
sumo_parse_power_table() = 0 num_ps=1 boot_ps=0x0     <- parse "succeeds", boot_ps NULL
calling sumo_dpm_enable() with boot_ps == NULL ...
*** SIGNAL 11 at address 0x28 ***                     <- offsetof(radeon_ps, ps_priv) = 40
exit=99
```

The faulting address `0x28` matches the kernel field offset exactly — this is
the `NULL->ps_priv` load itself, i.e. the kernel page-fault at
`sumo_dpm.c:1186/1235`.

Stubs that do not affect the result: WREG32/RREG32 (no-ops),
`r600_calculate_u_and_p` (no-op), kzalloc/kfree (canary allocator — irrelevant
here), le16/le32 (identity), `atom_parse_data_header` (image crafted with the
same table-offset struct).

## Fix validation

1. Harness fixed build (`-DFIX_DF4187`: `boot_ps == NULL` guard at the top of
   `sumo_dpm_enable` and after the hw check in `sumo_dpm_disable`):
   `harness_fixed 4187` → "no boot power state, refusing to enable DPM",
   exit 0, no signal. (run.log, fixed section.)
2. `fix.diff` (both guards) applied to the guest's `/usr/src` copy together
   with the other three sumo fixes (`fix_combined.diff`): full `radeon.ko`
   module build under `-Werror` → `MAKE_RC=0`, `sumo_dpm.o` + `radeon.ko`
   produced (`radeon_module_build.log`, `radeon_fix_apply.log` hunks 1-2).

Kernel-on-hardware validation is not possible on the audit guest (no ATI APU;
`kldstat | grep -c radeon` = 0).

## Kernel references

- sys/dev/drm/radeon/sumo_dpm.c:1235 (the deref, enable path)
- sys/dev/drm/radeon/sumo_dpm.c:1186, :77-79 (NULL->ps_priv load)
- sys/dev/drm/radeon/sumo_dpm.c:1280 (disable-path twin)
- sys/dev/drm/radeon/sumo_dpm.c:1424-1427 (boot_ps only set for BOOT class)
- sys/dev/drm/radeon/sumo_dpm.c:1526-1527 (parse returns 0 regardless)
- sys/dev/drm/radeon/radeon_pm.c:1448 (DF-4162 swallow), :1453 (enable call)
- sys/dev/drm/radeon/radeon.h:1342-1356 (ps_priv at offset 40)

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
