NULL-pointer dereference of rdev->pm.dpm.boot_ps in btc_dpm_enable/btc_dpm_disable when the VBIOS power table has no BOOT-classified state (or ucStateEntrySize<=1) β btc twin of DF-3610/3646/3754/3953
Summary
boot_ps is only set when ucStateEntrySize>1 AND a state carries the BOOT classification; radeon_pm_init_dpm ignores btc_dpm_init's return and btc_dpm_enable unconditionally dereferences the NULL boot_ps (NULL-page read at btc_init_smc_table -> populate_smc_initial_state). Physical access / malicious reflashed Barts/Turks/Caicos card: kernel panic at drm attach with default-enabled DPM. Same enabling sequence as the reproduced ni twin DF-3754.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3972 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.8 KB | β raw | |
| VERDICT.md | β | 3.2 KB | β raw | |
| verdict.json | β | 2.2 KB | view raw | |
| manifest.json | β | 872 B | view raw | |
| fix.diff | β | 825 B | view raw | |
| env.txt | β | 1.1 KB | view raw |
DF-3972 β NULL-pointer dereference of rdev->pm.dpm.boot_ps in btc_dpm_enable/btc_dpm_disable (crafted-VBIOS Barts/Turks/Caicos)
- File:
sys/dev/drm/radeon/btc_dpm.c(pass 2) - Class: CWE-476 NULL deref β kernel panic (Medium)
- Family: radeon DPM boot_ps twins (DF-3610 si / DF-3646 ci / DF-3754 ni / DF-3953 kv) β this is the btc (Barts/Turks/Caicos) sibling; distinct enable path, distinct file. Known DF-1314 (mc_reg_table off-by-one) is unrelated.
Build / Run / Expected
Hardware-gated: requires an AMD Barts/Turks/Caicos (NI-generation discrete GPU) whose VBIOS
PowerPlayInfo table either (a) contains no state with ATOM_PPLIB_CLASSIFICATION_BOOT set, or
(b) declares ucStateEntrySize <= 1 so the non-clock-info (classification) parse is skipped entirely.
No buildable PoC exists without the card: the trigger data lives in the GPU ROM image, parsed by
rv7xx_parse_power_table() at driver attach. See VERDICT.md for the line-level trace.
Root cause (source-level, certain)
rv7xx_parse_power_table()βsys/dev/drm/radeon/rv770_dpm.c:2271-2329β is the only code that setsrdev->pm.dpm.boot_psfor BTC asics. It does so insiderv7xx_parse_pplib_non_clock_info()(rv770_dpm.c:2172-2173), which is only reached whenpower_info->pplib.ucStateEntrySize - 1 != 0(rv770_dpm.c:2304) and a parsed state carries the BOOT classification bit. A VBIOS with no BOOT-classified state (or ucStateEntrySize<=1) leavesboot_ps == NULLwhilebtc_dpm_init()still returns 0 (parse "succeeded").radeon_pm_init_dpm()βsys/dev/drm/radeon/radeon_pm.c:1448β ignores the return ofradeon_dpm_init(rdev)(=btc_dpm_init) and unconditionally callsradeon_dpm_enable(rdev)(line 1453). There is no boot_ps validation anywhere on the path.btc_dpm_enable()βsys/dev/drm/radeon/btc_dpm.c:2373-2488β takesstruct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;(2377) and dereferences it at: - 2446btc_init_smc_table(rdev, boot_ps)βcypress_populate_smc_initial_state(rdev, NULL, table)βrv770_get_ps(NULL)theninitial_state->low.mclk(cypress_dpm.c:1242,1266) β NULL-page read. - 2451cypress_populate_mc_reg_table(rdev, boot_ps)- 2485btc_update_current_ps(rdev, rdev->pm.dpm.boot_ps)btc_dpm_disable()βbtc_dpm.c:2490-2527β same NULL at 2526 (btc_update_current_ps).- Also note
radeon_pm.c:1449assignscurrent_ps = requested_ps = boot_ps(NULL is tolerated there until later consumers run).
DPM is enabled by default (radeon.dpm=1 default on this family), so a crafted/flashed VBIOS panics
the kernel at drm attach β local DoS with physical access (or a supply-chain-flashed card).
Fix
Validate boot_ps after parse (upstream-style guard) β see fix.diff.
VERDICT β DF-3972
status: inconclusive (hardware-gated; source-level certainty: certain) impact: none demonstrated on available hardware; real-world impact = local kernel panic (DoS) at drm attach on Barts/Turks/Caicos with crafted VBIOS
Why inconclusive, not false-positive
The QEMU guest (env.txt) has no AMD GPU: only Intel/Red Hat QEMU PCI devices, no /dev/dri, no drm
modules. The bug's trigger bytes live in the GPU's ATOM BIOS PowerPlayInfo table; there is no way to
feed a radeon VBIOS to the guest's non-existent radeon device, and radeon.ko is not even loadable
there. Per audit convention for the DF-3610/3646/3754/3953 family this is recorded as
inconclusive with confidence: certain at source level.
Reproduction reasoning (line-level, no hardware needed)
Attacker model: physical access (or malicious reseller/reflash) supplying a GPU ROM whose
_ATOM_PPLIB_POWERPLAYTABLE:
ucNumStates >= 1, and either- no state's
_ATOM_PPLIB_NONCLOCK_INFO.usClassificationhasATOM_PPLIB_CLASSIFICATION_BOOT, or ucStateEntrySize == 1(skips the whole per-state parse block, rv770_dpm.c:2304-2325).
Trace:
radeon_pm_init (radeon_pm.c:1505)
ββ radeon_pm_init_dpm (radeon_pm.c:1422)
ββ radeon_dpm_init(rdev) # 1448 β btc_dpm_init, RETURN IGNORED
β ββ btc_dpm_init (btc_dpm.c:2549)
β ββ rv7xx_parse_power_table (rv770_dpm.c:2271)
β ββ boot_ps NEVER set (2172 only under classification parse)
ββ current_ps = requested_ps = boot_ps # 1449, NULL ok
ββ radeon_dpm_setup_asic β btc_dpm_setup_asic (btc_dpm.c:2529) # no boot_ps use
ββ radeon_dpm_enable β btc_dpm_enable (btc_dpm.c:2373)
ββ 2377 boot_ps = rdev->pm.dpm.boot_ps == NULL
ββ 2446 btc_init_smc_table(rdev, NULL) (btc_dpm.c:1624)
ββ 1661 cypress_populate_smc_initial_state(rdev, NULL, table)
ββ cypress_dpm.c:1242 rv770_get_ps(NULL) == NULL->ps_priv β #PF
rv770_get_ps() is a plain container_of-style cast (rps->ps_priv), so the first dereference reads
address ~0x0 + offsetof(ps_priv) on the NULL page β kernel page fault β panic. This is the exact
enabling sequence already proven for the ni twin (DF-3754, reproduced/panic on that batch's
harness).
Not a duplicate
DF-3754 (ni_dpm.c) covers Cayman's ni_dpm_enable; DF-3610/3646/3953 cover si/ci/kv. Barts/Turks/
Caicos use btc_dpm_enable via the btcd.h asic table β a different function and file, and the
orchestrator's pass-2 checklist explicitly requested it. DF-1314 (this file's known finding) is the
mc_reg_table off-by-one β unrelated.
Fix validation
fix_status: not_testable β no Barts-class GPU on the guest; a kernel rebuild cannot exercise the path. fix.diff authored against the read-only sys/ tree (guard + error propagation), mirroring the upstream si/ci/kv hardening pattern.
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 (boot_ps guard + error propagation) but not build-testable: guest lacks any radeon GPU.
findings/poc/DF-3972/fix.diff
Confirmed kernel references
- sys/dev/drm/radeon/btc_dpm.c:2377
- sys/dev/drm/radeon/btc_dpm.c:2446
- sys/dev/drm/radeon/btc_dpm.c:2451
- sys/dev/drm/radeon/btc_dpm.c:2485
- sys/dev/drm/radeon/btc_dpm.c:2526
- sys/dev/drm/radeon/rv770_dpm.c:2172
- sys/dev/drm/radeon/rv770_dpm.c:2304
- sys/dev/drm/radeon/radeon_pm.c:1448
- sys/dev/drm/radeon/cypress_dpm.c:1242
Detail
Evidence (decisive lines)
VERDICT.md full trace; env.txt (guest PCI inventory: no 0x1002 device, no /dev/dri); kernel_refs below
PoC changes
No PoC built: hardware-gated (Barts/Turks/Caicos VBIOS required). Evidence pack is a line-level source trace instead.
Verified recommended fix
Validate rdev->pm.dpm.boot_ps != NULL after rv7xx_parse_power_table in btc_dpm_init and propagate btc_dpm_init failure in radeon_pm_init_dpm (radeon_pm.c:1448).
Verdict
Source-certain NULL-deref: rdev->pm.dpm.boot_ps is only set under a BOOT-classified, fully-parsed VBIOS state (rv770_dpm.c:2172 within the ucStateEntrySize>1 block at 2304); radeon_pm_init_dpm ignores btc_dpm_init's return (radeon_pm.c:1448) and btc_dpm_enable dereferences the NULL boot_ps at btc_dpm.c:2446/2451/2485 via cypress_populate_smc_initial_state (cypress_dpm.c:1242,1266). Cannot reproduce: the QEMU guest has no AMD GPU (env.txt), and the trigger bytes live in the card's VBIOS PowerPlayInfo table. Same enabling sequence as the reproduced ni twin DF-3754.
No comments yet.