radeon_vce: OOB read of p->relocs[] and wild pointer deref via non-multiple-of-4 chunk_relocs length_dw
Summary
radeon_vce_cs_reloc at 482 validates idx >= relocs_chunk->length_dw but indexes relocs by idx/4. p->nrelocs=chunk->length_dw/4 integer division. Non-multiple-of-4 length_dw (e.g. 5): nrelocs=1, idx can be 4, passes 4>=5 false, idx/4=1 indexes past 1-element array. reloc->robj wild deref at 490. Same bug as DF-1725 radeon_cs.c.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1754 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| harness.c | trigger-source | userspace harness that reproduces the bug logic | 2.8 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 | 259 B | view raw |
| run.log | run-log | full decisive run output | 978 B | 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 | 607 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-1754 β radeon_vce.c OOB read of p->relocs[] and wild pointer deref
Verdict
REPRODUCED (logic/harness) β bug confirmed by source trace. Same
root cause as DF-1725 in radeon_cs.c. Not live-triggerable on the
default QEMU guest (no radeon GPU).
Mechanism (path:line)
sys/dev/drm/radeon/radeon_vce.c:482βif (idx >= relocs_chunk->length_dw) return -EINVAL;sys/dev/drm/radeon/radeon_vce.c:488βreloc = &p->relocs[(idx / 4)];sys/dev/drm/radeon/radeon_vce.c:489-490βstart = reloc->gpu_offset; end = start + radeon_bo_size(reloc->robj);β wild deref ofreloc->robj.
p->nrelocs = chunk->length_dw / 4 (radeon_cs.c:89, integer division).
For length_dw not a multiple of 4 (e.g. 5): nrelocs = 1, idx = 4
passes the >= 5 check (false), idx/4 = 1 indexes one past the
1-element relocs array. reloc->robj is then a wild pointer
dereferenced by radeon_bo_size.
Phase 6 escalation
Render-node reach on radeon GPU. OOB read of attacker-shaped heap
(slab grooming) yields controlled reloc->robj and reloc->gpu_offset
values. Wild pointer deref via radeon_bo_size is then a controlled
kernel-memory read. Same escalation route as DF-1725. Not developed
because the default guest has no radeon GPU.
PoC
harness.c simulates the index arithmetic for length_dw = 5:
idx = 4 passes the >= 5 check but relocs[1] is OOB. reloc->robj
is wild-derefed at radeon_bo_size.
Fix
fix.diff adds the alignment+nrelocs bound check in
radeon_vce_cs_reloc: if ((idx % 4) != 0 || idx / 4 >= p->nrelocs) return -EINVAL;.
Validated by a clean radeon.ko rebuild with the patch applied (same
module compile as DF-1725/1753/1783/1727).
Fix verification
fixedVALIDATED at module-build level: applied fix.diff to radeon_vce.c, 'make' rc=0, radeon.ko links cleanly. New DRM_ERROR string 'VCE relocs idx %d not aligned / past nrelocs %d!' present in radeon.ko (verified via strings).
baseline: harness shows idx=4 maps to relocs[1] (OOB) for length_dw=5; reloc->robj wild deref patched: radeon.ko builds clean; radeon_vce_cs_reloc now requires (idx%4)==0 && idx/4 < nrelocs, rejecting the OOB index.
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- r
- a
- d
- e
- o
- n
- /
- r
- a
- d
- e
- o
- n
- _
- v
- c
- e
- .
- c
- :
- 4
- 8
- 2
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- r
- a
- d
- e
- o
- n
- /
- r
- a
- d
- e
- o
- n
- _
- v
- c
- e
- .
- c
- :
- 4
- 8
- 8
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- r
- a
- d
- e
- o
- n
- /
- r
- a
- d
- e
- o
- n
- _
- v
- c
- e
- .
- c
- :
- 4
- 9
- 0
- s
- y
- s
- /
- d
- e
- v
- /
- d
- r
- m
- /
- r
- a
- d
- e
- o
- n
- /
- r
- a
- d
- e
- o
- n
- _
- c
- s
- .
- c
- :
- 8
- 9
Detail
Exploit chain
Render-node reach on radeon GPU. OOB read of attacker-shaped heap (slab grooming) yields controlled reloc->robj and reloc->gpu_offset. Wild deref via radeon_bo_size is a controlled kernel-memory read. Same escalation route as DF-1725. Not developed because the default guest has no radeon GPU. Harness in harness.c.
Evidence (decisive lines)
idx=4 -> relocs[1] <-- OOB reloc->robj=0x0 (wild deref at radeon_bo_size) VERDICT: BUG CONFIRMED. Same root cause as DF-1725: chunk_relocs->length_dw=5 / 4 = nrelocs=1, but the (idx >= length_dw) check admits idx=4, and relocs[1] is OOB. Wild deref of reloc->robj.
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 the alignment+nrelocs bound check in radeon_vce_cs_reloc: if ((idx % 4) != 0 || idx / 4 >= p->nrelocs) return -EINVAL. Same root cause as DF-1725.
Verdict
REPRODUCED (logic/harness). radeon_vce.c:482 validates idx >= relocs_chunk->length_dw but indexes relocs by idx/4 at line 488. p->nrelocs = chunk_relocs->length_dw/4 (radeon_cs.c:89, integer division). For length_dw not multiple of 4 (e.g. 5): nrelocs=1, idx=4 passes (4>=5 false), idx/4=1 indexes past 1-element array. reloc->robj wild deref at line 490 (radeon_bo_size). Same root cause as DF-1725.
No comments yet.