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

Integer divide-by-zero on zero MPLL reference clock in ci_calculate_mclk_params (usMemoryReferenceClock stored unchecked)

Summary

adev->clock.mpll.reference_freq is assigned verbatim from FirmwareInfo.usMemoryReferenceClock with no zero fixup (unlike pll_out_min). ci_calculate_mclk_params divides freq_nom by it inside the caps_mclk_ss_support block; freq_nom cannot be 0 (mclk==0 rejected), so a zero reference clock plus any parseable SS header is an unconditional #DE panic at ci_dpm_enable -> ci_populate_all_memory_levels. Twin of si_dpm DF-3613. The SPLL reference clock is only ever a multiplier in this file - the mpll path is the sole reference-clock divide.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3622 Β· 8 files
FileTypeDescriptionSize
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.4 KB ↓ raw
fix.diff β€” 576 B view raw
VERDICT.md
↓ download raw

DF-3622 VERDICT β€” divide-by-zero on zero MPLL reference clock

Bottom line

Real bug, source-certain; runtime inconclusive (no AMD GPU on guest).

ci_calculate_mclk_params() divides by adev->clock.mpll.reference_freq without checking it (ci_dpm.c:2977):

u32 reference_clock = adev->clock.mpll.reference_freq;   /* :2970 */
...
tmp = (freq_nom / reference_clock);                      /* :2977 β€” #DE if 0 */

The value is copied verbatim from the VBIOS FirmwareInfo table (usMemoryReferenceClock) at amdgpu_atombios.c:659-660 β€” with no zero fixup, in contrast to the neighboring pll_out_min fields that do get == 0 β†’ 64800 corrections (:642-643, :668-670). A crafted VBIOS with usMemoryReferenceClock == 0 plus any parseable ASIC_InternalSS_Info header (needed for caps_mclk_ss_support, ci_dpm.c:6052-6056, which gates the divide) triggers the division at driver enable time.

freq_nom is memory_clock * 2|4 * (1 << post_div) and cannot be zero (mclk == 0 rejected at ci_dpm.c:3480-3481), so zero reference clock is an unconditional #DE β†’ panic during ci_dpm_enable β†’ ci_populate_all_memory_levels β†’ ci_populate_single_memory_level β†’ ci_calculate_mclk_params (called at ci_dpm.c:3107), i.e. at boot/bind and on every resume.

Note the sibling ci_calculate_sclk_params only ever multiplies by the SPLL reference clock β€” the mpll path is the only reference-clock divide in this file. (For completeness: ci_program_display_gap divides by refresh_rate, but that is guarded 0β†’60 at ci_dpm.c:2133-2134.)

Verification narrative

  • Guest lacks any AMD ASIC β†’ kernel path unexecutable β†’ inconclusive; module presence verified (amdgpu.ko loads).
  • The shared ci_ss_div0.c executed on the guest demonstrates sink [C]: the exact freq_nom / reference_clock division with usMemoryReferenceClock = 0 (run.log).
  • Twin of si_dpm DF-3613.

Fix

fix.diff returns -EINVAL from ci_calculate_mclk_params when the mpll reference clock is zero (SS setup cannot be computed); enable then fails cleanly instead of panicking. Not testable on this guest.

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

fix.diff fails enable cleanly on zero reference clock instead of panicking; not testable without AMD hardware.

fix.diff; no AMD ASIC on guest
↓ fix.diffper-fix-DF-3622

Confirmed kernel references

Detail

Exploit chain

crafted VBIOS -> driver bind/resume -> integer #DE in kernel thread -> panic (DoS). No memory-corruption path.

Evidence (decisive lines)

run.log sink [C] block; amdgpu_atombios.c:659-660 contrast with the pll_out_min zero-fixups at :642/:668 in VERDICT.md.

PoC changes

shared binary with DF-3621; sink [C] is the DF-3622-specific demonstration

Verified recommended fix

Return -EINVAL from ci_calculate_mclk_params when adev->clock.mpll.reference_freq == 0 (see fix.diff), or zero-fixup usMemoryReferenceClock in amdgpu_atombios_get_clock_info like pll_out_min.

Verdict

Source-certain kernel divide-by-zero: ci_calculate_mclk_params (ci_dpm.c:2977) divides freq_nom by adev->clock.mpll.reference_freq, which amdgpu_atombios_get_clock_info stores verbatim from FirmwareInfo.usMemoryReferenceClock (amdgpu_atombios.c:659-660) with no zero fixup. A crafted VBIOS with zero usMemoryReferenceClock plus a parseable ASIC_InternalSS_Info header (to set caps_mclk_ss_support, ci_dpm.c:6052-6056, gating the divide) yields an unconditional #DE panic at ci_dpm_enable (memory-level population, ci_dpm.c:3107) on boot and resume. Runtime inconclusive: no AMD ASIC on the guest; the trapping arithmetic demonstrated by the shared ci_ss_div0.c (run.log sink [C]).