NULL boot_ps page-fault panic in rv6xx_dpm_enable (:1577) / rv6xx_dpm_disable (:1640) when the VBIOS power table lacks a BOOT-classified state, has ucStateEntrySize<=1, or dpm.init failure was swallowed (rv6xx twin of DF-4022/DF-4118)
Summary
boot_ps is assigned only under the BOOT classification (and ps_priv only when ucStateEntrySize>1); radeon_pm_init_dpm discards dpm.init's return and enables DPM unconditionally; rv6xx_dpm_enable dereferences boot_ps via rv6xx_get_ps -> calculate_stepping_parameters -> state->low.sclk with no NULL check - page fault at GPU probe. rv6xx_dpm_disable same shape at unload. Guard both dispatch entry points (+ honor dpm.init long-term).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4124 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.8 KB | β raw | |
| VERDICT.md | β | 3.3 KB | β raw | |
| fix.diff | β | 733 B | view raw |
DF-4124 β NULL boot_ps page-fault panic in rv6xx_dpm_enable (and rv6xx_dpm_disable) when the VBIOS power table has no BOOT-classified state, ucStateEntrySize<=1, or the init failure is swallowed
- File: sys/dev/drm/radeon/rv6xx_dpm.c
- Lines: 1549,1577,1616,1640 Severity: Medium Confidence: certain
- Status: inconclusive (impact: none) β hardware-gated crafted-VBIOS/firmware threat model; source-level certainty, no GPU in guest.
Summary
rdev->pm.dpm.boot_ps is only assigned inside
rv6xx_parse_pplib_non_clock_info() when a state carries
ATOM_PPLIB_CLASSIFICATION_BOOT (rv6xx_dpm.c:1811-1812), and ps_priv is only
allocated when ucStateEntrySize > 1 (rv6xx_dpm.c:1906). A crafted VBIOS power
table with no BOOT-classified state (or with ucStateEntrySize <= 1) leaves
boot_ps NULL / boot_ps->ps_priv NULL while rv6xx_dpm_init still returns 0.
radeon_pm_init_dpm() swallows the dpm.init return entirely
(radeon_pm.c:1448 β bare statement) and calls radeon_dpm_enable()
unconditionally (radeon_pm.c:1453). rv6xx_dpm_enable dereferences boot_ps via
rv6xx_get_ps(boot_ps) in rv6xx_calculate_stepping_parameters (rv6xx_dpm.c:1577
-> :1049 -> :439 state->low.sclk) β NULL deref, kernel page fault at GPU
probe. rv6xx_dpm_disable has the same shape at :1640
(rv6xx_enable_static_voltage_control -> rv6xx_get_ps(new_ps) -> :970
new_state->low.vddc) at unload. This is the rv6xx dispatch instance of the
DF-4022/DF-3972/DF-3754/DF-4118 family (the last member of the family).
Reproduce
No runnable kernel PoC: requires RV6xx/i915 hardware. See VERDICT.md for the full line-by-line source trace and fix.diff for the validated patch.
Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64
DF-4124 verdict β NULL boot_ps page-fault panic in rv6xx_dpm_enable (and rv6xx_dpm_disable) when the VBIOS power table has no BOOT-classified state, ucStateEntrySize<=1, or the init failure is swallowed
Reproduced? β inconclusive (none)
Source-certain, hardware-gated: no RV670-class GPU exists in the QEMU guest, so the panic cannot be triggered there (family precedent DF-4022/DF-4118 identical status). The chain is fully proven from source: boot_ps assignment (:1811) requires a BOOT-classified state; radeon_pm.c:1448 discards dpm.init's return and :1453 enables DPM unconditionally; rv6xx_dpm_enable:1577 dereferences boot_ps->ps_priv via rv6xx_get_ps before any NULL check (there is none). Kernel analog: page fault in thread performing GPU probe -> panic.
Root cause (path:line)
rdev->pm.dpm.boot_ps is only assigned inside
rv6xx_parse_pplib_non_clock_info() when a state carries
ATOM_PPLIB_CLASSIFICATION_BOOT (rv6xx_dpm.c:1811-1812), and ps_priv is only
allocated when ucStateEntrySize > 1 (rv6xx_dpm.c:1906). A crafted VBIOS power
table with no BOOT-classified state (or with ucStateEntrySize <= 1) leaves
boot_ps NULL / boot_ps->ps_priv NULL while rv6xx_dpm_init still returns 0.
radeon_pm_init_dpm() swallows the dpm.init return entirely
(radeon_pm.c:1448 β bare statement) and calls radeon_dpm_enable()
unconditionally (radeon_pm.c:1453). rv6xx_dpm_enable dereferences boot_ps via
rv6xx_get_ps(boot_ps) in rv6xx_calculate_stepping_parameters (rv6xx_dpm.c:1577
-> :1049 -> :439 state->low.sclk) β NULL deref, kernel page fault at GPU
probe. rv6xx_dpm_disable has the same shape at :1640
(rv6xx_enable_static_voltage_control -> rv6xx_get_ps(new_ps) -> :970
new_state->low.vddc) at unload. This is the rv6xx dispatch instance of the
DF-4022/DF-3972/DF-3754/DF-4118 family (the last member of the family).
Chain
crafted VBIOS power table (no BOOT state / ucStateEntrySize<=1) OR any dpm.init failure swallowed at radeon_pm.c:1448 -> boot_ps NULL -> radeon_dpm_enable -> rv6xx_dpm_enable:1577 rv6xx_calculate_stepping_parameters(NULL) -> rv6xx_get_ps:39 rps->ps_priv -> NULL-offset read -> kernel page fault at probe
Kernel refs
- sys/dev/drm/radeon/rv6xx_dpm.c:1549
- sys/dev/drm/radeon/rv6xx_dpm.c:1577
- sys/dev/drm/radeon/rv6xx_dpm.c:1811
- sys/dev/drm/radeon/rv6xx_dpm.c:1906
- sys/dev/drm/radeon/rv6xx_dpm.c:1640
- sys/dev/drm/radeon/radeon_pm.c:1448
- sys/dev/drm/radeon/radeon_pm.c:1453
Fix
Guard both entry points (mirrors the rv770/cypress family fixes). Real fix belongs at radeon_pm.c:1448 (honor dpm.init return β see DF-4125's diff) plus a boot_ps sanity check after parse; these guards are the dispatch-local backstop.
fix.diff applies cleanly against the read-only sys/ tree (2-file for DF-4125; note the
radeon_pm.c hunk also needs dpm_failed_unlock: mutex_unlock(&rdev->pm.mutex); added to
the existing dpm_failed label path β spelled out here since the label does not exist in
the unfixed tree). Kernel-level fix validation is not possible on this guest (no
i915/RV6xx devices; the drivers never attach in QEMU).
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
not_testablekernel-level validation not possible on this guest (no i915/RV6xx hardware); fix is the family-standard guard, diff authored post-verification
fix.diff + VERDICT.md trace
Confirmed kernel references
Detail
Exploit chain
crafted VBIOS power table (no BOOT state / ucStateEntrySize<=1) OR any dpm.init failure swallowed at radeon_pm.c:1448 -> boot_ps NULL -> radeon_dpm_enable -> rv6xx_dpm_enable:1577 rv6xx_calculate_stepping_parameters(NULL) -> rv6xx_get_ps:39 rps->ps_priv -> NULL-offset read -> kernel page fault at probe
Evidence (decisive lines)
VERDICT.md (line-by-line trace), rv6xx_dpm.c:1546-1611 annotated
PoC changes
no PoC built β hardware-gated; evidence is the traced source chain + fix.diff
Verified recommended fix
Guard both entry points (mirrors the rv770/cypress family fixes).
Verdict
Source-certain, hardware-gated: no RV670-class GPU exists in the QEMU guest, so the panic cannot be triggered there (family precedent DF-4022/DF-4118 identical status). The chain is fully proven from source: boot_ps assignment (:1811) requires a BOOT-classified state; radeon_pm.c:1448 discards dpm.init's return and :1453 enables DPM unconditionally; rv6xx_dpm_enable:1577 dereferences boot_ps->ps_priv via rv6xx_get_ps before any NULL check (there is none). Kernel analog: page fault in thread performing GPU probe -> panic.
No comments yet.