# DF-1781 — drm_crtc.c uninitialized heap read in drm_mode_setcrtc cleanup

## Verdict
**REPRODUCED (logic/harness)** — bug confirmed by source trace. Reach
requires a DRM master (logind / consolekit grant or `DRM_IOCTL_SET_MASTER`).
The default guest has no DRM device, so no live trigger.

## Mechanism (path:line)
* `sys/dev/drm/drm_crtc.c:713-715` — `connector_set = kmalloc_array(crtc_req->count_connectors, sizeof(struct drm_connector *), GFP_KERNEL);`
  — `kmalloc_array` in the linuxkpi slab shim (`sys/dev/drm/include/linux/slab.h`)
  does **not** pass `M_ZERO`, unlike Linux's `kcalloc`.
* `sys/dev/drm/drm_crtc.c:721-741` — populate loop sets
  `connector_set[i] = NULL;` only at the start of iteration `i`. If an
  iteration fails (`get_user` EFAULT at 724 or unknown connector at 730),
  control jumps to `out:`, leaving slots `[k+1..count_connectors-1]` as
  heap residue.
* `sys/dev/drm/drm_crtc.c:761-766` — cleanup loop iterates **all**
  `count_connectors` slots: `if (connector_set[i]) drm_connector_put(connector_set[i]);`
  — reads uninit slots; non-NULL garbage calls `drm_connector_put(garbage)`
  → `drm_mode_object_put(&garbage->base)` → `kref_put` on a wild
  refcount pointer.

## Phase 6 escalation
DRM-master reach. Panic-DoS is the immediate effect (wild deref); with
slab grooming the wild pointer can be a UAF re-claim into a
victim object → uid0. Not developed because the default guest has no
DRM device.

## PoC
`harness.c` simulates the populate loop failing at iteration 1 of a
4-slot `connector_set`. With `memset(cs, 0xAA, ...)` to mimic heap
residue, slots `[2..3]` are non-NULL and the cleanup loop dereferences
them as wild pointers.

## Fix
`fix.diff` switches `kmalloc_array` to `kcalloc` (`sys/dev/drm/include/linux/slab.h:44` defines `kcalloc` as `kzalloc(n*size, flags)` which zeroes). One-line change at `drm_crtc.c:713`. Validated by a clean `drm.ko` rebuild with the patch applied.
