# DF-1264 — drm_dp_sideband_msg_build chunk[48] OOB write

## Verdict
**INCONCLUSIVE (hardware-gated latent bug, not triggerable on this guest).**
The OOB write is **confirmed real by source tracing**; not reachable on the
audit QEMU guest because the sink lives in the loadable `drm.ko` module and is
driven only by DisplayPort MST sideband replies from real MST hardware (absent).
fix.diff authored and **validated to apply + compile** (nativekernel `rc=0`,
`-Werror`).

## Mechanism (source trace)
`drm_dp_sideband_msg_build` (`sys/dev/drm/drm_dp_mst_topology.c:326`):
```c
struct drm_dp_sideband_msg_rx { u8 chunk[48]; u8 msg[256]; ... };   /* helper.h:215-225 */

if (hdr) {
    ...
    msg->curchunk_len = recv_hdr.msg_len;          /* 6-bit field, 0..63  (:349) */
    msg->curchunk_hdrlen = hdrlen;
    /* NO bound vs sizeof(msg->chunk)=48 */
    msg->curchunk_idx = min(msg->curchunk_len, (u8)(replybuflen - hdrlen));
    memcpy(&msg->chunk[0], replybuf + hdrlen, msg->curchunk_idx);   /* can be >48 (:365) */
} else {
    memcpy(&msg->chunk[msg->curchunk_idx], replybuf, replybuflen);  /* OOB  (:367) */
    msg->curchunk_idx += replybuflen;
}
```
- `msg->curchunk_len` comes from `recv_hdr.msg_len`, a 6-bit value (0–63) parsed
  from the sideband header, with a CRC4 the attacker controls.
- The header branch can copy up to `curchunk_len` (63) bytes into `chunk[0]`,
  already 15 bytes past `chunk[48]`.
- The non-header branch memcpy's `replybuflen` bytes at `chunk[curchunk_idx]`
  with no check that `curchunk_idx + replybuflen <= sizeof(chunk)`. Across
  chunks, `curchunk_idx` grows toward 61 and the write runs off the end of
  `chunk[48]` into `msg[256]` / the count fields / `initial_hdr` of the
  `drm_dp_sideband_msg_rx` struct (and, depending on the embedding struct,
  adjacent heap).
- Input is an attacker-controlled MST sideband message — i.e. a malicious DP MST
  branch device / dock / monitor (or a fuzz-injected AUX reply).

## Reachability on the audit guest
- `drm_dp_sideband_msg_build` is **module-only**: it is in `drm.ko`
  (`nm /boot/kernel/drm.ko` ⇒ `drm_dp_sideband_msg_build`), NOT in the base
  kernel (`nm /boot/kernel/kernel | grep drm_dp_sideband` ⇒ 0 hits). `drm.ko` is
  not loaded on the guest.
- Even loaded, it is only reached via the MST topology worker processing
  sideband replies from a DP MST branch device. The guest's only GPU is a
  virtio-class `vgapci0`; there is no DP MST topology. Not triggerable here.

## Exploit chain
None — not exercisable on this guest (module-only + no DP MST HW). The primitive
is a bounded-but-over-48 OOB write of attacker-shaped bytes (`replybuf`) into the
`drm_dp_sideband_msg_rx` struct; reachable only with a malicious/buggy MST
device on real display hardware.

## PoC changes
Authored `dp_sideband_oob.c` — a documentation stub that records the
reachability finding (sink is module-only / HW-driven; no userspace program can
reach it on this guest).

## Fix validation
- `fix.diff` applies cleanly: `git apply --check -p1` ⇒ OK (2 hunks).
- Compiles: applied to `/usr/src`, `make nativekernel` rebuilt `drm.ko` ⇒
  `NK_DONE rc=0`, `drm_dp_mst_topology.c` built with `-Werror` (`fix_build.log`).
- Functional test: **not_testable** (no DP MST HW; module not loadable into a
  path that reaches the sink).

## Recommended fix
- Reject `curchunk_len > sizeof(msg->chunk)` right after it is assigned (bound
  the header-branch copy too).
- In the non-header branch, reject `curchunk_idx + replybuflen > curchunk_len`
  before the memcpy. See `fix.diff`.
