drm_dp_sideband_msg_build OOB write past chunk[48] via unchecked msg_len from malicious MST hub
Summary
drm_dp_sideband_msg_build at drm_dp_mst_topology.c:349: msg->curchunk_len=recv_hdr.msg_len (6-bit 0-63 from attacker-controlled sideband header, CRC4 computed by attacker). chunk[48] (drm_dp_mst_helper.h:216). Non-hdr branch :367-368: memcpy(&chunk[curchunk_idx],replybuf,replybuflen) with NO bounds check on curchunk_idx+replybuflen vs sizeof(chunk). msg_len=63 -> curchunk_idx grows to 61 -> writes past chunk into msg[]. Multi-chunk: curlen += curchunk_len-1 (62), after 5 chunks curlen wraps msg[256] -> overwrites curchunk_len/curchunk_idx/initial_hdr. UNAUTHENTICATED: malicious MST hub/dock/monitor (HPD IRQ -> drm_dp_mst_hpd_irq). Fix: check curchunk_len<=sizeof(chunk), check curchunk_idx+replybuflen, check curlen+curchunk_len-1.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1264 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| dp_sideband_oob.c | trigger-source | trigger / documentation PoC | 2.1 KB | view raw |
| fix.diff | suggested-fix | git-apply-able patch closing the cited path | 919 B | view raw |
| VERDICT.md | verdict | full source trace + reachability + fix analysis | 3.5 KB | β raw |
| README.md | readme | build/run/expected | 1.4 KB | β raw |
| build.sh | build-script | cc -O2 -Wall -o dp_sideband_oob dp_sideband_oob.c | 117 B | view raw |
| run.sh | run-script | ./dp_sideband_oob | 49 B | view raw |
| run.log | run-log | decisive run, full output | 350 B | view raw |
| fix_build.log | build-log | nativekernel compile-validation excerpt, rc=0 | 32.5 KB | view raw |
| env.txt | environment | uname, cc version, device/module state | 583 B | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1264 PoC β drm_dp_sideband_msg_build chunk[48] OOB write
Status
INCONCLUSIVE on the audit guest: bug confirmed real by source trace at
sys/dev/drm/drm_dp_mst_topology.c:326, but hardware-gated and not triggerable here. fix.diff authored and
validated to apply + compile (nativekernel rc=0, -Werror). See
VERDICT.md for the full trace and fix.diff for the patch.
Build
./build.sh
(equivalent: cc -O2 -Wall -o dp_sideband_oob dp_sideband_oob.c)
Run (as unprivileged user)
./run.sh
Expected on the audit guest
The PoC runs and reports that the kernel trigger surface is absent on this
QEMU/KVM guest (no LSI MegaRAID controller / no AMD Tonga GPU / no DP MST
hardware; mfi is in-kernel but /dev/mfi0 is never created; drm/amdgpu are
loadable modules that are not loaded and would not attach). It exits 0 without
exercising the sink. The bug is therefore a latent, hardware-dependent
defect, not a false positive.
Files
dp_sideband_oob.cβ trigger / documentation PoCfix.diffβ standalonegit apply -p1patch closing the cited pathVERDICT.mdβ full source-level mechanism + reachability + fix analysisbuild.log/run.logβ captured build/run outputfix_build.logβ nativekernel compile-validation excerpt (rc=0)env.txtβ guest environmentmanifest.jsonβ machine-readable artifact catalog
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):
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_lencomes fromrecv_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 intochunk[0], already 15 bytes pastchunk[48]. - The non-header branch memcpy's
replybuflenbytes atchunk[curchunk_idx]with no check thatcurchunk_idx + replybuflen <= sizeof(chunk). Across chunks,curchunk_idxgrows toward 61 and the write runs off the end ofchunk[48]intomsg[256]/ the count fields /initial_hdrof thedrm_dp_sideband_msg_rxstruct (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_buildis module-only: it is indrm.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.kois 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.diffapplies cleanly:git apply --check -p1β OK (2 hunks).- Compiles: applied to
/usr/src,make nativekernelrebuiltdrm.koβNK_DONE rc=0,drm_dp_mst_topology.cbuilt 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_lenbefore the memcpy. Seefix.diff.
Fix verification
not_testablecompile validated -Werror
module/kernel build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. drm_dp_sideband_msg_build curchunk_len 6-bit no bounds vs chunk[48] -> OOB write. drm module only, no DP MST HW.
No comments yet.