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

port_to_transcoder[PORT_F] out-of-bounds read in intel_enable_ddi_hdmi on GEN9_BC DDI-F hardware leads to wild CHICKEN_TRANS MMIO write

Summary

Display WA #1143's port_to_transcoder[] has entries only for PORT_A..PORT_E (5 elements) but is indexed with encoder->port, which is PORT_F (5) whenever a GEN9_BC part with SFUSE_STRAP_DDIF_DETECTED and a VBT port-F child gets a DDI-F encoder. The OOB .rodata read yields a garbage transcoder that is then used to compute CHICKEN_TRANS(transcoder) for two MMIO writes at a wrong register offset during HDMI enable. Local userspace performing a modeset on DDI F of an affected SKL/KBL/CFL part: display-register corruption at an uncontrolled MMIO offset (GPU state corruption/hang). Hardware precondition (DDIF strap + VBT port F on GEN9_BC) could not be confirmed to exist in the field - hence Low/likely. Not runnable on the guest (QEMU std VGA); one-line missing-entry fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3809 Β· 5 files
FileTypeDescriptionSize
README.md β€” 1.9 KB ↓ raw
VERDICT.md β€” 2.8 KB ↓ raw
verdict.json β€” 2.0 KB view raw
manifest.json β€” 727 B view raw
env.txt β€” 730 B view raw

DF-3809 β€” port_to_transcoder[PORT_F] out-of-bounds read on GEN9_BC (SKL/KBL/CFL) DDI F

File

sys/dev/drm/i915/intel_ddi.c:3180-3187 (intel_enable_ddi_hdmi, Display WA #1143)

Build / Run / Expected

Not built, not run β€” guest has no Intel graphics (DragonFly QEMU guest: std VGA, no i915/drm0 attachment β€” see env.txt). Source-level finding.

Hypothetical trigger on affected hardware: boot a GEN9_BC part (SKL/KBL/CFL, IS_GEN9_BC() = IS_GEN9() && !IS_LP(), i915_drv.h:2562) whose SFUSE_STRAP reports SFUSE_STRAP_DDIF_DETECTED (i915_reg.h:9664) and whose VBT declares port F DP/HDMI/DVI capable, then userspace enables an HDMI mode on that port (any modeset via drm ioctls). Expected: port_to_transcoder[5] reads past the 5-element array.

Root cause

The WA #1143 lookup table covers PORT_A..PORT_E only:

static const enum transcoder port_to_transcoder[] = {
        [PORT_A] = TRANSCODER_EDP,
        [PORT_B] = TRANSCODER_A,
        [PORT_C] = TRANSCODER_B,
        [PORT_D] = TRANSCODER_C,
        [PORT_E] = TRANSCODER_A,
};
enum transcoder transcoder = port_to_transcoder[port];   /* port == PORT_F == 5 -> OOB */

intel_display.c:14340-14341 constructs PORT_F DDI encoders inside the HAS_DDI() branch (which includes all GEN9_BC parts) whenever the DDIF strap bit is set, and intel_ddi_init() completes for the port because every helper it uses (intel_port_to_power_domain, intel_ddi_max_lanes, intel_infoframe_init) handles PORT_F. Only this WA array does not. The OOB read lands in adjacent .rodata; the garbage transcoder value is then used to compute CHICKEN_TRANS(transcoder) β€” an MMIO write with an attacker-uncontrolled but out-of-range register offset (bits set then cleared).

Impact

Wrong-register MMIO writes during HDMI enable on DDI F of an affected part: display-state corruption / potential GPU hang. No proven control over the offset or data beyond two fixed bits. Severity: Low.

VERDICT.md
↓ download raw

DF-3809 β€” VERDICT

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

What was verified (source-level)

  1. The array has exactly 5 designated initializers, indices 0..4 (intel_ddi.c:3180-3186). port at the use site (intel_ddi.c:3187) is encoder->port, type enum port, values PORT_A=0 .. PORT_F=5 (checked: enum port in intel_drv.h includes PORT_F; I915_MAX_PORTS=6).
  2. The enclosing block executes for every IS_GEN9_BC(dev_priv) HDMI enable (intel_ddi.c:3173) β€” SKL, KBL, CFL per i915_drv.h:2562.
  3. PORT_F DDI encoders are created on the same platform family: intel_display.c:14317 (else if (HAS_DDI(dev_priv))) β†’ 14340-14341 (SFUSE_STRAP_DDIF_DETECTED β†’ intel_ddi_init(dev_priv, PORT_F)). intel_ddi_init itself has no port whitelist; VBT gating (ddi_port_info[PORT_F].supports_*) is the only filter (intel_ddi.c:3772-3774).
  4. No other array/index guard exists between init and the WA site.

Why not run

The DragonFly QEMU guest exposes no Intel graphics device; the i915 module never attaches (env.txt). Even on real hardware, triggering requires the CPU DDIF strap + a VBT declaring port F on a GEN9_BC part β€” a configuration we could not confirm exists in the field. The code defect (5-entry array indexed by a value that is 5 on a reachable path) is certain; the hardware precondition is the open question, hence confidence likely, severity Low.

What a maintainer should check

Whether any shipping SKL/KBL/CFL SKU sets SFUSE_STRAP_DDIF_DETECTED with a VBT port-F child device. Upstream later replaced the array with enum transcoder transcoder = (enum transcoder) port; semantics β€” aligning with that removes the OOB read.

Fix

--- a/sys/dev/drm/i915/intel_ddi.c
+++ b/sys/dev/drm/i915/intel_ddi.c
@@ -3177,7 +3177,10 @@ static void intel_enable_ddi_hdmi(struct intel_encoder *encoder,
         * the bits affect a specific DDI port rather than
         * a specific transcoder.
         */
        static const enum transcoder port_to_transcoder[] = {
            [PORT_A] = TRANSCODER_EDP,
            [PORT_B] = TRANSCODER_A,
            [PORT_C] = TRANSCODER_B,
            [PORT_D] = TRANSCODER_C,
            [PORT_E] = TRANSCODER_A,
+           [PORT_F] = TRANSCODER_A,
        };
        enum transcoder transcoder = port_to_transcoder[port];

(PORT_F has no dedicated transcoder; TRANSCODER_A mirrors the PORT_E handling. Alternatively add a WARN_ON(port >= ARRAY_SIZE(port_to_transcoder)) guard.)

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-3809

Confirmed kernel references

Detail

Evidence (decisive lines)

findings/poc/DF-3809/VERDICT.md (array size vs index proof, init-path citations), findings/poc/DF-3809/env.txt (guest lacks Intel GPU)

PoC changes

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

Verified recommended fix

Add [PORT_F] = TRANSCODER_A to port_to_transcoder[] (or guard port against ARRAY_SIZE) in intel_enable_ddi_hdmi

Verdict

intel_enable_ddi_hdmi's Display WA #1143 lookup table port_to_transcoder[] has only PORT_A..PORT_E entries but is indexed with encoder->port, which can be PORT_F (5) on GEN9_BC (SKL/KBL/CFL) parts whose SFUSE_STRAP reports DDIF and whose VBT declares the port (encoder created at intel_display.c:14340-14341). The result is a .rodata out-of-bounds read whose garbage value feeds CHICKEN_TRANS(transcoder), i.e. an MMIO write at a wrong register offset during HDMI enable. Not executed: the audit guest has no Intel GPU (no i915 attachment) and the required DDIF-strapped GEN9_BC hardware could not be confirmed to exist; the code defect itself is certain.