Integer divide-by-zero in spread-spectrum programming when VBIOS SS rate == 0 (or truncates to 0 via /=100)
Summary
ci_calculate_sclk_params and ci_calculate_mclk_params divide by ss.rate copied verbatim from the VBIOS SS table: v1 usSpreadRateInKhz has no zero check and V2/V3 do ss->rate /= 100, truncating any value <100 (in 10Hz) to exactly 0. Executes for every sclk/mclk level when the SS caps are set (true whenever the SS table header parses). Kernel #DE -> panic at ci_dpm_enable and resume. Twin of si_dpm DF-3612; distinct sink from known DF-1143 (fan table deltas). PoC demonstrates the truncation and traps SIGFPE at the exact expression on the guest.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3621 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| ci_ss_div0.c | β | 3.1 KB | view raw | |
| build.sh | β | 92 B | view raw | |
| run.sh | β | 116 B | view raw | |
| build.log | β | 393 B | view raw | |
| run.log | β | 393 B | view raw | |
| env.txt | β | 547 B | view raw | |
| VERDICT.md | β | 2.3 KB | β raw | |
| fix.diff | β | 2.2 KB | view raw |
DF-3621 VERDICT β divide-by-zero on VBIOS spread-spectrum rate == 0
Bottom line
Real bug, source-certain; runtime inconclusive (no AMD GPU on guest).
Two unguarded kernel integer divisions by the VBIOS-controlled spread spectrum rate:
ci_calculate_sclk_params()β ci_dpm.c:3337clk_s = reference_clock * 5 / (reference_divider * ss.rate);ci_calculate_mclk_params()β ci_dpm.c:2981clks = reference_clock * 5 / ss.rate;
ss.rate is filled by amdgpu_atombios_get_asic_ss_info()
(amdgpu_atombios.c:896-992) with no zero validation in any of the three
table revisions, and the V2/V3 paths additionally do ss->rate /= 100
(:959/:984), so even a non-zero VBIOS value below 100 (in 10Hz units)
truncates to exactly 0.
Reachability: pi->caps_sclk_ss_support / caps_mclk_ss_support are set to
true whenever the ASIC_InternalSS_Info header parses (ci_dpm.c:6052-6056);
the divides then execute for every graphics/memory level during
ci_dpm_enable β ci_init_smc_table β ci_populate_all_graphic_levels /
ci_populate_all_memory_levels (ci_dpm.c:3432-3444 / 3479-3487) β i.e., at
driver bind with a crafted VBIOS, and again on each resume.
On x86-64 a kernel integer division by zero raises #DE β panic.
Verification narrative
- Guest has no AMD ASIC (ramfb only) β kernel path unexecutable β inconclusive; module presence verified.
- Logic PoC
ci_ss_div0.cexecuted on the guest reproduces both the V2/V3/= 100truncation-to-zero and the actual machine division trapping (run.log: SIGFPE caught at sink [A], the ci_dpm.c:3337 expression; sinks [B]/[C] are the same instruction pattern). - Distinct from known DF-1143 (fan-table t_diff div-by-zero): different operands, different functions, different VBIOS fields. Twin: si_dpm DF-3612.
Fix
fix.diff wraps each SS-programming block in if (ss.rate) β skipping SS
setup for a zero rate is safe (the SSEN enable bit is simply not set).
Not testable on this guest (no AMD hardware).
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_testablefix.diff skips SS programming when rate==0 (SSEN simply not enabled); not testable without AMD hardware.
fix.diff; no AMD ASIC on guest for kernel baseline/patched runs
Confirmed kernel references
Detail
Exploit chain
crafted VBIOS with zero (or <100-in-10Hz) spread rate -> driver bind/resume -> integer #DE in kernel thread -> panic (DoS). No memory-corruption path.
Evidence (decisive lines)
run.log: 'usSpreadRateIn10Hz=50 -> ss.rate after /=100 = 0' followed by 'divide-by-zero trapped (SIGFPE ...) -> PANIC' at the ci_dpm.c:3337 expression; build.log clean.
PoC changes
authored from scratch; two iterations needed to defeat gcc -O2 const-folding of the divisors (made VBIOS values volatile, added SIGILL handler)
Verified recommended fix
Wrap the SS programming blocks in ci_calculate_sclk_params/ci_calculate_mclk_params in 'if (ss.rate)' (see fix.diff); optionally validate rate!=0 in amdgpu_atombios_get_asic_ss_info.
Verdict
Source-certain kernel divide-by-zero: ci_calculate_sclk_params (ci_dpm.c:3337) and ci_calculate_mclk_params (ci_dpm.c:2981) divide by ss.rate taken verbatim from the VBIOS SS table by amdgpu_atombios_get_asic_ss_info (amdgpu_atombios.c:936 v1 no zero check; :954+:959 / :976+:984 V2/V3 '/= 100' truncates any value <100 to exactly 0). Reached during ci_dpm_enable for every sclk/mclk level when the SS table header parses (caps_*_ss_support, ci_dpm.c:6052-6056). Kernel #DE -> panic. Runtime inconclusive: guest lacks any AMD ASIC; the truncation and the trapping division demonstrated on the guest by ci_ss_div0.c.
No comments yet.