# DF-3901 — Uninitialized stack consumed as DRAM channel info when one MAD_DIMM channel is blank (SKL/KBL)

**File:** `sys/dev/drm/i915/i915_drv.c`
**Class:** uninitialized stack read (CWE-457) consumed into watermark config
**Severity:** Low (hardware-config-gated; no memory corruption, no info leak to userspace)

## What

`skl_dram_get_channels_info()` (i915_drv.c:1216) declares channel structs
uninitialized:

```c
struct dram_channel_info ch0, ch1;          /* :1219 — NO initializer */
...
val_ch0 = I915_READ(SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN);
ret = skl_dram_get_channel_info(&ch0, val_ch0);   /* fills ch0 only on success */
...
val_ch1 = I915_READ(SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN);
ret = skl_dram_get_channel_info(&ch1, val_ch1);   /* fills ch1 only on success */
if (dram_info->num_channels == 0) return -EINVAL; /* both blank -> early out */
```

`skl_dram_get_channel_info()` (:1154) returns `-EINVAL` **before assigning
anything** when `val == 0` or when both size fields are 0 (i.e. the DIMM slot
is empty — the MAD_DIMM register reads 0). If exactly one channel is
populated (single-channel memory, common budget SKL/KBL configs), the failed
channel's struct is left entirely uninitialized, yet the caller consumes it:

```c
if (ch0.rank == I915_DRAM_RANK_SINGLE ||       /* :1243 — uninit if ch0 failed */
    ch1.rank == I915_DRAM_RANK_SINGLE)         /* :1244 — uninit if ch1 failed */
	dram_info->rank = I915_DRAM_RANK_SINGLE;
else
	dram_info->rank = max(ch0.rank, ch1.rank);  /* :1247 — uninit max() */

dram_info->is_16gb_dimm = ch0.is_16gb_dimm || ch1.is_16gb_dimm;  /* :1254 */

dev_priv->dram_info.symmetric_memory =                          /* :1256 */
	intel_is_dram_symmetric(val_ch0, val_ch1, &ch0);            /* reads ch0->s_info.* */
```

Stale stack bytes then steer `dram_info->rank` / `is_16gb_dimm` /
`symmetric_memory`, which feed `intel_get_dram_info()` (:1379) → SKL
watermark latency selection (skl_wm_*) — the wrong "16Gb DIMM" assumption
directly changes the level-0 watermark latency workaround decisions.

Upstream fixed exactly this by zero-initializing the channel structs
(`struct dram_channel_info ch0 = {}, ch1 = {};` in later
drivers/gpu/drm/i915/display/intel_dram.c) plus reworking the rank logic.

## Impact

Attacker-influence: essentially none (value comes from MMIO/stack garbage, not
user input). Effect: wrong watermark programming → display FIFO underruns,
flicker, blank screens on single-channel SKL/KBL machines; latent KMSAN-grade
uninitialized-memory defect. DoS at worst, hardware-config-gated.

## Reproduce

`skl_dram_probe.c` would issue I915_GETPARAM pre/post on such hardware;
the uninit consumption itself needs KMSAN-style instrumentation or a
single-channel SKL. Not runnable on this guest (no Intel GPU). Status:
`inconclusive`, code path certain.

## Fix

Zero-initialize `ch0`/`ch1` (and mirror upstream's early bail when a channel
read fails), see fix.diff.
