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

NULL boot_ps page-fault panic in cypress_dpm_enable when the VBIOS power table has no BOOT-classified state (or dpm.init failed) β€” cypress twin of DF-4022/DF-3972/DF-3754

Summary

boot_ps is assigned only under the BOOT classification. Two crafted-VBIOS shapes reach a NULL deref: (a) no BOOT-classified state -> cypress_force_mc_use_s0(rdev, NULL) -> rv770_get_ps(NULL) reads rps->ps_priv at NULL+offset -> page fault at DPM enable (default-on at boot); (b) dpm_init failed but the double-swallowed error lets radeon_dpm_enable run on the kzalloc-zeroed eg_pi and cypress_init_smc_table(rdev, NULL) -> same NULL-page read. cypress_dpm_disable carries the same latent deref. NULL-guard fix (+ honor dpm.init long-term).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4118 Β· 6 files
FileTypeDescriptionSize
README.md β€” 1.5 KB ↓ raw
VERDICT.md β€” 2.5 KB ↓ raw
fix.diff β€” 717 B view raw
env.txt β€” 583 B view raw
manifest.json β€” 1.2 KB view raw
verdict.json β€” 3.0 KB view raw

DF-4118 β€” NULL boot_ps dereference panic in cypress_dpm_enable (cypress dispatch; twin of DF-4022/3972/3754/3953/3646/3610) ==================================================================== File: sys/dev/drm/radeon/cypress_dpm.c β€” pass 2 (GLM 5.3).

rdev->pm.dpm.boot_ps is set ONLY at rv770_dpm.c:2172-2173 under ATOM_PPLIB_CLASSIFICATION_BOOT. Two crafted-VBIOS shapes reach cypress_dpm_enable with boot_ps == NULL:

(a) no BOOT-classified state (parse OK, init fully initializes eg_pi->dynamic_ac_timing=true at cypress_dpm.c:2119): cypress_dpm_enable :1837-1839 -> cypress_force_mc_use_s0(rdev, NULL) -> rv770_get_ps(NULL) reads rps->ps_priv at NULL+offset (rv770_dpm.c:53-57) -> kernel page fault. (b) cypress_dpm_init fails (missing PowerPlayInfo header / DF-4117 alloc failure): radeon_pm.c:1448 IGNORES the error, evergreen.c:5235 calls radeon_pm_init() as a statement; enable runs on the kzalloc-zeroed eg_pi (dynamic_ac_timing=0 skips (a)) and, when SMC firmware uploads, :1878 cypress_init_smc_table(rdev, NULL) -> cypress_populate_smc_initial_state:1242 -> rv770_get_ps(NULL).

Panic at module load / boot on the affected card (DPM is default-on); persistent boot DoS via VBIOS/option-ROM level crafting, attacker- controlled precondition is physical/vBIOS access β€” same acceptance basis as the filed btc/rv770/ni twins (DF-3972/4022/3754). No evergreen hardware on the audit guest => runtime inconclusive; source-level certain. fix.diff: early boot_ps guards in cypress_dpm_enable/cypress_dpm_disable.

VERDICT.md
↓ download raw

DF-4118 VERDICT β€” NULL boot_ps page fault in cypress_dpm_enable

STATUS: inconclusive (runtime hardware-gated); mechanism source-certain. impact ceiling (not demonstrated): kernel page-fault panic at module load/boot. confidence: certain.

CHAIN (path:line): * boot_ps is assigned ONLY at rv770_dpm.c:2172-2173 (if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) rdev->pm.dpm.boot_ps = rps;) inside rv7xx_parse_pplib_non_clock_info. * rv770_get_ps(rps) is an unguarded return rps->ps_priv (rv770_dpm.c:53-57) β€” NULL rps reads at NULL + offsetof(ps_priv). * Path (a) β€” no BOOT-classified state in an otherwise-valid power table: cypress_dpm_init completes (dynamic_ac_timing=true at cypress_dpm.c:2119; voltage/mvdd flags from VBIOS), cypress_dpm_enable:1837 if (eg_pi->dynamic_ac_timing) -> :1839 cypress_force_mc_use_s0(rdev, boot_ps=NULL) -> :1184 rv770_get_ps(NULL) -> page fault. Runs BEFORE any code that could fail gracefully. * Path (b) β€” cypress_dpm_init itself fails (atom_parse_data_header fails on missing/garbage PowerPlayInfo at rv770_dpm.c:2279-2282, or DF-4117's alloc failure): radeon_pm.c:1448 ignores .dpm.init's error and evergreen.c:5235 ignores radeon_pm_init's error, so radeon_dpm_enable (radeon_pm.c:1453) still executes with the kzalloc-zeroed eg_pi (all feature flags 0): the :1837 branch is skipped, and with SMC firmware present the flow reaches :1878 cypress_init_smc_table(rdev, NULL) -> cypress_populate_smc_initial_state:1242 rv770_get_ps(NULL) -> page fault. (Without SMC firmware rv770_upload_firmware at :1867 fails first and returns β€” the DF-4023 graceful variant.) * cypress_dpm_disable:1953 cypress_force_mc_use_s1(rdev, boot_ps) has the same latent deref if ever reached with dpm enabled.

Twin of DF-4022 (rv770), DF-3972 (btc), DF-3754 (ni); the knowns for THIS file (DF-1385/1386/1387) do not cover it.

FIX: fix.diff β€” early if (boot_ps == NULL) return -EINVAL; guards in cypress_dpm_enable and cypress_dpm_disable. Kernel-level validation impossible here (no evergreen GPU): fix_status not_testable.

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_testable
baseline no→ patch + rebuild →patched clean

Diff authored but kernel-level validation requires evergreen hardware absent from the audit guest.

fix.diff; VERDICT.md
↓ fix.diffper-fix-DF-4118

Confirmed kernel references

Detail

Exploit chain

Crafted/missing BOOT-state VBIOS on an evergreen-family card -> kernel page-fault panic at radeon attach (DPM default-on) -> persistent boot DoS; precondition is physical/vBIOS access (option-ROM/vBIOS flash), matching the acceptance basis of the filed btc/rv770/ni twins.

Evidence (decisive lines)

VERDICT.md (both sub-paths with path:line); fix.diff (early boot_ps guards); env.txt (hardware absence)

PoC changes

No seed PoC; hardware-gated (no AMD evergreen GPU on the audit guest).

Verified recommended fix

Reject enable/disable when rdev->pm.dpm.boot_ps == NULL (fix.diff guards in cypress_dpm_enable/cypress_dpm_disable); long-term: honor dpm.init failure in radeon_pm.c.

Verdict

Source-level certain, runtime hardware-gated. rdev->pm.dpm.boot_ps is set only under ATOM_PPLIB_CLASSIFICATION_BOOT (rv770_dpm.c:2172-2173); two crafted-VBIOS shapes reach a NULL deref through this file's dispatch: (a) power table parses but no BOOT-classified state -> cypress_dpm_enable:1837-1839 cypress_force_mc_use_s0(rdev, NULL) -> rv770_get_ps(NULL) reads rps->ps_priv at NULL+offset (rv770_dpm.c:53-57) -> page fault; (b) cypress_dpm_init fails (missing PowerPlayInfo header / DF-4117 alloc failure) but radeon_pm.c:1448 discards .dpm.init's error and evergreen.c:5235 calls radeon_pm_init() as a statement, so radeon_dpm_enable executes on the kzalloc-zeroed eg_pi and, with SMC firmware present, cypress_init_smc_table(rdev, NULL) at cypress_dpm.c:1878 -> cypress_populate_smc_initial_state:1242 -> rv770_get_ps(NULL) -> page fault at boot/module-load. cypress_dpm_disable:1953 has the same latent deref. Twin of DF-4022/3972/3754; this file's knowns (DF-1385/1386/1387) do not cover it.