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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1340 Β· 9 files
FileTypeDescriptionSize
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
README.md readme summary, mechanism, trigger conditions, fix
↓ download 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, chip 0x11111234) β€” no AMD GPU.
  • No PCI audio device (class 0x0401/0x0403); hw.snd empty; no /dev/dsp.
  • radeon.ko is a loadable module only (NOT in X86_64_GENERIC), is not loaded, and cannot be kldload'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.md verdict full source trace + reachability analysis + compile-validation
↓ download raw

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_testable

compile 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.