β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3586

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3586 Β· 3 files
FileTypeDescriptionSize
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
VERDICT.md verdict full source trace of the NULL boot_ps dereference
↓ download 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

  1. boot_ps assignment is conditional on a BIOS-controlled classification bit: sys/dev/drm/amd/amdgpu/si_dpm.c:7123-7124 if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) adev->pm.dpm.boot_ps = rps; No other assignment exists; adev is zero-initialized => stays NULL otherwise.

  2. si_parse_power_table() has no "needs a BOOT state" validation (si_dpm.c:7210-7300) and returns 0; si_dpm_init returns 0 (si_dpm.c:7343-7345); si_dpm_sw_init succeeds and even propagates the NULL (si_dpm.c:7720: adev->pm.dpm.current_ps = adev->pm.dpm.requested_ps = adev->pm.dpm.boot_ps;).

  3. 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 :6846 and :6867, and si_init_smc_table (:6830) internally calls si_populate_smc_initial_state(adev, adev->pm.dpm.boot_ps, table) (si_dpm.c:5159, 5205).

  4. 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) does aps->ps_priv on 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]) via si_populate_mc_reg_table(adev, boot_ps) at :6846, and si_dpm_disable's ni_update_current_ps(adev, boot_ps) at :6932.

  5. 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

inconclusive
baseline no→ patch + rebuild →patched clean

Guard 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
↓ fix.diffper-fix-DF-3586

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.