btc_dpm_get_sclk/btc_dpm_get_mclk dereference eg_pi->requested_rps.ps_priv (NULL) before the first power-state change β NULL-page read panic from display bandwidth updates
Summary
requested_rps.ps_priv is NULL from the kzalloc until the first pre_set_power_state; change_power_state's early returns can defer that indefinitely (headless or single-state VBIOS), while evergreen watermark code calls get_sclk directly from display commit whenever dpm_enabled. Boot headless then hotplug a monitor -> NULL read -> panic. Prime-at-enable fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3975 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.2 KB | β raw | |
| VERDICT.md | β | 2.3 KB | β raw | |
| verdict.json | β | 2.4 KB | view raw | |
| manifest.json | β | 697 B | view raw | |
| fix.diff | β | 296 B | view raw |
DF-3975 β btc_dpm_get_sclk/btc_dpm_get_mclk dereference eg_pi->requested_rps.ps_priv before the first power-state change (NULL-page read panic)
- File:
sys/dev/drm/radeon/btc_dpm.c:2802-2822(sink), consumersys/dev/drm/radeon/evergreen.c:2162-2197 - Class: CWE-476 (Medium) β the "ps_priv-NULL window" half of DF-3953 (kv), now for the btc get_sclk path; checklist item (e).
Build / Run / Expected
Hardware-gated (Barts/Turks/Caicos display path). Trigger: any radeon_bandwidth_update() that runs
after btc_dpm_enable() succeeds but before the first btc_dpm_pre_set_power_state() β e.g. the
first display hotplug/modeset on a headless or single-state system.
Root cause
eg_pi = kzalloc(...)(btc_dpm.c:2556) βeg_pi->requested_rps.ps_priv == NULLinitially. The ONLY writer isbtc_update_requested_ps()(btc_dpm.c:2266-2275), reached solely frombtc_dpm_pre_set_power_state()(2293).btc_dpm_get_sclk()/btc_dpm_get_mclk()(2802/2813):c struct rv7xx_ps *requested_state = rv770_get_ps(&eg_pi->requested_rps); /* NULL */ return requested_state->low.sclk; /* read at ~NULL β page fault */- Consumers:
evergreen_update_mc_scaling/watermarkβevergreen.c:2162-2197β callradeon_dpm_get_sclk/get_mclk(rdev, ...)wheneverpm_method == PM_METHOD_DPM && dpm_enabled.radeon_bandwidth_update()is invoked directly from display commit paths (atombios_crtc.c:1448,atombios_crtc.c:1642), NOT only from the power-state machine. - The window survives normal boot:
radeon_dpm_change_power_state_locked()(radeon_pm.c:1053) returns early at 1080/1105-1107 when the picked state equalscurrent_ps(set toboot_psat radeon_pm.c:1449) and the active-CRTC set is unchanged β e.g. headless boot, or a single-state power table β without ever calling pre_set_power_state. The next display event then runs the watermark computation withps_privstill NULL β NULL-page kernel read β panic. (The ioctl path is safe:RADEON_INFO_CURRENT_GPU_SCLK(radeon_kms.c:567-580) uses get_current_sclk, andcurrent_rpsis populated bybtc_update_current_psat the end of a successfulbtc_dpm_enable(2485).)
VERDICT β DF-3975
status: inconclusive (hardware-gated; source-level certainty: likely)
Trace
boot/attach: radeon_pm_init_dpm
1448 radeon_dpm_init (btc_dpm_init: eg_pi kzalloc'd, requested_rps.ps_priv == NULL)
1453 radeon_dpm_enable β btc_dpm_enable succeeds (2485 sets current_rps only)
1457 dpm_enabled = true
late_init/first compute_clocks:
radeon_pm_compute_clocks_dpm (radeon_pm.c:1810)
ββ radeon_dpm_change_power_state_locked (1053)
1080 current_ps == requested_ps (both = boot_ps, set at radeon_pm.c:1449)
1105-1107 new_active_crtcs == current_active_crtcs (headless/single-display steady state)
β return; pre_set_power_state NEVER called β requested_rps.ps_priv stays NULL
first display event (hotplug worker β modeset, or CRTC commit):
atombios_crtc.c:1448/1642 radeon_bandwidth_update
ββ evergreen.c:2162 dpm_enabled β radeon_dpm_get_sclk(rdev, false)
ββ btc_dpm_get_sclk (btc_dpm.c:2802)
ββ rv770_get_ps(&eg_pi->requested_rps) == NULL
ββ requested_state->low.sclk β read at 0x0+offset β kernel page fault
Exact structural twin of the second half of DF-3953 (kv_dpm_get_sclk ps_priv-NULL window, rated Medium). DF-3754 (ni) also documents the same window for its file. Not a duplicate: different asic-op table entry (btcd.h wires btc_dpm_get_sclk for Barts/Turks/Caicos).
Why "likely" and not "certain": the code shape is certain; the runtime window depends on display event ordering that I could not exercise (no radeon GPU in the guest β env.txt). The early-return conditions that keep the window open (state==boot state, crtcs unchanged) are ordinary for headless or single-state-VBIOS systems, and display hotplug is an unprivileged physical action.
Fix validation
not_testable (no hardware). fix.diff: initialize requested_rps/current_rps from boot_ps at the end of btc_dpm_enable (mirroring btc_update_current_ps at 2485), which closes the window for every consumer.
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_testablefix.diff authored (prime requested_rps at enable); not build-testable without the hardware.
findings/poc/DF-3975/fix.diff
Confirmed kernel references
- sys/dev/drm/radeon/btc_dpm.c:2802
- sys/dev/drm/radeon/btc_dpm.c:2813
- sys/dev/drm/radeon/btc_dpm.c:2266
- sys/dev/drm/radeon/btc_dpm.c:2293
- sys/dev/drm/radeon/btc_dpm.c:2485
- sys/dev/drm/radeon/btc_dpm.c:2556
- sys/dev/drm/radeon/evergreen.c:2162
- sys/dev/drm/radeon/atombios_crtc.c:1448
- sys/dev/drm/radeon/radeon_pm.c:1080
- sys/dev/drm/radeon/radeon_pm.c:1449
Detail
Evidence (decisive lines)
VERDICT.md bootβhotplug trace; the ioctl path (radeon_kms.c:567-580) uses get_current_sclk and is safe β the vulnerable consumer is the display-bandwidth path
PoC changes
No PoC: hardware-gated (needs real Barts-class display pipeline to order the events).
Verified recommended fix
Prime requested_rps from boot_ps at the end of btc_dpm_enable (btc_update_requested_ps at 2485) so get_sclk/get_mclk never observe ps_priv==NULL.
Verdict
btc_dpm_get_sclk/btc_dpm_get_mclk (btc_dpm.c:2802-2822) unconditionally dereference eg_pi->requested_rps.ps_priv, which stays NULL from the eg_pi kzalloc (btc_dpm.c:2556) until the first btc_dpm_pre_set_power_state (2293); radeon_dpm_change_power_state_locked's early returns (radeon_pm.c:1080,1105-1107) can defer that first call indefinitely on headless/single-state systems, while evergreen watermark code calls radeon_dpm_get_sclk directly from display commit (evergreen.c:2162-2197 via atombios_crtc.c:1448/1642) whenever dpm_enabled. First display event in the window β NULL-page read β panic. Structural twin of DF-3953's ps_priv window for the btc asic ops; hardware-gated (no radeon GPU in guest) so inconclusive with source-level likelihood.
No comments yet.