β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1753

radeon_vce: OOB read and OOB write of IB buffer in cs_parse/cs_reloc via unchecked multi-dword command fields

Summary

CS parse loop at 565 checks p->idx < length_dw but reads p->idx+1 (cmd) and up to p->idx+12 per command type. radeon_get_ib_value no bounds check. radeon_vce_cs_reloc writes p->ib.ptr[lo]/[hi] with caller-supplied unchecked indices. len validation at 569 only enforces min 8/multiple 4, NOT that idx+len/4<=length_dw. Reloc writes 8 bytes per call into next radeon_sa_bo object. Unpriv render node -> kCE with grooming or panic.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1753 Β· 10 files
FileTypeDescriptionSize
harness.c trigger-source userspace harness that reproduces the bug logic 2.9 KB view raw
build.sh build-script cc -O2 -Wall -Wextra -o harness harness.c 98 B view raw
run.sh run-script ./harness 59 B view raw
build.log build-log full build output 13 B view raw
run.log run-log full decisive run output 1.3 KB view raw
env.txt environment uname + cc version 188 B view raw
VERDICT.md verdict full narrative: mechanism, Phase 6, fix 1.7 KB ↓ raw
fix.diff suggested-fix git-apply-able one-logical-change fix 866 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
VERDICT.md verdict full narrative: mechanism, Phase 6, fix
↓ download raw

DF-1753 β€” radeon_vce.c OOB read/write of IB buffer in cs_parse/cs_reloc

Verdict

REPRODUCED (logic/harness) β€” bug confirmed by source trace. Not live-triggerable on the default QEMU guest (no radeon GPU).

Mechanism (path:line)

Phase 6 escalation

Render-node reach on radeon GPU. OOB read of IB (kernel memory info leak) + OOB write of p->ib.ptr[] into the next radeon_sa_bo object. Slab grooming of the IB-adjacent slab β†’ controlled write into a victim object β†’ RIP control β†’ uid0 on this guest. Not developed because the default guest has no radeon GPU.

PoC

harness.c shows that with length_dw = 4 and p->idx = 2, the encode case reads ib[4..13] (all past length_dw) β€” OOB.

Fix

fix.diff adds a single bound check at the top of the parse loop, before reading cmd: if (p->idx + len > p->chunk_ib->length_dw) return -EINVAL;. Validated by a clean radeon.ko rebuild with the patch applied.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

VALIDATED at module-build level: applied fix.diff to radeon_vce.c, 'make' rc=0, radeon.ko links cleanly. New DRM_ERROR string 'VCE command at %d len %d overflows IB (%d)!' present in radeon.ko (verified via strings).

baseline: harness shows ib[4..13] read as OOB for p->idx=2, length_dw=4
patched: radeon.ko builds clean; radeon_vce_cs_parse now checks (p->idx + len > chunk_ib->length_dw) before reading cmd, rejecting OOB commands.
↓ fix.diffradeon.ko module rebuild (loadable .ko) - applied fix.diff (with DF-1725/1727/1754/1783), 'make' rc=0, radeon.ko 2029704 bytes built clean

Confirmed kernel references

Detail

Exploit chain

Render-node reach on radeon GPU. OOB read of IB (kernel memory info leak) + OOB write of p->ib.ptr[] into the next radeon_sa_bo object. Slab grooming of the IB-adjacent slab -> controlled write into a victim object -> RIP control -> uid0 on this guest (no SMAP/SMEP/KASLR). Not developed because the default guest has no radeon GPU. Harness in harness.c.

Evidence (decisive lines)

p->idx=2 (within length_dw=4)
  radeon_get_ib_value(p, p->idx+2) = ib[4] = 0xdead0004   <-- OOB
  radeon_get_ib_value(p, p->idx+10) = ib[12] = 0x00000000   <-- OOB
VERDICT: BUG CONFIRMED. cs_parse reads IB dwords past chunk_ib->length_dw (no idx+len/4 <= length_dw check). Same path writes p->ib.ptr[lo]/[hi] in cs_reloc; combined, OOB read + OOB write of IB on render node.

PoC changes

Wrote harness.c, build.sh, run.sh, VERDICT.md, manifest.json, fix.diff. Original folder was empty.

Verified recommended fix

fix.diff adds a single bound check at the top of the parse loop, before reading cmd: if (p->idx + len > p->chunk_ib->length_dw) return -EINVAL. One logical change.

Verdict

REPRODUCED (logic/harness). radeon_vce.c:565 while(p->idx < chunk_ib->length_dw) reads p->idx+1 (line 567), then case encode reads p->idx+8/+9/+10/+11/+12 via radeon_vce_cs_reloc. Line 569 only checks (len<8)||(len&3), not that idx+len/4<=length_dw. radeon_get_ib_value (radeon.h:1098) does NO bounds check on idx. radeon_vce_cs_reloc also writes p->ib.ptr[lo]/[hi] (lines 493-494) with caller-supplied indices. Harness shows with length_dw=4 and p->idx=2, the encode case reads ib[4..13] all OOB.