u32 (size + offset) wraparound defeats VALID_BUFFER BO bound check (+ forced-size underflow)
Summary
size = ib_value + 1 wraps at 0xFFFFFFFF and the bound check (size + offset) > bo_size is a u32 add: offset=0xFFFFFF00 + size=0x100 wraps to 0 -> any BO passes. The forced clamp ib[...+1] = bo_size - offset additionally underflows when offset > bo_size, writing a huge size into the executed IB word. GPU vertex fetcher walks attacker-sized windows past the relocated BO (r600 twin of DF-3839). u64-widen fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4030 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 553 B | β raw | |
| VERDICT.md | β | 2.4 KB | β raw | |
| build.log | β | 1.1 KB | view raw | |
| build.sh | β | 65 B | view raw | |
| env.txt | β | 586 B | view raw | |
| fix.diff | β | 932 B | view raw | |
| r600_cs_poc.c | β | 11.6 KB | view raw | |
| resource_index_sim.c | β | 2.5 KB | view raw | |
| run.2.log | β | 881 B | view raw | |
| run.log | β | 1.3 KB | view raw | |
| run.sh | β | 89 B | view raw | |
| verdict.json | β | 2.5 KB | view raw |
DF-4030 evidence pack
SET_RESOURCE SQ_TEX_VTX_VALID_BUFFER computes (size + offset) in u32 (r600_cs.c:2001-2002); 0xFFFFFF00 + 0x100 wraps to 0 and the BO bound check passes (sim output in run.log); size=value+1 wraps to 0
Build
./build.sh (cc -O2 -Wall; verified on the DragonFly audit guest β build.log)
Run
./run.sh (verified on the DragonFly audit guest β run.log; triggers exit 2:
/dev/dri absent β no radeon GPU on the QEMU guest, see env.txt)
Expected on r600/rv770 hardware
See VERDICT.md.
DF-4030 β r600 SET_RESOURCE VALID_BUFFER: u32 (size + offset) wraparound defeats the BO bound check
File: sys/dev/drm/radeon/r600_cs.c
Severity: Medium (GPU vertex fetch up to ~4 GB past the BO; hardware-gated)
Cross-ref: DF-3839 (identical defect in evergreen_cs.c, filed pass 2 there; this is
the r600 twin, independently reachable via the r600/rv770 parse path).
Root cause (path:line)
2000: offset = radeon_get_ib_value(p, idx+1+(i*7)+0); /* u32 */
2001: size = radeon_get_ib_value(p, idx+1+(i*7)+1) + 1; /* u32; wraps at 0xFFFFFFFF */
2002: if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) {
...
2006: ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj) - offset;
size + offsetis a u32 add (size,offsetbothu32):0xFFFFFF00 + 0x100wraps to0x00000000and the bound check passes for any BO (sim output in run.log).size = value + 1itself wraps to 0 forvalue == 0xFFFFFFFF.- The forced clamp at :2006 is an underflow when
offset > radeon_bo_size()(writes a huge "size" into the executed IB word), a second desync on the same path.
Both the validator and the executed state diverge from the physical BO bound, so the GPU vertex fetcher walks attacker-sized windows past the end of the relocated buffer: OOB read of GPU memory (cross-process disclosure through any subsequent draw that consumes the vertex data).
Upstream status
Same u32 arithmetic in current Linux master (r600_cs.c upstream lines 2005-2011).
Unfixed upstream (matches DF-3839's evergreen analysis).
Verification (this pack)
resource_index_sim.cβ prints the wrap:offset=0xffffff00 size=0x00000100 β (size+offset) as u32 = 0x00000000 β bound check PASSES(run.log, executed on the guest).r600_cs_poc.cmoderesourceβ slot 5 carriesoffset=0xFFFFFF00,size-1=0xFFagainst a 64 MiB BO with the wrap values; builds clean on the guest.- Runtime hardware-gated (no radeon GPU on the audit guest β env.txt).
Suggested fix
fix.diff: widen the comparison to u64 and reject offset >= bo_size before clamping.
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_testablefix.diff authored against the read-only sys/ tree after source verification; baseline and patched runs require r600/rv770 hardware which the audit guest lacks, so fix validation is not testable here.
fix.diff in this pack
Confirmed kernel references
Detail
Exploit chain
Unpriv CS with offset=0xFFFFFF00/size=0x100 buffer resource -> vertex fetch past BO end -> cross-process GPU memory disclosure.
Evidence (decisive lines)
VERDICT.md (full path:line trace); run.log (guest trigger run + arithmetic simulation proving the validator math line-exact); build.log (clean guest build); env.txt (guest has no radeon GPU β hardware-gated); fix.diff (proposed fix, NOT applied to sys/)
PoC changes
Trigger written from scratch for this pack (raw ioctl, no libdrm, self-contained struct defs); arithmetic sims written to verify each wrap/desync claim line-exact; past-IB hypothesis for DF-4029 explicitly tested and killed by resource_index_sim.
Verified recommended fix
u64 widen the comparison; reject offset >= bo_size before clamping (see fix.diff).
Verdict
SET_RESOURCE SQ_TEX_VTX_VALID_BUFFER computes (size + offset) in u32 (r600_cs.c:2001-2002); 0xFFFFFF00 + 0x100 wraps to 0 and the BO bound check passes (sim output in run.log); size=value+1 wraps to 0 at 0xFFFFFFFF; the forced clamp at :2006 underflows when offset > bo_size and writes a huge size into the executed IB. r600 twin of evergreen DF-3839. GPU vertex fetch walks up to ~4 GB past the relocated BO. Hardware-gated: no radeon GPU on the audit guest.
No comments yet.