# DF-4189 — VERDICT

**Status: REPRODUCED (logic-level harness; kernel-level repro hardware-gated)**
**Impact: deterministic kernel page-fault panic on DPM state change (plus garbage-driven clock/voltage programming when the read happens to be mapped)**
**Confidence: certain**

## Root cause

`sumo_parse_pplib_clock_info()` sets `ps->num_levels = index + 1` — but it is
only called from inside the `j < ucNumDPMLevels` loop
(`sumo_dpm.c:1508-1520`). A pplib power state whose
`ATOM_PPLIB_STATE_V2.ucNumDPMLevels == 0` (pptable.h:428, u8 from the VBIOS,
never validated) leaves the kzalloc'd `struct sumo_ps` with
`num_levels == 0`. Only BOOT-classified states get patched up
(`sumo_patch_boot_state`, `:1395-1403`, forces 1); every other state keeps 0.

`struct sumo_ps` (sumo_dpm.h:44-49) begins with
`struct sumo_pl levels[SUMO_MAX_HARDWARE_POWERLEVELS]` (24-byte elements), and
`num_levels` is `u32`. Every consumer that asks for the "last" level executes

```c
ps->levels[ps->num_levels - 1]        /* == levels[0xFFFFFFFF] */
```

= base + 0xFFFFFFFF × 24 ≈ **+96 GB** past the allocation:

- `sumo_set_uvd_clock_before_set_eng_clock` — sumo_dpm.c:847-848
- `sumo_set_uvd_clock_after_set_eng_clock` — sumo_dpm.c:865-866
- `sumo_program_bsp` — sumo_dpm.c:350 (feeds `sumo_calculate_bsp`, whose
  `65535*100/high_clk` is the known DF-1438 div0 sink when the garbage is 0)
- `sumo_program_at` — sumo_dpm.c:426-427 (`r[num_levels-1]`/`l[num_levels-1]`,
  stack OOB below `u32 r[5]`/`l[5]`)
- `sumo_dpm_get_sclk` — sumo_dpm.c:1891 (sysfs/debugfs sclk read path)
- `sumo_program_bsp`'s write loop `for (i = 0; i < ps->num_levels - 1; i++)`
  (`:357`) underflows to 2^32 iterations → MMIO write storm (hardware hang)
  if the load itself somehow returned.

## Trigger / threat model

Crafted VBIOS with one BOOT state plus one non-BOOT state carrying
`ucNumDPMLevels == 0`, on a Sumo/Ontario/Palm APU. `radeon_dpm_pick_power_state`
selects the crafted state for any matching UI/thermal class; the first
`radeon_dpm_change_power_state_locked()` (display change, thermal event,
profile switch — regular operation) reaches `sumo_dpm_pre_set_power_state` →
`sumo_update_requested_ps` (working copy keeps `num_levels == 0`) →
`sumo_dpm_set_power_state` → the wild read → page-fault panic. This is the
sumo twin of DF-4145 (trinity) / DF-3954 (kv) / DF-3888 (amdgpu kv).

## Harness proof (mode 4189)

Two-state crafted table (state 0: `ucNumDPMLevels=0`, PERFORMANCE, vclk≠boot
to force the UVD comparison; state 1: BOOT, 1 level — parse succeeds,
`boot_ps` valid). After `sumo_update_requested_ps` + `sumo_update_current_ps`
(the `sumo_dpm_pre_set_power_state` replica), the first
`sumo_set_uvd_clock_before_set_eng_clock` call faults:

```
expected fault address for levels[num_levels-1].sclk ~= 0x20004e2128 (object + ~95 GB)
*** SIGNAL 11 at address 0x20004b5258 ***
```

`0x20004b5258 − 0xFFFFFFFF×24 = 0x8004b5270` = `&pi->requested_ps` — i.e. the
fault is exactly `&pi->requested_ps.levels[0xFFFFFFFF].sclk`, the working-copy
object the kernel uses at the same call site. An unmapped-address read is
deterministic: in the kernel this is a page-fault panic, not a recoverable
garbage read.

(The harness faults at the uvd_before site because the load there feeds the
observable `sumo_setup_uvd_clocks` stub; in the kernel all six sites are live.
The earlier variant that "survived" uvd_before and faulted inside
`sumo_program_bsp` instead showed the same address — both are the same
`levels[0xFFFFFFFF]` load.)

## Fix validation

1. `harness_fixed 4189` (`-DFIX_DF4189`: reject the table when a state parsed
   zero levels): "power state 0 has no DPM levels", parse returns -22, no
   crash, `canary_violations = 0`, exit 0.
2. `fix.diff` applied with the other three sumo fixes on guest `/usr/src`
   (`radeon_fix_apply.log` hunk 5): `radeon.ko` builds under `-Werror`,
   `MAKE_RC=0` (`radeon_module_build.log`).

## Kernel references

- sys/dev/drm/radeon/sumo_dpm.c:1508-1520 (loop that can leave num_levels 0)
- sys/dev/drm/radeon/sumo_dpm.c:1447 (num_levels set only per parsed level)
- sys/dev/drm/radeon/sumo_dpm.c:847-848, :865-866, :350, :426-427, :1891 (the
  `levels[num_levels-1]` consumers)
- sys/dev/drm/radeon/sumo_dpm.h:44-49 (levels[] is the FIRST member; u32)
- sys/dev/drm/radeon/pptable.h:424-436 (ucNumDPMLevels from VBIOS, unchecked)

## 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.
