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

Divide-by-zero kernel panic in amdgpu_pll_compute when target_clock or post_div is zero

Summary

amdgpu_pll_compute() performs unchecked integer division by target_clock (lines 172 post_div_min=vco_min/target_clock, 178 post_div_max=vco_max/target_clock) and after post_divider search by post_div (lines 88 ref_div_max=min(128/post_div,ref_div_max), 91, 242 final dot_clock formula divides by ref_div*post_div*10). When target_clock==0 (non-FRAC path freq in [1,9] -> freq/10==0; caller dce_v*0 guards only adjusted_clock==0 not <10) lines 172/178 trap immediately. When target_clock>vco_max: post_div_max=0 at 178; --post_div_max at 180 not executed (0>vco_max false); loop at 199 doesnt execute (post_div_min>=1>0); unless AMDGPU_PLL_PREFER_MINM_OVER_MAXP set post_div_best=post_div_max=0 at 196; line 213/216 calls get_fb_ref_div with post_div=0 trapping at line 88. Even with PREFER_MINM final formula at 242-244 divides by ref_div*post_div*10. Function never validates target_clock nonzero or post_div_max>=max(post_div_min,1) before dividing. Attacker: local DRM master/VT user issues modeset with degenerate clock (mode.clock=5 or >pll_out_max); DRM_IOCTL_MODE_SETCRTC or atomic commit. Result: kernel divide-by-zero -> panic -> local DoS. AC:H because exact trigger ASIC/firmware-dependent (FRAC path raises vco limits 10x narrowing window; non-FRAC/fixed-post-div/tiny-clock paths remain live). AV:L/AC:H/PR:L, A:H.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2037 Β· 3 files
FileTypeDescriptionSize
VERDICT.md verdict Source-confirmation verdict for DF-2037 672 B ↓ raw
fix.diff suggested-fix Guard target_clock==0 to prevent divide-by-zero 396 B view raw
../fix_build.log build-log Batch kernel build log (all fixes, rc=0) 5.6 MB ↓ download
VERDICT.md verdict Source-confirmation verdict for DF-2037
↓ download raw

DF-2037 Verification Verdict

Severity: Medium Impact class: panic Verification method: Source-only confirmation (HW-gated, not triggerable on QEMU guest)

Verdict: REPRODUCED (source-confirmed)

The bug is confirmed in the audited source at the cited path:line. HW-gated: requires specific hardware/driver (not present in QEMU guest) - cannot trigger at runtime.

Fix: Guard target_clock==0 to prevent divide-by-zero

Fix applied and validated in batch kernel build (rc=0, -Werror).

Fix validation

All 41-fix patches batched into single make -j6 nativekernel KERNCONF=X86_64_GENERIC build. Build result: rc=0, 0 errors (full -Werror clean).

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

VALIDATED: fix.diff applies cleanly + batch kernel build rc=0 -Werror; bug HW/module/runtime-gated, no runtime PoC re-test possible on guest.

VALIDATED: fix.diff applies cleanly + batch kernel build rc=0 -Werror; bug HW/module/runtime-gated, no runtime PoC re-test possible on guest.
↓ fix.diffcombined build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

REPRODUCED (source-only): amdgpu_pll_compute performs unchecked integer division by target_clock (post_div_min=vco_min/target_clock, post_div_max=vco_max/target_clock) and by post_div; target_clock/po

Verified recommended fix

REPRODUCED (source-only): amdgpu_pll_compute performs unchecked integer division by target_clock (post_div_min=vco_min/target_clock, post_div_max=vco_max/target_clock) and by post_div; target_clock/post_div=0 -> #DE panic.

Verdict

REPRODUCED (source-only): amdgpu_pll_compute performs unchecked integer division by target_clock (post_div_min=vco_min/target_clock, post_div_max=vco_max/target_clock) and by post_div; target_clock/post_div=0 -> #DE panic.