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

skl_calc_wrpll_link divides by p0*p1*p2*5 with no zero guard β€” QDIV_MODE=1 with QDIV_RATIO=0 readback panics the kernel (#DE)

Summary

skl_calc_wrpll_link computes p1 directly from the 8-bit DPLL_CFGCR2_QDIV_RATIO field when QDIV_MODE(1) is set; ratio==0 leaves p1==0 and the return statement divides by (p0*p1*p2*5) -> integer-divide exception. The CNL sibling guards exactly this; the HSW sibling's omission is known DF-1226; the SKL variant was missed. The driver's own programming never writes ratio 0, so triggering needs BIOS/firmware-leftover or faulted DPLL_CFGCR2 content read back during state sanitize. Local DoS (kernel #DE panic) at boot-time display state sanitize or CRTC state readback on SKL/KBL/CFL when DPLL_CFGCR2 holds the invalid QDIV combo. Mirror the CNL guard.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3810 Β· 5 files
FileTypeDescriptionSize
README.md β€” 2.1 KB ↓ raw
VERDICT.md β€” 2.5 KB ↓ raw
verdict.json β€” 1.8 KB view raw
manifest.json β€” 741 B view raw
env.txt β€” 730 B view raw

DF-3810 β€” skl_calc_wrpll_link() divides by p1 without zero guard (#DE panic)

File

sys/dev/drm/i915/intel_ddi.c:1306-1364 (skl_calc_wrpll_link)

Build / Run / Expected

Not built, not run β€” guest has no Intel graphics (see env.txt). Hypothetical trigger on SKL/KBL/CFL hardware: DPLL_CFGCR2 programmed with DPLL_CFGCR2_QDIV_MODE(1) set and QDIV_RATIO == 0 (invalid/reserved combo that the driver itself never writes β€” the state would come from BIOS/firmware leftovers read back during display hw-state sanitize, or a wedged register), then any readback path reaching skl_ddi_clock_get() β†’ skl_calc_wrpll_link() (e.g. intel_ddi_get_config at intel_ddi.c:3467 during boot-time intel_modeset_setup_hw_state or debugfs state dump). Expected: dco_freq / (p0 * p1 * p2 * 5) with p1 == 0 β†’ integer divide exception β†’ kernel panic.

Root cause

p0 = cfgcr2_val & DPLL_CFGCR2_PDIV_MASK;      /* raw field        */
p2 = cfgcr2_val & DPLL_CFGCR2_KDIV_MASK;
if (cfgcr2_val & DPLL_CFGCR2_QDIV_MODE(1))
        p1 = (cfgcr2_val & DPLL_CFGCR2_QDIV_RATIO_MASK) >> 8;   /* 8-bit field, can be 0 */
else
        p1 = 1;
switch (p0) { ... }                            /* encodings 1,2,3,7; 0 maps to PDIV_1 case */
switch (p2) { ... }                            /* all 4 encodings handled */
return dco_freq / (p0 * p1 * p2 * 5);          /* intel_ddi.c:1363 β€” no zero guard */

The CNL sibling cnl_calc_wrpll_link() has the guard:

if (WARN_ON(p0 == 0 || p1 == 0 || p2 == 0))
        return 0;                              /* intel_ddi.c:1424-1425 */

The HSW sibling missing the same class of guard was filed as DF-1226 (p*r division). The SKL variant's only zero-capable divisor operand is p1 (PDIV 0 maps to PDIV_1; all KDIV encodings map to nonzero; but QDIV_RATIO is a free 8-bit field when QDIV_MODE is set). The driver's own programming path (intel_dpll_mgr.c:1214-1215 qdiv_ratio = p1; qdiv_mode = (qdiv_ratio == 1) ? 0 : 1;) never writes ratio 0, so the trigger requires anomalous register content.

Impact

Kernel #DE panic (local DoS at boot/state-readback on affected config). Severity: Low (anomalous-HW-state dependent).

VERDICT.md
↓ download raw

DF-3810 β€” VERDICT

status: untested (poc enum) / not testable on this guest β€” no Intel GPU.

What was verified (source-level)

  1. Division at intel_ddi.c:1363 return dco_freq / (p0 * p1 * p2 * 5); with no preceding zero check in skl_calc_wrpll_link (whole function read: intel_ddi.c:1306-1364).
  2. p1 is the only operand that can be zero: QDIV_RATIO is an 8-bit field (DPLL_CFGCR2_QDIV_RATIO_MASK (0xff << 8), i915_reg.h:9319) read raw when DPLL_CFGCR2_QDIV_MODE(1) (bit 7) is set; ratio==0 leaves p1==0 and no case remaps it. p0==0 hits case DPLL_CFGCR2_PDIV_1 (encoding 0, i915_reg.h:9330) β†’ p0=1; p2's four encodings (0..3, i915_reg.h:9324-9327) all map nonzero.
  3. The CNL sibling guards exactly this (WARN_ON(p0 == 0 || p1 == 0 || p2 == 0), intel_ddi.c:1424), proving the maintainers consider the state reachable enough to guard β€” SKL was simply missed. HSW sibling = known DF-1226 (excluded from this report); this is the distinct SKL function.
  4. Reachability: skl_ddi_clock_get (intel_ddi.c:1609-1656) calls it whenever DPLL_CTRL1_HDMI_MODE(pll_id) is set during config readback (intel_ddi_clock_get ← intel_ddi_get_config ← encoder->get_config), i.e. boot-time hw-state sanitize and CRTC state reads.
  5. The driver's own DPLL programming never emits QDIV_MODE=1 with ratio 0 (intel_dpll_mgr.c:1214-1215, 2206-2207), so the divide-by-zero requires firmware/BIOS-leftover or faulted register content β€” matching the Low/"anomalous state" rating, consistent with how DF-1226 was rated.

Why not run

No Intel display hardware on the guest; a synthetic register value cannot be injected into a real DPLL_CFGCR2 readback without the hardware.

Fix

--- a/sys/dev/drm/i915/intel_ddi.c
+++ b/sys/dev/drm/i915/intel_ddi.c
@@ -1360,6 +1360,10 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
    dco_freq += (((cfgcr1_val & DPLL_CFGCR1_DCO_FRACTION_MASK) >> 9) * 24 *
        1000) / 0x8000;

+   if (WARN_ON(p0 == 0 || p1 == 0 || p2 == 0))
+       return 0;
+
    return dco_freq / (p0 * p1 * p2 * 5);
 }

(Mirrors cnl_calc_wrpll_link's guard at intel_ddi.c:1424.)

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.

(No fix.diff for this item: documented recommendation only - see Fix above.)

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

not_testable: baseline never reproduced (no hardware)

per-fix-DF-3810

Confirmed kernel references

Detail

Evidence (decisive lines)

findings/poc/DF-3810/VERDICT.md (division + guard asymmetry proof), findings/poc/DF-3810/env.txt

PoC changes

no PoC written; source-level analysis only (no trigger hardware)

Verified recommended fix

Add the cnl-style WARN_ON(p0==0||p1==0||p2==0) return-0 guard before the division in skl_calc_wrpll_link

Verdict

skl_calc_wrpll_link() (intel_ddi.c:1363) divides by p0p1p2*5 with no zero guard, unlike its CNL sibling cnl_calc_wrpll_link() which explicitly WARNs and returns 0 (intel_ddi.c:1424-1425) for the same fields. p1 can be zero: when DPLL_CFGCR2_QDIV_MODE(1) is set the 8-bit QDIV_RATIO field is used raw. The driver's own PLL programming never writes ratio 0 (intel_dpll_mgr.c:1214-1215), so triggering requires BIOS/firmware-leftover or faulted DPLL_CFGCR2 content read back during state sanitize; on such state the kernel takes an integer-divide exception and panics. Not executed: guest has no Intel GPU; the register cannot be synthesized without hardware.