NULL-pointer dereference in si_dpm_enable when the VBIOS power table has no ATOM_PPLIB_CLASSIFICATION_BOOT state (boot_ps unvalidated)
Summary
boot_ps is assigned only when a VBIOS state carries the BOOT classification; si_parse_power_table and si_dpm_sw_init succeed with boot_ps==NULL, and si_dpm_enable passes it unguarded into si_init_smc_table -> si_populate_smc_initial_state -> si_get_ps(NULL) which reads aps->ps_priv from a fixed near-NULL address -> page fault/panic at boot/module-load/resume. Also si_populate_mc_reg_table(adev,NULL) and ni_update_current_ps(adev,NULL). Source-certain (NULL+offsetof arithmetic); kernel path unreachable on the virtio-only guest. Read at fixed low address only - DoS, no memory-control primitive. Fix: early-out in si_dpm_enable (git-apply-verified).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3586 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | full source trace of the NULL boot_ps dereference | 3.3 KB | β raw |
| fix.diff | suggested-fix | reject si_dpm_enable when boot_ps==NULL (git-apply-verified) | 606 B | view raw |
| env.txt | env | guest evidence: no AMD PCI device; amdgpu.ko present but si_dpm unreachable | 304 B | view raw |
DF-3586 Verification Verdict
Severity: Medium β crafted-VBIOS NULL-deref panic (CWE-476) Verification method: source-line proof. Kernel-level execution impossible on the verification guest (no AMD GPU); the defect is a direct NULL dereference whose reachability is fully determined by source β no harness adds information.
Source proof chain
-
boot_psassignment is conditional on a BIOS-controlled classification bit:sys/dev/drm/amd/amdgpu/si_dpm.c:7123-7124if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) adev->pm.dpm.boot_ps = rps;No other assignment exists; adev is zero-initialized => stays NULL otherwise. -
si_parse_power_table()has no "needs a BOOT state" validation (si_dpm.c:7210-7300) and returns 0;si_dpm_initreturns 0 (si_dpm.c:7343-7345);si_dpm_sw_initsucceeds and even propagates the NULL (si_dpm.c:7720:adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;). -
si_dpm_hw_init(si_dpm.c:7748-7766) ->si_dpm_enable(si_dpm.c:6778):struct amdgpu_ps *boot_ps = adev->pm.dpm.boot_ps;(:6783) β no NULL check β passed at:6846and:6867, andsi_init_smc_table(:6830) internally callssi_populate_smc_initial_state(adev, adev->pm.dpm.boot_ps, table)(si_dpm.c:5159, 5205). -
Crash sink:
si_populate_smc_initial_state(si_dpm.c:4829-4834):struct si_ps *initial_state = si_get_ps(amdgpu_initial_state);si_get_ps(si_dpm.c:1971-1976) doesaps->ps_privon the NULL pointer => kernel read from page 0 (fixed low address) => fatal page fault. Additional unguarded sinks: si_dpm.c:6118 (boot_state->performance_levels[0]) viasi_populate_mc_reg_table(adev, boot_ps)at :6846, andsi_dpm_disable'sni_update_current_ps(adev, boot_ps)at :6932. -
Trigger surface: boot /
kldload amdgpu/ resume with an SI GPU whose VBIOS PowerPlayInfo state array contains no BOOT-classified entry. Purely VBIOS-content-controlled; no privilege required beyond having the hardware present. Impact: panic (driver init / system boot DoS), no memory-control primitive (fixed-address read).
Why inconclusive and not kernel-reproduced
Verification guest is virtio-only: pciconf -l shows zero vendor-0x1002
devices; amdgpu.ko loads ([drm] amdgpu kernel modesetting enabled) but no
SI asic attaches, so si_dpm_enable never runs. The NULL-deref itself is
arithmetically trivial (NULL->ps_priv) β source-certain.
Fix validation
fix.diff adds an early if (boot_ps == NULL) return -EINVAL; in
si_dpm_enable (covers hw_init and resume paths; dpm then degrades to disabled
via the existing adev->pm.dpm_enabled = false handling, si_dpm.c:7760-7763).
Patch git-apply-verified against the read-only tree; logic-level validation only
(no kernel build this run β guard introduces no type changes).
Verdict
inconclusive at kernel level (no SI hardware on guest); source-certain
NULL-deref defect; one-line guard recommended as in 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
inconclusiveGuard is a pure early-return; logic-level validation only (no SI hardware to build/boot a test kernel against on this guest). Patch git-apply-verified against the read-only sys/ tree.
findings/poc/DF-3586/fix.diff
Confirmed kernel references
Detail
Exploit chain
crafted VBIOS PowerPlayInfo state array without ATOM_PPLIB_CLASSIFICATION_BOOT -> driver init succeeds -> si_dpm_enable -> si_populate_smc_initial_state(NULL) -> si_get_ps(NULL) reads ps_priv at a fixed near-NULL offset -> kernel panic (boot/module-load DoS).
Evidence (decisive lines)
VERDICT.md proof chain (path:line); env.txt: guest has zero 0x1002 PCI devices so the kernel path is unreachable there; fix.diff guard is git-apply-verified.
PoC changes
no orchestrator seed; source-only verification (NULL-deref arithmetic needs no harness)
Verified recommended fix
Reject si_dpm_enable when adev->pm.dpm.boot_ps == NULL so dpm degrades gracefully (see fix.diff).
Verdict
Source-certain NULL dereference: adev->pm.dpm.boot_ps is set only when a VBIOS power state carries ATOM_PPLIB_CLASSIFICATION_BOOT (si_dpm.c:7123-7124); nothing validates that any state has it. si_dpm_sw_init succeeds with current_ps=requested_ps=boot_ps=NULL (si_dpm.c:7720) and si_dpm_enable passes the unguarded boot_ps (si_dpm.c:6783) into si_init_smc_table (6830) -> si_populate_smc_initial_state (5205) -> si_get_ps(NULL) (4829-4834: aps->ps_priv read from ~NULL+0x50-0x80), plus si_populate_mc_reg_table (6846/6118) and si_dpm_disable (6932). Result: page fault / panic at boot, kldload, or resume with a crafted VBIOS lacking a BOOT-classified state. Kernel-level reproduction impossible on the verification guest (no AMD GPU, virtio-only; amdgpu.ko loads but si_dpm never attaches). Read at a fixed low address only - DoS, no memory-control primitive.
No comments yet.