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

(value + 1) 32-bit wrap in r100_cs_track_check_pkt3_indx_buffer() bypasses the PACKET3_INDX_BUFFER offset check -> GPU OOB index fetch up to ~4GB past the BO

Summary

The INDX_BUFFER index-offset validation is 'if ((value + 1) > radeon_bo_size(robj))' with value a full attacker-controlled u32 read from the IB. At value=0xFFFFFFFF the addition wraps to 0, the check passes, and the GPU is directed to fetch index data at a ~4GB offset from a small BO. Local DRI user on pre-R300 asics gets GPU OOB read of adjacent GPU memory (info leak via rendering) or GPU fault/hang. The identical expression exists in upstream Linux master (checked) - carried upstream equivalent. One-line wrap-free comparison fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3766 Β· 10 files
FileTypeDescriptionSize
df3766_indx_wrap.c β€” 3.6 KB view raw
build.sh β€” 106 B view raw
run.sh β€” 119 B view raw
build.log β€” 221 B view raw
run.log β€” 266 B view raw
env.txt β€” 595 B view raw
fix.diff β€” 359 B view raw
VERDICT.md β€” 2.1 KB ↓ raw
manifest.json β€” 766 B view raw
verdict.json β€” 2.5 KB view raw
VERDICT.md
↓ download raw

DF-3766 - VERDICT

status: inconclusive (runtime) | reproduced: 0 | impact (expected): leak | confidence: certain (source)

What was verified

r100_cs_track_check_pkt3_indx_buffer() validates the PACKET3_INDX_BUFFER index-buffer offset with '(value + 1) > radeon_bo_size(robj)' where value is a full attacker-controlled u32 read from the IB (r100.c:1909-1910). At value=0xFFFFFFFF the addition wraps to 0, the check passes, and the GPU is told to fetch index data at a ~4GB offset from a small BO -> GPU OOB read of adjacent GPU memory (info leak via rendering) or GPU fault/hang. The identical expression exists in upstream Linux torvalds master (checked 2026-09-16) -> carried upstream defect (equivalent). PoC builds on the guest and exits 1 (no /dev/dri): inconclusive at runtime, certain at source level.

Kernel references

Why not reproduced on the guest

Guest = DragonFly 6.5-DEVELOPMENT x86_64 under QEMU (virtio-only): - kldstat: only kernel + ehci.ko + xhci.ko (drm.ko exists in /boot/kernel but is not loaded and there is no radeonkms.ko anywhere) - /dev/dri does not exist - pciconf shows no vendor-1002 (ATI) device => The radeon CS ioctl path cannot execute. The finding is proven by line-exact source analysis (integer identities / NULL flow), and the PoC is proven to build (build.log, cc 8.3 -Wall -O2, zero warnings).

Upstream comparison

Checked against Linux torvalds master r100.c (fetched 2026-09-16): identical '(value + 1) >' expression present upstream (equivalent).

Fix

fix.diff in this directory (not applied to the read-only sys/ tree; kernel rebuild validation not possible - no target ASIC).

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_testable
baseline no→ patch + rebuild →patched clean

fix.diff authored from line-exact source analysis; kernel-rebuild validation impossible on this guest (no target ASIC to baseline)

fix.diff in pack
↓ fix.diffper-fix-DF-3766

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (full narrative); df3766_indx_wrap.c (trigger); build.log (clean compile, cc 8.3 -Wall -O2); run.log (device absent); env.txt (guest has no radeon hw/module); fix.diff

PoC changes

Re-seeded PoC from scratch: DF-style _IOWR('d', nr, type) ioctl encoding (uapi drm.h:800), self-contained uapi structs, packet builders verified against r100d.h/radeon_reg.h constants, register reachability verified against r100_reg_safe.h bitmap (102 entries).

Verified recommended fix

Use wrap-free comparison: value >= radeon_bo_size(robj) instead of (value+1) > size

Verdict

r100_cs_track_check_pkt3_indx_buffer() validates the PACKET3_INDX_BUFFER index-buffer offset with '(value + 1) > radeon_bo_size(robj)' where value is a full attacker-controlled u32 read from the IB (r100.c:1909-1910). At value=0xFFFFFFFF the addition wraps to 0, the check passes, and the GPU is told to fetch index data at a ~4GB offset from a small BO -> GPU OOB read of adjacent GPU memory (info leak via rendering) or GPU fault/hang. The identical expression exists in upstream Linux torvalds master (checked 2026-09-16) -> carried upstream defect (equivalent). PoC builds on the guest and exits 1 (no /dev/dri): inconclusive at runtime, certain at source level.