uint32 underflow in vega20_apply_clocks_adjust_rules: count-1 wraps to UINT32_MAX causing ~4B-iteration heap OOB read
Summary
vega20_apply_clocks_adjust_rules at vega20_hwmgr.c:3095-3104: if(disable_mclk_switching) { for(i=0;i<data->mclk_latency_table.count-1;i++) {...} }. count is uint32, kzalloc default 0. count-1 wraps to UINT32_MAX -> entries[i]/dpm_levels[i] read OOB past [16] arrays. disable_mclk_switching=true on multi-monitor out-of-sync. Triggered on display config change before vega20_get_memclocks runs. Sibling of DF-1179 (vega10). Fix: check count>0 before loop, guard dpm_table->count==0.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1253 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | source trace, underflow mechanism, impact ceiling, fix rationale | 3.1 KB | β raw |
| fix.diff | suggested-fix | guard count==0 + rewrite loop bound as i+1<count with MAX_REGULAR_DPM_NUMBER cap | 1.4 KB | view raw |
| fix_build.log | build-log | vega20_hwmgr.o compiled with fix, RC=0, no warnings | 3.9 KB | view raw |
| build.sh | build-log | repro: apply-check + note | 382 B | view raw |
| run.sh | run-log | no runtime trigger (no HW) | 367 B | view raw |
| env.txt | environment | uname, cc version, module state | 359 B | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1253 β uint32 underflow in vega20_apply_clocks_adjust_rules (count-1 wraps to UINT32_MAX)
Verdict
SOURCE-CONFIRMED (real bug), INCONCLUSIVE at runtime β the amdgpu.ko module is not loaded (no AMD Vega20 GPU in the QEMU guest) and is not in the GENERIC kernel, so the underflow path is dormant. Fix authored and compile-validated.
Mechanism (source trace)
vega20_apply_clocks_adjust_rules() iterates over the MCLK latency table using a uint32_t count - 1 loop bound with no zero-guard:
sys/dev/drm/amd/powerplay/hwmgr/vega20_hwmgr.c:3095-3104:if (disable_mclk_switching) { dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; for (i = 0; i < data->mclk_latency_table.count - 1; i++) { /* <- UNDERFLOW */ if (data->mclk_latency_table.entries[i].latency <= latency) { if (dpm_table->dpm_levels[i].value >= ...) { ... } } } }data->mclk_latency_table.countisuint32_t(vega20_hwmgr.h:267), default 0 after kzalloc. It is set non-zero only byvega20_get_memclocks()(vega20_hwmgr.c:2435). Ifvega20_apply_clocks_adjust_rulesruns beforevega20_get_memclockspopulates the table,count - 1wraps to0xFFFFFFFFβ the loop iterates ~4 billion times, readingentries[i]anddpm_levels[i]OOB past theirMAX_REGULAR_DPM_NUMBER=16arrays (vega20_hwmgr.h:159,268).disable_mclk_switchingistruewhen1 < num_display && !multi_monitor_in_sync(multi-monitor out of sync) orvblank_too_short(vega20_hwmgr.c:3037-3039) β a plausible state on a multi-monitor Vega20 system when display config changes.- The same
count - 1OOB pattern also appears at lines 3045/3047/3069/3071/3096/3108 fordpm_table->count, though those are guarded byvega20_setup_default_dpm_tablessettingcount >= 1(vega20_hwmgr.c:598).
Why not reproduced at runtime
amdgpu.kois not loaded on the guest and is not in X86_64_GENERIC.- Requires an AMD Vega20 GPU (Radeon VII / Vega 20); QEMU guest has no AMD GPU.
- On real hardware, an unprivileged user changing display config (hotplug, mode set) could influence
num_display/multi_monitor_in_syncand trigger the underflow if the power-management state machine callsapply_clocks_adjust_rulesbeforeget_memclocks.
Fix (fix.diff, compile-validated)
- Guard
dpm_table->count == 0before thecount - 1accesses in thedisable_mclk_switchingandnb_pstate_switch_disableblocks (skip via agoto skip/ early return). - Rewrite the latency loop bound as
i + 1 < data->mclk_latency_table.count(no underflow when count is 0) and add a hardi < MAX_REGULAR_DPM_NUMBERcap as defense-in-depth.
The patched vega20_hwmgr.c compiles cleanly with gcc 8.3, -Werror, no warnings.
Realistic impact ceiling
Kernel heap OOB read (entries[]/dpm_levels[] past [16]) of up to ~4B iterations on a Vega20 system when MCLK switching is disabled before the latency table is populated β a DoS (hang/panic from OOB read or page fault) and potential info leak. On this guest: not reachable (no AMD GPU).
Fix verification
not_testablecompile validated
module/object build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. vega20 count-1 uint32 underflow -> 4B OOB loop. amdgpu not in GENERIC, no Vega20 GPU.
No comments yet.