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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1754 Β· 10 files
FileTypeDescriptionSize
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
VERDICT.md verdict full narrative: mechanism, Phase 6, fix
↓ download 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)

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

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 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.
↓ fix.diffradeon.ko module rebuild (loadable .ko) - applied fix.diff (with DF-1725/1727/1753/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 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.