Integer overflow in aperture bounds check in agp_generic_bind_memory
Summary
Bounds check offset+mem->am_size > AGP_GET_APERTURE(dev) at :522 can be bypassed via unsigned 64-bit integer wraparound. User-supplied pg_start shifted left 12 bits produces offset near 2^64 causing offset+size to wrap to small value that passes check. Also offset<0 is dead code (vm_offset_t unsigned). Signed left shift past sign bit UB per C11. Currently mitigated by chipset-level bind_page bounds checks in all four chipset drivers but generic code is primary defense and is broken. Same pattern replicated in intel-gtt.c:1259-1260. [VERIFIED pass2: reproduced through verbatim agp.c - pg_start 0xFFFFFFFFFFFFF wrap bind passes the offset-plus-size check via wrap to 0 and invokes chipset bind_page far outside the 64MB aperture; wrap-reject fix-validated A/B]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2398 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 879 B | β raw | |
| VERDICT.md | β | 1.4 KB | β raw | |
| env.txt | β | 145 B | view raw | |
| fix.diff | β | 1.0 KB | view raw | |
| fixed.log | β | 409 B | view raw | |
| run.log | β | 512 B | view raw | |
| run.sh | β | 121 B | view raw | |
| verdict.json | β | 1.9 KB | view raw |
DF-2398 - agp bind aperture check integer wrap
Rig (agp_shim.c: VERBATIM agp.c compiled into ACHARNESS with
device agp removed; fabricated 64MB-aperture chipset implementing the
real agp_if methods; VM page accessors interposed)
- control: agp_generic_bind_memory(dev, mem, 0x8000000) -> EINVAL, 0 calls
- wrap: agp_generic_bind_memory(dev, mem, 0xfffffffffffff000)
-> PASSES the check (offset+size wraps to 0), chipset
bind_page invoked at 0xfffffffffffff000
Baseline (run.log)
control bind offset=2x aperture -> error=22 bind_calls=0 WRAP bind offset=0xfffffffffffff000 am_size=0x1000 -> error=0 bind_calls=1 bind range=[0xfffffffffffff000..0xfffffffffffff000] aperture=0x4000000 VERDICT: BUG REPRODUCED
Fixed kernel (fix.diff: subtractive bounds form)
WRAP bind offset=0xfffffffffffff000 -> error=22 bind_calls=0
DF-2398 VERDICT
Status: reproduced (reproduced) Impact: corruption Confidence: certain Attempts: 2
agp_generic_bind_memory aperture bounds check bypassed by 64-bit wraparound through the VERBATIM production code: control bind at 2x aperture correctly rejected (EINVAL, 0 chipset calls) while the wrap bind offset=0xfffffffffffff000 am_size=0x1000 (pg_start=0xFFFFFFFFFFFFF) PASSED the offset + mem->am_size > AGP_GET_APERTURE() check (sum wraps to 0) and invoked the chipset bind_page method at offset 0xfffffffffffff000 - far outside the 64MB aperture. The dead offset < 0 test (vm_offset_t unsigned) confirmed. Fixed kernel rejects the wrap with EINVAL, 0 chipset calls.
Kernel references
Guest
DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #7: Sat Oct 24 00:08:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/ACHARNESS x86_64
Fix validation
See fix.diff and README.md for the baseline/fixed A/B outputs (run.log / fixed.log).
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_testableConfirmed kernel references
Detail
Exploit chain
AGPIOC_BIND pg_start from userspace wraps the check and reaches the chipset driver with an out-of-aperture GATT index; on the four in-tree chipsets their own bind_page checks currently stop it, but any chipset driver relying on the generic check gets out-of-bounds GATT writes
Evidence (decisive lines)
run.log (control error=22 calls=0; WRAP error=0 bind_calls=1 range [0xfffffffffffff000..0xfffffffffffff000]); fixed.log (WRAP error=22 calls=0)
PoC changes
agp_shim.c verbatim-interposition harness (real agp.c compiled in, agp_if methods + VM accessors interposed) written for this batch
Verified recommended fix
see fix.diff
Verdict
agp_generic_bind_memory aperture bounds check bypassed by 64-bit wraparound through the VERBATIM production code: control bind at 2x aperture correctly rejected (EINVAL, 0 chipset calls) while the wrap bind offset=0xfffffffffffff000 am_size=0x1000 (pg_start=0xFFFFFFFFFFFFF) PASSED the offset + mem->am_size > AGP_GET_APERTURE() check (sum wraps to 0) and invoked the chipset bind_page method at offset 0xfffffffffffff000 - far outside the 64MB aperture. The dead offset < 0 test (vm_offset_t unsigned) confirmed. Fixed kernel rejects the wrap with EINVAL, 0 chipset calls.
No comments yet.