# VERDICT — DF-3899

**Finding:** Off-by-one bounds guard in `intel_get_shared_dpll_id()`
(`sys/dev/drm/i915/intel_dpll_mgr.c:103-107`)

**Verdict: untested — Info-severity hardening defect, source-level certainty
(certain), no runtime reproduction attempted or possible on the audit guest.**

## What was verified, line by line

1. **The defect is real and certain.** The guard condition at
   intel_dpll_mgr.c:103-104 is
   `pll < dev_priv->shared_dplls || pll > &dev_priv->shared_dplls[dev_priv->num_shared_dpll]`.
   A pointer equal to `&shared_dplls[num_shared_dpll]` (exactly one past the
   last valid element) satisfies neither disjunct, escapes the `WARN_ON`, and
   the subtraction at :107 yields `num_shared_dpll`. On ICL,
   `num_shared_dpll == 7` (the `icl_plls[]` table at :3206-3215 has 7 entries
   + terminator; `dev_priv->shared_dplls` is declared
   `struct intel_shared_dpll shared_dplls[I915_NUM_PLLS]` with
   `I915_NUM_PLLS == 7` at i915_drv.h:1793 / intel_dpll_mgr.h:137). `id == 7`
   is out of bounds for both `dev_priv->shared_dplls[]` and
   `intel_atomic_state.shared_dpll[7]`.

2. **What the bad id would do downstream.** All three consumers use it as a
   register sub-field index / address-macro index:
   - `skl_ddi_clock_get()` intel_ddi.c:1617-1625:
     `DPLL_CTRL1_HDMI_MODE(pll_id)` / `DPLL_CTRL1_LINK_RATE_MASK(pll_id)` /
     `_SHIFT(pll_id)` — id 7 would shift/mask outside the 4×6-bit DPLL_CTRL1
     layout;
   - `icl_ddi_clock_get()` intel_ddi.c:1537-1543 →
     `icl_calc_dp_combo_pll_link()` intel_dpll_mgr.c:2555-2565:
     `ICL_DPLL_CFGCR0(7)/ICL_DPLL_CFGCR1(7)` — MMIO read at a computed offset
     outside the CFGCR block;
   - `cnl_ddi_clock_get()` intel_ddi.c:1563-1565: `CNL_DPLL_CFGCR0(7)` — same.

   Consequence class: wrong-clock readback / garbage link rate / MMIO reads at
   off-block offsets — at minimum wrong display state, at worst a
   state-machine corruption feeding later clock math. (The readback-clock math
   consumers `skl_calc_wrpll_link` / `cnl_calc_wrpll_link` divide by values
   read from those registers — the DF-3810 divide-by-zero family — so a
   mis-indexed readback plausibly feeds that family too. All speculative past
   the boundary defect itself.)

3. **Why it is unreachable today.** Exhaustive caller audit of
   `intel_get_shared_dpll_id` (rg across sys/dev/drm/i915):
   - intel_ddi.c:1537, 1563, 1617 — all pass `pipe_config->shared_dpll`.
   - `pipe_config->shared_dpll` is assigned ONLY from:
     a. `intel_get_shared_dpll()` → platform `get_dpll` hooks, every one of
        which returns `&dev_priv->shared_dplls[k]` for k < num (ibx:437/443,
        hsw:811/840, skl:1405/1409, bxt:1843, cnl:2378, icl:2922 via
        `intel_find_shared_dpll` ranges 0..num-1 or `by_id` with in-range ids);
     b. register-readback paths in intel_display.c that all `WARN_ON` range-
        check the register-derived id BEFORE `intel_get_shared_dpll_by_id`:
        :9386 (BXT `SKL_DPLL0..SKL_DPLL2`), :9407 (ICL combo `{0,1}`),
        :9411-9421 (ICL TC ports fixed MG ids 3..6), :9464 (SKL `SKL_DPLL0..3`),
        :9477-9495 (HSW switch on PORT_CLK_SEL constants),
        :9097-9103 (ILK: pipe<2 / PCH_DPLL_SEL → {0,1}).
   - NULL is caught by the `pll < shared_dplls` clause of the guard itself
     (pointer comparison; NULL < array base).
   Therefore no existing path can deliver the one-past-end pointer. The bug
   negates the guard's purpose for future callers — classic defense-in-depth
   finding.

4. **Why no guest run.** The QEMU audit guest has no Intel display hardware;
   `intel_shared_dpll_init()` never installs a `dpll_mgr`
   (intel_dpll_mgr.c:3249-3252), `intel_get_shared_dpll()` returns NULL at
   :3295, and `intel_get_shared_dpll_id()` is never invoked. Runtime
   reproduction would require an Intel i915 + display + a hypothetical buggy
   future caller. Info-tier, Phase V skipped per contract (status recorded as
   `untested` to satisfy the poc_results CHECK constraint).

## Fix

One-line, mirrors upstream's eventual index-based rewrite. See `fix.diff`.
No fix-build validation performed (nothing to observe at runtime on the
guest); `fix_status: not_testable` with this file as evidence.

## 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.
