Divide-by-zero in spread spectrum clock calculation via ss.rate == 0
Summary
ni_calculate_sclk_params() at ni_dpm.c:2044: divides by ss.rate from VBIOS ASIC_InternalSS_Info V3 table. radeon_atombios_get_asic_ss_info divides ss.rate/=100 at radeon_atombios.c:1594; if BIOS usSpreadRateIn10Hz<100, ss.rate truncates to 0 -> divide-by-zero panic. Same at ni_populate_mclk_value() :2246. Sibling of DF-1128/DF-1143/DF-1166 div-by-zero fan pattern. Fix: check ss.rate==0 before division, return -EINVAL.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1204 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | source-level analysis: ss.rate/=100 truncates to 0, downstream divides by zero | 2.8 KB | β raw |
| fix.diff | suggested-fix | guard ss.rate<100 before /=100 in both v2 and v3 parsers | 1.4 KB | view raw |
| build.sh | build-script | no-op (no userspace PoC; driver-gated) | 444 B | view raw |
| run.sh | run-script | no-op (no AMD GPU on guest) | 264 B | view raw |
| fix_build.log | build-log | cumulative kernel build with all 5 fixes applied, NK_DONE rc=0 | 5.6 MB | β download |
| env.txt | environment | guest uname, PCI topology, target HW required | 1.2 KB | view raw |
| README.md | readme | human reproduce doc | 976 B | β 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-1204 β radeon div-by-zero in spread-spectrum clock calc (build/run scripts)
Hardware+config-gated (AMD/ATI Cayman/Northern-Islands GPU + radeon.ko +
ni_dpm). radeon is not in GENERIC and no AMD GPU is present on this guest.
See VERDICT.md.
Files
VERDICT.mdβ detailed source-level analysisfix.diffβ git-apply-able patch guarding ss->rate /= 100env.txtβ guest environment snapshotfix_build.logβ kernel-build output (cumulative batch)
build.sh
#!/bin/sh
echo 'build.sh: no userspace PoC for DF-1204 (driver-gated).'
echo 'To validate the fix, apply fix.diff and build a kernel + modules:'
echo ' cd /usr/src && patch -p1 < fix.diff && make -j6 nativekernel KERNCONF=X86_64_GENERIC'
run.sh
#!/bin/sh
echo 'run.sh: DF-1204 is hardware-gated (AMD/ATI GPU + radeon.ko).'
echo 'radeon is not in GENERIC and no AMD GPU is present on this guest.'
echo 'See VERDICT.md for the source-level confirmation.'
DF-1204 β radeon divide-by-zero in spread-spectrum clock calculation
Verdict
NOT REPRODUCED (source-confirmed; hardware+config-gated). The div-by-zero
is real in both call sites that consume ss.rate, and the truncation that
zeroes it is real in both the v2 and v3 parsers of the VBIOS
ASIC_InternalSS_Info table. But radeon is not in GENERIC and no AMD/ATI GPU
is present on this QEMU/KVM guest. No runtime trigger; validated by line-level
source trace + single-fix kernel build.
Mechanism
radeon_atombios_get_asic_ss_info (sys/dev/drm/radeon/radeon_atombios.c:1506)
parses the VBIOS ASIC_InternalSS_Info table. For the engine-clock (SCLK) and
memory-clock (MCLK) spread-spectrum assignments the rate field is read in
"10 Hz" units and then divided by 100 to convert to Hz:
- v2 (
crev==2),radeon_atombios.c:1564-1569:c ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz); ... if ((crev == 2) && ((id == ASIC_INTERNAL_ENGINE_SS) || (id == ASIC_INTERNAL_MEMORY_SS))) ss->rate /= 100; - v3,
radeon_atombios.c:1586-1594:c ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz); ... if ((id == ASIC_INTERNAL_ENGINE_SS) || (id == ASIC_INTERNAL_MEMORY_SS)) ss->rate /= 100;
If the BIOS reports usSpreadRateIn10Hz < 100 (i.e. < 10 kHz), the integer
divide truncates to 0. Downstream, that zero flows into:
ni_calculate_sclk_params(sys/dev/drm/radeon/ni_dpm.c:2044):c u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);ni_populate_mclk_value(ni_dpm.c:2246):c clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
Both perform an integer division by ss.rate and would trap #DE (kernel
panic) on a Cayman/Northern Islands GPU whose VBIOS carries a malformed
spread-spectrum entry. This is the same family of div-by-zero panics as
DF-1128/DF-1143/DF-1166 (fan div-by-zero).
Why not triggered on this guest
Same as DF-1200: radeon is not in GENERIC, no AMD GPU is present (vgapci0 is
QEMU std VGA), and ni_dpm (Cayman/Northern-Islands DPM) only attaches to a
small subset of radeon GPUs that are not emulated by QEMU. Option (d).
Recommended fix (in fix.diff)
Defend the division at the source: in both the v2 and v3 branches of
radeon_atombios_get_asic_ss_info, return false (no valid SS info) when
ss->rate < 100 before the /= 100 truncation. This is preferable to
guarding ni_calculate_sclk_params / ni_populate_mclk_value because it
kills the bad value at the parser boundary, the same way a real BIOS
malfunction should be reported, and the DPM callers already test the boolean
return and disable SS when it is false.
Build validation
Cumulative kernel build with all 5 fixes applied β NK_DONE rc=0. See
fix_build.log.
Reproduce
./build.sh # no-op ./run.sh # no-op
Fix verification
not_testablecompile validated
nativekernel rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. radeon ss.rate/=100 truncates to 0 -> div-by-zero in ni_dpm. radeon not in GENERIC.
No comments yet.