NULL-deref panic in rv770_dpm_enable->rv770_init_smc_table when the VBIOS power table has no BOOT-classified state (or ucStateEntrySize<=1) or dpm.init failed β rv770-family twin of DF-3972/3953/3754/3646/3610
Summary
rv7xx_parse_power_table only sets boot_ps under ucStateEntrySize>1 AND a BOOT-classified state; a crafted VBIOS without one (or a dpm.init failure whose return radeon_pm_init_dpm IGNORES) leaves boot_ps NULL while num_ps is published. rv770_dpm_enable takes it without NULL check -> rv770_get_ps(NULL) panic at attach; same sinks re-hit via requested_ps in get_sclk/get_mclk and resume. Crafted-VBIOS reboot-loop DoS. Guard + propagate-init-failure fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4022 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.1 KB | β raw | |
| VERDICT.md | β | 3.5 KB | β raw | |
| env.txt | β | 775 B | view raw | |
| fix.diff | β | 832 B | view raw | |
| manifest.json | β | 1.3 KB | view raw | |
| verdict.json | β | 4.2 KB | view raw |
DF-4022 evidence pack
rv770_dpm.c boot_ps NULL-deref (rv770-family twin of DF-3972/3953/3754/3646/3610).
- No runnable PoC: hardware-gated (guest has virtio VGA only, zero AMD/ATI PCI devices -- env.txt). Source chain is deterministic: rv7xx_parse_power_table rv770_dpm.c:2271-2329 (boot_ps only under ucStateEntrySize>1 + BOOT class, :2172-2173/:2304) -> radeon_pm.c:1448 ignores dpm.init failure, :1449 publishes NULL -> radeon_pm.c:1453 radeon_dpm_enable -> rv770_dpm.c:1901 boot_ps NULL, :1956 rv770_init_smc_table(rdev, NULL) -> rv770_dpm.c:1170/:52-57 rv770_get_ps(NULL) = NULL->ps_priv -> panic.
- VERDICT.md: full narrative. env.txt: hardware absence + md5 match.
- fix.diff: boot-state guard in rv770_dpm_enable + propagate dpm.init error in radeon_pm_init_dpm (git apply --check clean).
Reproduce (on RV770/RV730/RV710/RV740 hardware or a PCI passthrough VM): flash/craft a VBIOS whose PowerPlayInfo table has ucNumStates>0 with no ATOM_PPLIB_CLASSIFICATION_BOOT state (or ucStateEntrySize<=1) -> panic at drm attach. Expected: "Fatal trap 12: page fault while in kernel mode" at rv770_get_ps/boot_state->low.sclk.
DF-4022 β NULL-deref panic via boot_ps == NULL in rv770_dpm_enable / rv770_init_smc_table
File: sys/dev/drm/radeon/rv770_dpm.c (pass 2)
Class: CWE-476 NULL pointer dereference β kernel panic (DoS)
Hardware gate: RV770/RV730/RV710/RV740 GPU with (crafted) VBIOS AtomBios
PowerPlayInfo table. Same threat model as DF-1333/1334/1335 (crafted VBIOS via
PCIe passthrough / hotplug / reflash).
Status: source-level certain; runtime hardware-gated (guest has virtio VGA
only β see env.txt). Per family convention (DF-3610/3646/3754/3953/3972) this
is inconclusive at runtime, certain at source level.
Root cause
rv7xx_parse_power_table() (rv770_dpm.c:2271-2329) only ever sets
rdev->pm.dpm.boot_ps β inside rv7xx_parse_pplib_non_clock_info()
(rv770_dpm.c:2172-2173) β and that function is only reached when
power_info->pplib.ucStateEntrySize - 1 is non-zero (rv770_dpm.c:2304), i.e.
ucStateEntrySize >= 2. Two fully VBIOS-controlled conditions therefore leave
boot_ps == NULL while num_ps = ucNumStates is still published
(rv770_dpm.c:2327):
ucStateEntrySize <= 1(states are counted but never parsed), or- no parsed state carries
ATOM_PPLIB_CLASSIFICATION_BOOT.
Additionally rv770_dpm_init() failure of any kind
(r600_get_platform_caps() fail at rv770_dpm.c:2364-2366;
rv7xx_parse_power_table() fail at :2368-2370) leaves boot_ps NULL, and
its return value is ignored by the caller (radeon_pm.c:1448), so the
enable path runs regardless.
Crash chain
radeon_pm_init_dpm() radeon_pm.c:1448 radeon_dpm_init() return IGNORED
radeon_pm.c:1449 current_ps = requested_ps = boot_ps (NULL)
radeon_pm.c:1453 radeon_dpm_enable()
rv770_dpm_enable() rv770_dpm.c:1898
boot_ps = rdev->pm.dpm.boot_ps rv770_dpm.c:1901 (NULL, never checked)
rv770_init_smc_table(rdev, NULL) rv770_dpm.c:1956
boot_state = rv770_get_ps(NULL) rv770_dpm.c:1170 -> :52-57 rps->ps_priv
pi->boot_sclk = boot_state->low.sclk rv770_dpm.c:1176
rv770_get_ps(NULL) reads NULL->ps_priv β page-0 fault in kernel mode β
panic ("Fatal trap 12: page fault while in kernel mode"). The same NULL
boot_ps/requested_ps is later dereferenced on every
rv770_dpm_get_sclk/get_mclk (rv770_dpm.c:2554-2572) and on the resume
path (radeon_pm.c:1320-1322).
When ucStateEntrySize == 1, ps_priv[i] also stays NULL for every state
(rv770_dpm.c:2304-2325 skips the kzalloc), so even a "BOOT" state that
magically existed would still deref NULL via ps_priv.
Impact
Kernel panic at device attach (boot or PCIe hotplug) on RV770-family GPUs with a malformed/malicious VBIOS power table; reboot-loop DoS on such a system. No info leak / no write primitive (pure NULL deref).
rv770-family twin of DF-3972 (btc), DF-3953 (kv), DF-3754 (ni), DF-3646 (ci), DF-3610 (si). The rv770 instance was NOT previously filed (pass 1 filed only DF-1333/1334/1335 against this file).
Fix
rv770_dpm_enable() must refuse to run without a boot state, and
radeon_pm_init_dpm() must not ignore dpm.init failure. See fix.diff.
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 (rv770_dpm.c guard + radeon_pm.c error propagation) applies clean against the read-only tree; cannot be runtime-validated on a guest without radeon hardware.
findings/poc/DF-4022/fix.diff
Confirmed kernel references
- sys/dev/drm/radeon/rv770_dpm.c:2271
- sys/dev/drm/radeon/rv770_dpm.c:2304
- sys/dev/drm/radeon/rv770_dpm.c:2172
- sys/dev/drm/radeon/rv770_dpm.c:2327
- sys/dev/drm/radeon/rv770_dpm.c:2368
- sys/dev/drm/radeon/rv770_dpm.c:1898
- sys/dev/drm/radeon/rv770_dpm.c:1901
- sys/dev/drm/radeon/rv770_dpm.c:1956
- sys/dev/drm/radeon/rv770_dpm.c:1170
- sys/dev/drm/radeon/rv770_dpm.c:1176
- sys/dev/drm/radeon/radeon_pm.c:1448
- sys/dev/drm/radeon/radeon_pm.c:1453
- sys/dev/drm/radeon/radeon_asic.c:1285
Detail
Exploit chain
On RV770-family hardware: craft/reflash VBIOS PowerPlayInfo (PCIe passthrough/hotplug) with no BOOT-classified state -> drm attach panics -> reboot-loop DoS. No write primitive; NULL-deref only.
Evidence (decisive lines)
VERDICT.md (path:line chain); env.txt (hardware absence + guest-src md5 044c898d346408165b2f18b045f210c9 == audited tree); fix.diff (boot-state guard + init-error propagation, git apply --check clean)
PoC changes
No seed PoC. No runnable PoC possible on this guest (no radeon hardware); pack follows the DF-3972 convention (env + VERDICT + fix).
Verified recommended fix
Guard rv770_dpm_enable against NULL boot_ps/ps_priv and stop ignoring dpm.init failure in radeon_pm_init_dpm (see fix.diff).
Verdict
Source-level certain, runtime hardware-gated (inconclusive per family convention). rv7xx_parse_power_table (rv770_dpm.c:2271-2329) only sets rdev->pm.dpm.boot_ps inside rv7xx_parse_pplib_non_clock_info (:2172-2173), which is reached only when ucStateEntrySize>1 (:2304) and only for a state carrying ATOM_PPLIB_CLASSIFICATION_BOOT; a crafted VBIOS with no such state (or ucStateEntrySize<=1, which also leaves ps_priv[i] NULL) leaves boot_ps NULL while num_ps is still published (:2327). radeon_pm_init_dpm IGNORES the dpm.init return (radeon_pm.c:1448) -- so rv770_dpm_init failures (r600_get_platform_caps :2364, parse :2368) reach the same state -- then publishes NULL (radeon_pm.c:1449) and calls radeon_dpm_enable (radeon_pm.c:1453) = rv770_dpm_enable (rv770_dpm.c:1898) which never checks boot_ps (:1901) and passes NULL to rv770_init_smc_table (:1956) where rv770_get_ps(NULL) reads NULL->ps_priv (:52-57 via :1170) and boot_state->low.sclk (:1176) -> page-fault panic at drm attach on RV770/RV730/RV710/RV740 (rv770_asic dispatch, radeon_asic.c:1216/1285). Same sinks re-hit on every rv770_dpm_get_sclk/get_mclk via requested_ps (rv770_dpm.c:2554-2572) and the resume path (radeon_pm.c:1320). Guest: virtio VGA only, zero 0x1002 PCI devices, hw.drm absent (env.txt) -> not runtime-testable; rv770-family twin of DF-3972/3953/3754/3646/3610, NOT previously filed against this file (pass 1 filed DF-1333/1334/1335 only).
No comments yet.