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)
PoC verification
Evidence pack
findings/poc/DF-3810 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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).
DF-3810 β VERDICT
status: untested (poc enum) / not testable on this guest β no Intel GPU.
What was verified (source-level)
- Division at intel_ddi.c:1363
return dco_freq / (p0 * p1 * p2 * 5);with no preceding zero check inskl_calc_wrpll_link(whole function read: intel_ddi.c:1306-1364). - 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 whenDPLL_CFGCR2_QDIV_MODE(1)(bit 7) is set; ratio==0 leaves p1==0 and no case remaps it. p0==0 hitscase 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. - 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. - Reachability:
skl_ddi_clock_get(intel_ddi.c:1609-1656) calls it wheneverDPLL_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. - 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_testablenot_testable: baseline never reproduced (no hardware)
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.
No comments yet.