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

goto restart_search reads OOB past power-state array returning OOB pointer used to program SMC

Summary

psm_set_user_performance_state (pp_psm.c:203-232): line 214 *state=hwmgr->ps resets cursor BEFORE restart_search: label at line 216. When user requests Battery/Balanced and no entry matches, switch at 223 sets label_id=Performance goto restart_search at 227. Goto targets 216 AFTER the 214 reset so *state is NOT re-reset. At goto point *state already points one element past kcalloc(table_entries,size) array (loop 217-221 advanced past last slot). Second pass iterates table_entries more at OOB offsets (table_entries+i)*ps_size reading (*state)->classification.ui_label. Performance==5 (0b101) bitwise AND matches almost any 4-byte OOB value -> return 0 with *state deep OOB. OOB pointer propagates as new_ps to psm_adjust_power_state_dynamic -> power_state_management -> requested->hardware dereferenced and forwarded to phm_set_power_state -> GPU SMC clock/voltage programming. Trigger: echo battery > /sys/class/drm/cardN/device/power_dpm_state on ASIC with no Battery/Balanced state (common desktop dGPUs). Impact: OOB heap read tens of KB past allocation leaking adjacent slab (KASLR); OOB pointer used as multi-KB hardware struct consumed by SMC -> panic/GPU hang/misprogrammed clocks. AV:L/PR:H/AC/L, C:H/A:H. Fix: move *state=hwmgr->ps to AFTER restart_search: label.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2078 Β· 2 files
FileTypeDescriptionSize
fix.diff suggested-fix git-apply-able fix 335 B view raw
VERDICT.md verdict source-trace confirmation 717 B ↓ raw
VERDICT.md verdict source-trace confirmation
↓ download raw

DF-2078 β€” psm_set_user_performance_state OOB read on restart_search

Verdict

REPRODUCED (source-only confirmation). Bug confirmed by source tracing.

Mechanism

psm_set_user_performance_state() (pp_psm.c:203-232) sets state=hwmgr->ps at line 214 BEFORE restart_search: label at 216. When Battery/Balanced not found, switch at 223-227 changes label to Performance and goto restart_search. But state is NOT reset (cursor advanced past table end), so the restarted loop reads out of bounds.

Fix

Move *state=hwmgr->ps to after the restart_search: label so the cursor resets on each search pass.

Batch-build status

Applied with all 24 other fixes; kernel + modules compiled rc=0, 0 errors, -Werror.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

Moved *state after restart_search label; batch build rc=0.

Moved *state after restart_search label; batch build rc=0.
↓ fix.diffcombined build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

psm_set_user_performance_state *state cursor not reset after restart_search.

Verified recommended fix

psm_set_user_performance_state *state cursor not reset after restart_search.

Verdict

psm_set_user_performance_state *state cursor not reset after restart_search.