β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4187

NULL boot_ps page-fault panic in sumo_dpm_enable (:1235) / sumo_dpm_disable (:1280) when the VBIOS power table has no BOOT-classified state or dpm.init failed β€” sumo twin of DF-4118/4143/4124/3972/3754/3953

Summary

sumo_parse_pplib_non_clock_info sets boot_ps only for BOOT-classified states and the parse still returns 0, so a BOOT-less crafted VBIOS parses 'successfully' with boot_ps NULL. radeon_pm_init_dpm (error swallowed per DF-4162) calls sumo_dpm_enable, which unconditionally ends with sumo_update_current_ps(rdev, boot_ps) -> sumo_get_ps(NULL) loads NULL->ps_priv at offset 40 -> page-fault panic AFTER DPM started. Disable-path twin reachable on warm reset (enable early-returns, disable later derefs NULL at suspend/unload). Harness-proven (fault at 0x28 == offsetof(ps_priv); fixed harness refuses). radeon.ko builds with all four sumo fixes -Werror.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4187 Β· 11 files
FileTypeDescriptionSize
harness.c trigger-source verbatim sumo_dpm.c replica, mode 4187 = BOOT-less VBIOS -> enable -> NULL->ps_priv (0x28) 34.8 KB view raw
build.sh build-script cc -O2 -Wall; also builds harness_fixed (-DFIX_ALL) 65 B view raw
run.sh run-script all modes, baseline + fixed 120 B view raw
build.log build-log final successful builds (guest cc 8.3) 1018 B view raw
run.log run-log decisive run: baseline exit 99/98/99/99, fixed 0/0/0/0 3.5 KB view raw
fix.diff suggested-fix boot_ps NULL guards in sumo_dpm_enable + sumo_dpm_disable 817 B view raw
fix_combined.diff suggested-fix all four sumo fixes (DF-4187..4190) in one diff 3.3 KB view raw
radeon_fix_apply.log apply-log patch(1) hunk application on guest /usr/src 808 B view raw
radeon_module_build.log fix-build-log radeon.ko module build with fixes, -Werror, MAKE_RC=0 139.5 KB view raw
env.txt environment guest uname, cc version, no radeon loaded 568 B view raw
VERDICT.md verdict full narrative 4.4 KB ↓ raw
VERDICT.md verdict full narrative
↓ download raw

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

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

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.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

harness_fixed 4187 completes cleanly (refuses enable, exit 0); combined fix builds radeon.ko under -Werror on guest /usr/src (MAKE_RC=0)

run.log fixed section; radeon_fix_apply.log; radeon_module_build.log tail 'MAKE_RC=0', sumo_dpm.o + radeon.ko produced
↓ fix.diffper-fix-DF-4187

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log '===== mode 4187 =====' (baseline): SIGSEGV at 0x28; fixed section: 'no boot power state, refusing to enable DPM', exit=0; radeon_module_build.log MAKE_RC=0

PoC changes

wrote harness from scratch (no seed): verbatim function replicas + canary allocator + crafted VBIOS image; register-only plumbing stubbed

Verified recommended fix

guard rdev->pm.dpm.boot_ps == NULL in sumo_dpm_enable() and sumo_dpm_disable(); honor dpm.init failures in radeon_pm.c (DF-4162 hub)

Verdict

Reproduced at logic level with a verbatim userspace replica of the sumo code paths (harness mode 4187): a BOOT-class-less VBIOS power table parses successfully with boot_ps==NULL, and sumo_dpm_enable() (:1235) -> sumo_update_current_ps(rdev, NULL) -> sumo_get_ps(NULL) faults on NULL->ps_priv at offset 0x28 == offsetof(radeon_ps, ps_priv) β€” the exact kernel page-fault. Kernel-on-hardware repro is hardware-gated (no Sumo/Palm APU on the audit guest); DPM is enabled by default on these IGPs and radeon_pm.c:1448 (DF-4162) swallows init failures, but the BOOT-less-table path alone suffices. Fixed build refuses to enable (exit 0); fix also proven to compile in-kernel (radeon.ko, -Werror, MAKE_RC=0).