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)
PoC verification
Evidence pack
findings/poc/DF-3809 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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.
DF-3809 β VERDICT
status: untested (poc enum) / not testable on this guest β no Intel GPU.
What was verified (source-level)
- The array has exactly 5 designated initializers, indices 0..4
(intel_ddi.c:3180-3186).
portat the use site (intel_ddi.c:3187) isencoder->port, typeenum port, values PORT_A=0 .. PORT_F=5 (checked:enum portin intel_drv.h includes PORT_F; I915_MAX_PORTS=6). - 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. - 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_inititself has no port whitelist; VBT gating (ddi_port_info[PORT_F].supports_*) is the only filter (intel_ddi.c:3772-3774). - 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_testablenot_testable: baseline never reproduced (no hardware)
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.
No comments yet.