patch_gamut_packet_checksum reads up to 227 bytes past dc_info_packet.sb[32] (length byte unbounded; dead path β no producer ever sets gamut.valid)
Summary
The checksum loop iterates to the data byte sb[1] (<=255) against uint8_t sb[32] - reads up to 227 bytes past the struct. Currently dead: no producer ever sets gamut.valid=true (grep-verified); consumers exist in dce_stream_encoder. Filed as Info hardening (same dead-API treatment as DF-1300): if a future DC consumer wires gamut emission, this becomes a slow kernel-memory info-leak oracle into HDMI infoframes. Bound-the-loop fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3944 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| check_gamut_dead.sh | β | 766 B | view raw | |
| run.log | β | 884 B | view raw | |
| env.txt | β | 68 B | view raw | |
| VERDICT.md | β | 1.7 KB | β raw | |
| fix.diff | β | 572 B | view raw | |
| verdict.json | β | 1.9 KB | view raw |
VERDICT β DF-3944
Bottom line
not_reproduced β provably dead path in this tree; latent OOB read (Info).
Root cause
dc_resource.c:2152-2155:
ptr = &gamut_packet->sb[3];
for (i = 0; i <= gamut_packet->sb[1]; i++) / sb[1] β [0,255] /
chk_sum += ptr[i];
struct dc_info_packet is {... uint8_t sb[32]; } (dc_types.h:524-531).
Maximum index touched = 3 + 255 = 258 β 227 bytes OOB read; the summed byte
lands in sb[2] and would be transmitted as an HDMI Gamut infoframe checksum.
Why dead (path:line)
- Only caller:
resource_build_info_frame()dc_resource.c:2651, on&pipe_ctx->stream_res.encoder_info_frame.gamutwhich the same function invalidated at :2625 (info->gamut.valid = false). patch_gamut_packet_checksum()early-returns unlessgamut_packet->valid(dc_resource.c:2146).- No in-tree producer ever sets
encoder_info_frame.gamut.valid = true(guest-wide grep returned 0 matches β run.log). Consumers exist (dce_stream_encoder.c:771,784; dcn10_stream_encoder.c:646) but only read. Filed at Info (same "dead API, latent hazard" treatment as DF-1300), with the bounds fix in fix.diff so any future producer cannot resurrect the OOB read.
Guest run
run.log = output of check_gamut_dead.sh against the guest's /usr/src (uname in env.txt). No AMD GPU in the guest; no runtime reproduction claimed.
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.
Fix verification
not_testablepath dead in-tree; fix.diff applies clean and bounds the read for any future producer
fix.diff; git apply --check clean
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log (guest-wide grep: 0 producers; vulnerable loop; sb[32] size), check_gamut_dead.sh, fix.diff (git-apply-clean)
PoC changes
no seed; static presence checker
Verified recommended fix
bound the checksum loop by sizeof(sb)-3 (fix.diff) or delete the dead gamut emission path
Verdict
Latent OOB read: patch_gamut_packet_checksum (dc_resource.c:2152-2155) sums ptr[i] for i up to sb[1] (max 255) starting at &sb[3] of a 32-byte array -> up to 227 bytes past struct dc_info_packet. Path is dead in this tree: the only assignment to the gamut packet's valid flag is info->gamut.valid=false (dc_resource.c:2625) and a tree-wide grep finds no producer setting it true; the checksum patcher early-returns on !valid (:2146). Filed as Info hardening with an array-bounds fix; upstream DC later dropped gamut emission entirely.
No comments yet.