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

NULL-pointer dereference of adev->pm.dpm.boot_ps when the VBIOS power table has no ATOM_PPLIB_CLASSIFICATION_BOOT state

Summary

boot_ps is assigned only when a BOOT-classified state exists; ci_dpm_enable -> ci_init_smc_table -> ci_populate_smc_initial_state -> ci_get_ps(NULL) executes rps->ps_priv on NULL and boot_state->performance_levels[0].sclk; ci_update_current_ps(adev, NULL) and ci_dpm_disable hold the same unguarded pointer. Kernel NULL-page fault at driver bind and every resume. PoC walks the exact chain and SIGSEGVs at NULL+offsetof(ps_priv) on the guest. Twin of amdgpu DF-3586 / radeon DF-3610.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3623 Β· 8 files
FileTypeDescriptionSize
ci_bootps_null.c β€” 3.1 KB view raw
build.sh β€” 92 B view raw
run.sh β€” 116 B view raw
build.log β€” 353 B view raw
run.log β€” 353 B view raw
env.txt β€” 547 B view raw
VERDICT.md β€” 2.3 KB ↓ raw
fix.diff β€” 428 B view raw
VERDICT.md
↓ download raw

DF-3623 VERDICT β€” unvalidated boot_ps NULL dereference

Bottom line

Real bug, source-certain; runtime inconclusive (no AMD GPU on guest).

adev->pm.dpm.boot_ps is only ever assigned in ci_parse_pplib_non_clock_info() (ci_dpm.c:5573-5574) and only when the VBIOS power table contains a state classified ATOM_PPLIB_CLASSIFICATION_BOOT. A crafted (or simply malformed) VBIOS without such a state leaves boot_ps == NULL; nothing between the parser and the consumer checks it:

  • ci_dpm_enable() ci_dpm.c:5297 β€” boot_ps = adev->pm.dpm.boot_ps; (NULL)
  • ci_init_smc_table() ci_dpm.c:3704 β€” amdgpu_boot_state = boot_ps; then ci_dpm.c:3786 ci_populate_smc_initial_state(adev, amdgpu_boot_state)
  • first dereference: ci_get_ps() ci_dpm.c:326-331 executes rps->ps_priv on the NULL pointer; the second, boot_state->performance_levels[0].sclk at ci_dpm.c:2731 (and .mclk at :2739)
  • the tail of a successful enable would additionally deref NULL in ci_update_current_ps(adev, boot_ps) (ci_dpm.c:5412 β†’ 5245-5248: *rps copies). ci_dpm_disable() has the same unguarded boot_ps (ci_dpm.c:5420/5450).

NULL-page dereference in the device-init kernel thread β†’ panic at driver bind (and at each resume, since ci_dpm_resume β†’ ci_dpm_enable).

Verification narrative

  • Guest lacks any AMD ASIC β†’ the kernel path cannot execute β†’ inconclusive; module presence verified.
  • ci_bootps_null.c executed on the guest walks the exact call chain with a BOOT-less classification and traps SIGSEGV at NULL+offsetof(ps_priv) (run.log) β€” the userspace image of the kernel NULL-page fault.
  • Same defect class and fix as the si_dpm twins DF-3586 / DF-3610 (upstream radeon fixed this class by failing init when boot_ps is NULL).

Fix

fix.diff fails ci_dpm_init() with -EINVAL right after ci_parse_power_table() when no BOOT state was found, preventing the later dereferences. Not testable on this guest.

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

fix.diff aborts dpm init cleanly when no BOOT state exists; not testable without AMD hardware.

fix.diff; no AMD ASIC on guest
↓ fix.diffper-fix-DF-3623

Confirmed kernel references

Detail

Exploit chain

crafted VBIOS without a BOOT-classified state -> NULL deref in device-init kernel thread -> panic (DoS). No memory-corruption path.

Evidence (decisive lines)

run.log shows boot_ps=0x0 and the SIGSEGV at NULL+40 with the traced ci_dpm.c line sequence; build.log clean.

PoC changes

authored from scratch

Verified recommended fix

After ci_parse_power_table() in ci_dpm_init(), fail with -EINVAL when adev->pm.dpm.boot_ps is NULL (see fix.diff).

Verdict

Source-certain NULL-pointer dereference: with no ATOM_PPLIB_CLASSIFICATION_BOOT state in the VBIOS power table, adev->pm.dpm.boot_ps stays NULL (only assigned at ci_dpm.c:5573-5574) and is dereferenced by ci_get_ps (rps->ps_priv, ci_dpm.c:328) via ci_populate_smc_initial_state (ci_dpm.c:3786, reached from ci_dpm_enable:5297 -> ci_init_smc_table:3704), then again at boot_state->performance_levels[0].sclk (ci_dpm.c:2731) β€” kernel NULL-page fault/panic at driver bind and on every resume; ci_update_current_ps (ci_dpm.c:5412) and ci_dpm_disable (ci_dpm.c:5450) hold the same unguarded boot_ps. Runtime inconclusive: guest has no AMD ASIC; the exact chain demonstrated on the guest by ci_bootps_null.c (SIGSEGV at NULL+offsetof(ps_priv)).