SS getters return success with speed_spectrum_rate == 0 β integer divide-by-zero panic in every clock-spread consumer
Summary
The SS assignment getter copies the raw VBIOS rate and, for rev >=2.2/3, integer-divides by 100 - so explicit zeros and any value <100 become rate==0 - then returns success; the ci/iceland/fiji smumgr consumers immediately divide by this value with no zero check, panicking with a divide error at attach. Single-point fix at the producer neutralizes all five consumer divisions. Reject-rate-0 fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4290 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.6 KB | β raw | |
| VERDICT.md | β | 2.7 KB | β raw | |
| fix.diff | β | 1.0 KB | view raw | |
| manifest.json | β | 884 B | view raw | |
| verdict.json | β | 2.4 KB | view raw | |
| env.txt | β | 962 B | view raw |
DF-4290 β SS getters emit success with speed_spectrum_rate == 0 β integer divide-by-zero panic in clock-spread callers
Pass-2 finding for sys/dev/drm/amd/powerplay/hwmgr/ppatomctrl.c
(the "(c) rate==0 div0 family" hinted by the pass-2 brief).
The bug
asic_internal_ss_get_ss_asignment() copies the raw VBIOS rate into the
caller-visible struct and returns success without validating it
(ppatomctrl.c:1245-1254):
if (entry_found) {
ssEntry->speed_spectrum_percentage =
le16_to_cpu(ssInfo->usSpreadSpectrumPercentage);
ssEntry->speed_spectrum_rate = le16_to_cpu(ssInfo->usSpreadRateInKhz); // :1248
if (((GET_DATA_TABLE_MAJOR_REVISION(table) == 2) &&
(GET_DATA_TABLE_MINOR_REVISION(table) >= 2)) ||
(GET_DATA_TABLE_MAJOR_REVISION(table) == 3)) {
ssEntry->speed_spectrum_rate /= 100; // :1253
}
...
}
return entry_found ? 0 : 1;
- A VBIOS
usSpreadRateInKhz == 0stays 0. - For table revision β₯ 2.2 or 3, any value < 100 truncates to 0
(
/=integer division) β e.g. a legal-looking 30 kHz rate becomes 0.
The unvalidated value is then used as a divisor by every consumer:
| Consumer | Division | File:line |
|---|---|---|
| CI engine SS | clk_s = ref_clock * 5 / (ref_divider * ss_info.speed_spectrum_rate) |
sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.c:345-346 |
| CI memory SS | clks = reference_clock * 5 / ss_info.speed_spectrum_rate |
sys/dev/drm/amd/powerplay/smumgr/ci_smumgr.c:1085 |
| Iceland engine SS | clkS = reference_clock * 5 / (reference_divider * ss_info.speed_spectrum_rate) |
sys/dev/drm/amd/powerplay/smumgr/iceland_smumgr.c:849 |
| Iceland memory SS | same shape | iceland_smumgr.c:~1131 |
| Fiji engine SS | (ref_divider * ssInfo.speed_spectrum_rate) divisor |
fiji_smumgr.c:914 |
(None of the callers checks for zero; the getter's return 0 is taken as
"values are usable".)
Trigger: crafted VBIOS on a CI/Bonaire/Hawaii (ci), Topaz/Volcanic
(iceland), Fiji (or Tonga/VegaM analogues) dGPU that
(1) sets the PHM_PlatformCaps_{Engine,Memory}SpreadSpectrumSupport cap,
(2) provides an ASIC_InternalSS_Info entry matching the target clock with
usSpreadRateInKhz == 0 (or < 100 on revβ₯2.2 tables).
Result: integer divide-by-zero in kernel β Fatal trap 0: divide error
panic during SMC table construction at driver attach (CWE-369).
Reproduce
Not runnable on this audit guest (no AMD dGPU β env.txt). On hardware the
trigger is purely VBIOS content; expected Fatal trap 0: divide error
faulting in ci_program_display_gap/ci_populate_smc_* clock-spread
setup paths.
DF-4290 VERDICT β SS rate==0 divide-by-zero
Status: inconclusive (code-trace certain; guest has no AMD dGPU)
Trace
- Producer:
asic_internal_ss_get_ss_asignment()ppatomctrl.c:1245-1254. - :1248ssEntry->speed_spectrum_rate = le16_to_cpu(ssInfo->usSpreadRateInKhz);β raw USHORT from the VBIOS table, no zero check. - :1250-1254 forGET_DATA_TABLE_MAJOR_REVISION==2 && minor>=2or major==3:ssEntry->speed_spectrum_rate /= 100;β integer division; values 0..99 collapse to 0. (GET_DATA_TABLE_*_REVISION readtable->sHeaderβ same header whose usStructureSize is unvalidated, see DF-4289; the revision bytes are likewise VBIOS-controlled.) - :1272return entry_found ? 0 : 1;β success. - Consumers (all reached from
*_populate_*SMC-table construction at driver attach, gated only on the VBIOS-provided PHM_PlatformCaps_*SpreadSpectrumSupport caps): - ci_smumgr.c:338-356 βif (!atomctrl_get_engine_clock_spread_spectrum(...))then:345 clk_s = ref_clock * 5 / (ref_divider * ss_info.speed_spectrum_rate);β DIV by 0 when rate==0 and ref_divider!=0 (ref_divider=1 typical); the productref_divider * rateis a u32 multiply, 0 either factor β divide error (#DE) β kernel panic. - ci_smumgr.c:1084-1088 β memory-clock variant, same shape at :1085. - iceland_smumgr.c:843-859 β same at :849. - iceland_smumgr.c:1125-1135 family β same shape at :1131. - fiji_smumgr.c:909-915 β same at :914. - tonga/vegam equivalents exist for their SS-capable SKUs. - No consumer checks
speed_spectrum_rate != 0before dividing; the getter returning 0 (success) is treated as a green light. - x86-64 kernel #DE β
Fatal trap 0: divide errorβ panic during kldload/attach (non-recoverable; attach holds device locks).
Why the finding is filed against ppatomctrl.c
The zero value is manufactured in this file (:1248 raw copy, :1253 truncating division); the single-point fix is to fail the lookup when the rate is not usable, which neutralizes every downstream division at once. (Callers adding their own guards is defense-in-depth.)
Impact
Crafted-VBIOS boot/module-load kernel panic (CWE-369). Medium β same threat band as DF-1497 (NULL-deref panic from VBIOS content). Not runnable on this guest (no AMD dGPU) β inconclusive status, trace-certain.
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_testableBaseline behavior not reproducible on this guest (no AMD dGPU) -> no fixed-kernel build possible. fix.diff authored from trace.
findings/poc/DF-4290/fix.diff (not applied to sys/; authored post-verification from line-accurate trace)
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (producer/consumer trace with all division sites); README.md; fix.diff (zero-rate rejection at the getter); env.txt
PoC changes
n/a β no AMD dGPU on guest; code-trace evidence pack
Verified recommended fix
Reject SS assignments whose computed speed_spectrum_rate is 0 (return not-found) in asic_internal_ss_get_ss_asignment
Verdict
asic_internal_ss_get_ss_asignment() returns success with speed_spectrum_rate copied raw from the VBIOS (ppatomctrl.c:1248) and then integer-divided by 100 for table rev >= 2.2/3 (ppatomctrl.c:1253) β so both an explicit usSpreadRateInKhz of 0 and any value < 100 produce rate == 0 with return code 0 (success). Every consumer divides by this value with no zero check: ci_smumgr.c:345-346 (ref_clock5/(ref_dividerrate)), ci_smumgr.c:1085, iceland_smumgr.c:849 and :1131, fiji_smumgr.c:914 β kernel integer divide-by-zero (Fatal trap 0: divide error) panic during SMC table construction at driver attach (CWE-369). Single-point fix at the producer: fail the lookup when the rate is unusable. Crafted-VBIOS threat model, Medium (panic band, same as DF-1497). Not runnable on this guest (no AMD dGPU β env.txt); trace-certain.
No comments yet.