β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-4290

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4290 Β· 6 files
FileTypeDescriptionSize
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 == 0 stays 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.

VERDICT.md
↓ download raw

DF-4290 VERDICT β€” SS rate==0 divide-by-zero

Status: inconclusive (code-trace certain; guest has no AMD dGPU)

Trace

  1. Producer: asic_internal_ss_get_ss_asignment() ppatomctrl.c:1245-1254. - :1248 ssEntry->speed_spectrum_rate = le16_to_cpu(ssInfo->usSpreadRateInKhz); β€” raw USHORT from the VBIOS table, no zero check. - :1250-1254 for GET_DATA_TABLE_MAJOR_REVISION==2 && minor>=2 or major==3: ssEntry->speed_spectrum_rate /= 100; β€” integer division; values 0..99 collapse to 0. (GET_DATA_TABLE_*_REVISION read table->sHeader β€” same header whose usStructureSize is unvalidated, see DF-4289; the revision bytes are likewise VBIOS-controlled.) - :1272 return entry_found ? 0 : 1; β€” success.
  2. 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 product ref_divider * rate is 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.
  3. No consumer checks speed_spectrum_rate != 0 before dividing; the getter returning 0 (success) is treated as a green light.
  4. 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_testable
baseline no→ patch + rebuild →patched clean

Baseline 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)
↓ fix.diffper-fix-DF-4290

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.