u32 integer overflow in CB/DB size validation bypasses BO bounds check (cross-process GPU memory corruption)
Summary
r600_cs_track_validate_cb at r600_cs.c:430-443: tmp=nblocksy*nblocksx*blocksize*nsamples all u32. Max: 8192*8192*8*16=2^33 wraps to 0 -> check (tmp+offset)>bo_size passes for tiny BO. Same in r600_cs_track_validate_db :622 ntiles*bpe*64*nviews*nsamples. GPU writes past BO into adjacent GTT/VRAM (other process BOs). DRM_AUTH local user. Fix: compute in u64.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1340 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | git-apply-able fix; compile-validated under -Werror in the radeon module | 3.0 KB | view raw |
| VERDICT.md | verdict | full source trace + reachability analysis + compile-validation | 3.7 KB | β raw |
| README.md | readme | summary, mechanism, trigger conditions, fix | 3.4 KB | β raw |
| build.sh | build | module build that validated the fix compiles | 368 B | view raw |
| run.sh | run | guest reachability probe | 671 B | view raw |
| build_fix.log | build-log | full radeon module build output (rc=0, -Werror) | 3.6 KB | view raw |
| env.txt | environment | uname, cc, PCI/kldstat/device-node state proving no GPU/audio | 487 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-1340 β u32 integer overflow in CB/DB size validation bypasses the BO bounds check
File: sys/dev/drm/radeon/r600_cs.c:429-443 (CB) and 620-623 (DB)
Class: integer overflow -> cross-process GPU memory corruption
Status: INCONCLUSIVE at runtime β confirmed real source bug, hardware-gated on this guest
The vulnerable code path was traced line-by-line in sys/ and confirmed to be a genuine bug
(missing bounds check / integer overflow / UAF race). However it is not exercisable on the
DragonFly audit guest because the guest has neither an AMD GPU nor any audio controller:
- PCI shows only
vgapci0 class=0x030000(QEMU stdvga, chip0x11111234) β no AMD GPU. - No PCI audio device (class
0x0401/0x0403);hw.sndempty; no/dev/dsp. radeon.kois a loadable module only (NOT inX86_64_GENERIC), is not loaded, and cannot bekldload'd by an unprivileged user β and even if loaded would not attach without the hardware.
This is the valid hard-blocker case "vulnerable code path unreachable at runtime on this guest AND no harness can exercise it (device-integrated parser / ioctl / hardware-dependent race)." The bug is a real latent defect that would manifest on a system with the relevant hardware + the module loaded.
Mechanism (confirmed by source trace)
In r600_cs_track_validate_cb(), tmp is declared u32 (:353) and computed as nblocksynblocksxblocksizensamples (:430). With maximal attacker-chosen surface geometry (81928192816 = 2^33) the u32 product wraps to a tiny value, so the check (tmp + cb_color_bo_offset[i]) > radeon_bo_size(...) (:443) passes for an undersized BO; the GPU then writes colour-buffer data past the BO into adjacent GTT/VRAM (another process's BO). The tiled branch (:440) multiplies tmp by the slice count, compounding the overflow. r600_cs_track_validate_db() has the identical flaw at :622 (ntilesbpe64nviewsnsamples, also u32 via :520). Both reached from the DRM_AUTH command-submission path.
Live trigger conditions
Requires an AMD Radeon R600-family GPU with the radeon driver attached and a DRM_AUTH client issuing a crafted CS. The QEMU audit guest has only a QEMU stdvga (0x11111234) β no AMD GPU, no /dev/dri, radeon.ko not loaded β so r600_cs_track_validate_cb/db are unreachable here.
Fix
A standalone, git apply-able fix is in fix.diff. Compile-validated: applied to in-guest
/usr/src and the radeon module rebuilt under -Werror (rc=0, no warnings/errors in the
patched translation unit). See build_fix.log.
Compute the CB size in a new u64 tmp64 (cast the first operand to u64) and use tmp64 in the bounds comparison and dev_warn; split the DB tmp decl to u64 and cast the first operand. This removes the u32 overflow so the bounds check is sound. Supersedes the finding proposal (which only said 'compute in u64').
Reproduce / validate
# 1. Confirm the bug site exists (read-only source trace): grep -n ... sys/dev/drm/radeon/r600_cs.c # 2. Validate the fix compiles (on the audit guest): scp -F dfbsd-qemu/config findings/poc/DF-1340/fix.diff dfbsd:/root/fix.diff ./dfbsd-qemu/vm.sh run_root 'cd /usr/src && patch -p1 --forward < /root/fix.diff' ./dfbsd-qemu/vm.sh run_root 'cd /usr/src/sys/dev/drm/radeon && KERNCONF=X86_64_GENERIC SYSDIR=/usr/src/sys make -m /usr/src/share/mk' # 3. (requires real hardware) Exercise the bug: attach an AMD GPU / audio device and trigger.
VERDICT β DF-1340
Verdict: INCONCLUSIVE at runtime; source bug CONFIRMED; fix COMPILE-VALIDATED
Citations confirmed: sys/dev/drm/radeon/r600_cs.c:353, sys/dev/drm/radeon/r600_cs.c:430, sys/dev/drm/radeon/r600_cs.c:440, sys/dev/drm/radeon/r600_cs.c:443, sys/dev/drm/radeon/r600_cs.c:520, sys/dev/drm/radeon/r600_cs.c:622, sys/dev/drm/radeon/r600_cs.c:623
Is the bug real? β YES (source trace)
In r600_cs_track_validate_cb(), tmp is declared u32 (:353) and computed as nblocksynblocksxblocksizensamples (:430). With maximal attacker-chosen surface geometry (81928192816 = 2^33) the u32 product wraps to a tiny value, so the check (tmp + cb_color_bo_offset[i]) > radeon_bo_size(...) (:443) passes for an undersized BO; the GPU then writes colour-buffer data past the BO into adjacent GTT/VRAM (another process's BO). The tiled branch (:440) multiplies tmp by the slice count, compounding the overflow. r600_cs_track_validate_db() has the identical flaw at :622 (ntilesbpe64nviewsnsamples, also u32 via :520). Both reached from the DRM_AUTH command-submission path.
Can it be reproduced on this guest? β NO (hardware-gated)
Requires an AMD Radeon R600-family GPU with the radeon driver attached and a DRM_AUTH client issuing a crafted CS. The QEMU audit guest has only a QEMU stdvga (0x11111234) β no AMD GPU, no /dev/dri, radeon.ko not loaded β so r600_cs_track_validate_cb/db are unreachable here.
Guest evidence (env.txt): only vgapci0 class=0x030000 chip=0x11111234 (QEMU stdvga); no AMD GPU;
no PCI audio device; kldstat shows no drm/radeon/amdgpu/snd module; /dev/dri and /dev/dsp* do
not exist. The radeon module is not in X86_64_GENERIC, is not loaded, and cannot be loaded by
an unprivileged user (kldload is root-only); even loaded, it would not attach without the hardware.
Therefore the vulnerable code is unreachable at runtime here. Because the sinks are device-integrated
parsers / DRM ioctls / a hardware-dependent channel race, no userspace harness on this guest can
exercise them. This is the documented valid hard-blocker "unreachable at runtime + no feasible
harness"; the bug is a real latent defect with the live trigger conditions noted above.
No escalation chain (and why that is correct here)
There is no memory-corruption primitive to escalate on this guest: the corruption sinks live entirely
inside the not-loaded radeon driver behind hardware that is absent. The escalation work the
audit expects (slab groom -> victim -> uid0) presupposes a reachable write primitive; here there is
none on the guest. The deliverable is therefore the confirmed root-cause + a compile-validated fix.
Fix (fix.diff) β authored and COMPILE-VALIDATED
Compute the CB size in a new u64 tmp64 (cast the first operand to u64) and use tmp64 in the bounds comparison and dev_warn; split the DB tmp decl to u64 and cast the first operand. This removes the u32 overflow so the bounds check is sound. Supersedes the finding proposal (which only said 'compute in u64').
The fix was applied to in-guest /usr/src (all hunks applied cleanly) and the radeon module was
rebuilt with the kernel's -Werror flags:
cd /usr/src/sys/dev/...radeon... && KERNCONF=X86_64_GENERIC SYSDIR=/usr/src/sys make -m /usr/src/share/mk
=> rc=0, no warnings/errors in the patched translation unit (build_fix.log). The runtime
before/after of the bug cannot be tested on this guest (no hardware), so fix_status is not_testable
(diff applies + compiles; code path traced closed).
Why not not_reproduced (false-positive)?
This is NOT a false positive. The cited sys/ code is genuinely missing the guard / has the overflow
/ has the race β verified by reading the source. It is a real bug that is simply out of reach of this
particular (GPU/audio-less) QEMU guest.
Fix verification
not_testablecompile validated -Werror
module build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. r600_cs CB/DB size u32 overflow -> bounds check bypass -> cross-process GPU mem corruption. radeon not in GENERIC.
No comments yet.