Integer divide-by-zero in spread-spectrum programming when VBIOS usSpreadRateInKhz == 0 (si_calculate_sclk_params:4831 and si_populate_mclk_value:4931) β distinct sink from DF-1137
Summary
radeon_atombios_get_asic_ss_info copies ss->rate from the VBIOS ASIC_InternalSS_Info entry verbatim (no zero check) and returns true on match. si_calculate_sclk_params:4831 divides by (reference_divider * ss.rate) and si_populate_mclk_value:4931 divides by ss.rate for every power-level conversion whenever pi->sclk_ss/mclk_ss is armed by the same VBIOS tables. rate==0 -> div -> #DE -> kernel panic during si_dpm_enable state upload. VERIFIED: harness executes the exact expressions in forked children with rate=0 - both die SIGFPE (the userland face of kernel #DE); fixed-path rate=0 -> rc=-1 no trap, rate=30 -> rc=0 normal. Same malicious-VBIOS DoS family as DF-1137 (fan t_diff) but independent sinks.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3612 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| harness.c | β | 5.0 KB | view raw | |
| build.sh | β | 66 B | view raw | |
| run.sh | β | 90 B | view raw | |
| build.log | β | 11 B | view raw | |
| run.log | β | 821 B | view raw | |
| fix.diff | β | 1.1 KB | view raw | |
| fix_build.log | β | 1.6 KB | view raw | |
| fix_run.log | β | 196 B | view raw | |
| VERDICT.md | β | 2.8 KB | β raw | |
| README.md | β | 1.6 KB | β raw | |
| manifest.json | β | 755 B | view raw | |
| verdict.json | β | 2.9 KB | view raw |
DF-3612 β Integer divide-by-zero in spread-spectrum programming when VBIOS usSpreadRateInKhz == 0 (si_dpm.c:4831 and :4931)
Severity: Medium Confidence: certain Status: reproduced (harness) Impact: panic
What
radeon_atombios_get_asic_ss_info() copies ss->rate from the VBIOS ASIC_InternalSS_Info entry verbatim and returns true; si_calculate_sclk_params:4831 divides by (reference_divider * ss.rate) and si_populate_mclk_value:4931 divides by ss.rate whenever the SS entry matches the target clock (pi->sclk_ss/pi->mclk_ss set from the same VBIOS table). rate==0 -> div -> #DE -> kernel panic during si_dpm_enable power-state upload. Harness executes the exact expressions in forked children: SIGFPE (signal 4) on both sinks == kernel #DE panic. No AMD GPU on the audit guest for a live trigger.
Reproduce
sh build.sh # cc -O2 -Wall -o harness harness.c sh run.sh # prints [A] buggy-path behaviour, [B] fixed-path behaviour
Expected decisive output (see run.log): the [A] section shows the fault or
corruption the kernel would take; the [B] section shows the behaviour with
fix.diff applied.
No AMD GPU is attached to the audit QEMU guest (virtio-only), so the radeon DPM path cannot be exercised live; the harness replicates the exact kernel expressions with crafted-VBIOS inputs (house methodology, cf. DF-1137..1140).
Fix
fix.diff β validated: git apply --check clean; make si_dpm.o in
sys/dev/drm/radeon with KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC
compiles -Werror clean with all five pass-2 fixes stacked; harness [B]
shows the primitive gone.
DF-3612 β Verdict
Verdict: REPRODUCED (source-level + harness) β integer divide-by-zero (#DE) panic from crafted-VBIOS SS rate
Same malicious-VBIOS DoS family as DF-1137 (fan t_diff) but a distinct sink pair not covered by it.
Bug confirmation
The SS rate comes straight from the VBIOS with no zero check:
radeon_atombios.c:1543-1548 ss->percentage = le16(usSpreadSpectrumPercentage);
ss->type = ucSpreadSpectrumMode;
ss->rate = le16(usSpreadRateInKhz); // no check
return true; // "found"
si_dpm.c then divides by it on every matching state:
si_dpm.c:4829-4832 (si_calculate_sclk_params, pi->sclk_ss)
if (radeon_atombios_get_asic_ss_info(rdev, &ss, ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate); // :4831 #DE
u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000); // :4832 #DE when clk_s==0
si_dpm.c:4929-4932 (si_populate_mclk_value, pi->mclk_ss)
if (radeon_atombios_get_asic_ss_info(rdev, &ss, ASIC_INTERNAL_MEMORY_SS, freq_nom)) {
u32 clks = reference_clock * 5 / ss.rate; // :4931 #DE
pi->sclk_ss / pi->mclk_ss are enabled by rv770_get_engine_memory_ss
(si_dpm.c:7029) from the SAME VBIOS SS tables, so a crafted BIOS that sets
the SS-support firmware flag plus a zero-rate entry arms both sinks. The
functions run for every performance level of every power state during
si_dpm_enable (si_convert_power_level_to_smc -> si_populate_sclk_value /
si_populate_mclk_value). On x86-64, div with divisor 0 raises #DE ->
kernel panic.
Harness confirmation
run.log:
[A1] engine SS ... child died from SIGFPE (signal 4): integer divide by zero [A2] memory SS ... child died from SIGFPE (signal 4): integer divide by zero [B] rate=0 -> rc=-1 (SS skipped, no trap) ... rate=30 -> rc=0
Trigger conditions (not met on this guest)
SI GPU + radeon DPM (guest is virtio-only) + crafted VBIOS SS entry.
Exploit chain
None β #DE is not steerable; boot-time DoS panic.
Fix
fix.diff β if (ss.rate == 0) return -EINVAL; in both SS blocks.
Validation: apply-check OK; make si_dpm.o -Werror clean (stacked);
harness [B] no trap, sane-rate path unchanged (rc=0, clk values computed).
fix_status: fixed (compile + harness-level).
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
fixedgit apply --check OK (standalone and stacked with the other four si_dpm.c fixes); targeted module TU compile make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC si_dpm.o => rc=0, -Werror clean (87080 B). Harness fixed-path shows the primitive gone (fix.diff adds if (ss.rate == 0) return -EINVAL; in both SS blocks. git apply --check OK; stacked module TU compile -Werror clean; harness [B] no trap with sane-rate path still rc=0.)
fix.diff adds `if (ss.rate == 0) return -EINVAL;` in both SS blocks. git apply --check OK; stacked module TU compile -Werror clean; harness [B] no trap with sane-rate path still rc=0.
Confirmed kernel references
Detail
Exploit chain
crafted VBIOS SS entry with usSpreadRateInKhz=0 + SS tables present -> sclk/mclk SS programming on every power-level conversion -> div by 0 -> #DE -> panic at DPM enable (boot-time DoS)
Evidence (decisive lines)
run.log [A1]/[A2]: 'child died from SIGFPE (signal 4): integer divide by zero' at both :4831 and :4931 replicas; [B]: 'rate=0 -> rc=-1 (SS skipped, no trap)'
PoC changes
n/a (pass-2 finding authored with its harness; no seeded PoC to fix)
Verified recommended fix
see fix.diff
Verdict
Same malicious-VBIOS DoS family as DF-1137 (fan-table t_diff) but a distinct sink pair. radeon_atombios_get_asic_ss_info() copies ss->rate from the VBIOS ASIC_InternalSS_Info entry verbatim and returns true; si_calculate_sclk_params:4831 divides by (reference_divider * ss.rate) and si_populate_mclk_value:4931 divides by ss.rate whenever the SS entry matches the target clock (pi->sclk_ss/pi->mclk_ss set from the same VBIOS table). rate==0 -> div -> #DE -> kernel panic during si_dpm_enable power-state upload. Harness executes the exact expressions in forked children: SIGFPE (signal 4) on both sinks == kernel #DE panic. No AMD GPU on the audit guest for a live trigger.
No comments yet.