radeon_agp.c treats ai_aperture_size (BYTES tree-wide) as MB β dead <32MB guard and 2^20x-inflated gtt_size mis-programming GPU DMA-window registers; latent only (IS_ENABLED(CONFIG_AGP)==0, code not compiled on DragonFly)
Summary
The MB-unit math inherited from old Linux against DF's byte-unit source: the min-aperture guard is dead and <<20 inflates gtt_size 2^20x (64MB->64TB), inverting AIC_HI_ADDR windows and garbaging MC_AGP_TOP across 5 asic files. EMPIRICALLY PROVEN not compiled (kconfig.h lacks CONFIG_AGP; preprocessed with the module's exact flags - agp=AGP_DISABLED with positive controls). Units-demo reproduces the arithmetic. Fix the units for the day CONFIG_AGP is added.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5084 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.2 KB | β raw | |
| VERDICT.md | β | 5.1 KB | β raw | |
| iscfg2.c | β | 1.1 KB | view raw | |
| units_demo.c | β | 1.6 KB | view raw | |
| build.sh | β | 238 B | view raw | |
| run.sh | β | 141 B | view raw | |
| run.log | β | 2.2 KB | view raw | |
| env.txt | β | 308 B | view raw | |
| fix.diff | β | 1.3 KB | view raw | |
| manifest.json | β | 1.2 KB | view raw | |
| verdict.json | β | 4.5 KB | view raw |
DF-5084 β radeon_agp.c treats ai_aperture_size (BYTES) as MB
Severity: Info (latent β code is not compiled on DragonFly today)
File: sys/dev/drm/radeon/radeon_agp.c lines 152-157, 245
Status of bug: certain (source-level, proven); not compiled into any
shipped DragonFly kernel/module build (IS_ENABLED(CONFIG_AGP) == 0).
What the bug is
sys/dev/drm/kconfig.h (the Linux kconfig shim force-included by every file
in the drm/radeon build, sys/dev/drm/radeon/Makefile:148) does not
define CONFIG_AGP. On this tree:
radeon_agp_init()compiles to#else return 0;(radeon_agp.c:256-258),radeon_agp_fini()/radeon_agp_resume()compile to empty bodies,- the quirk table is not emitted.
Inside that dead body there is a genuine porting defect: the file was
imported from an old Linux revision whose agp_info.aper_size was in MB,
but DragonFly's agp_info.ai_aperture_size is in BYTES tree-wide
(vm_size_t, sys/dev/agp/agpvar.h:50, filled from rman_get_size() of the
aperture BAR at sys/dev/agp/agp.c:904; corroborated by
sys/dev/drm/drm_agpsupport.c:500 which prints ai_aperture_size >> 20 as
"β¦M"). Consequences if the code is ever compiled:
radeon_agp.c:152ai_aperture_size < 32intends "< 32 MB" β with bytes it is a dead check (an aperture is β₯ 4 MB = 4194304).radeon_agp.c:245ai_aperture_size << 20intends MBβbytes β with bytes it inflatesmc.gtt_sizeby 2^20: a 64 MB aperture yields a 64 TB GTT (gtt_end~2^46). Downstream 32-bit register writes truncate:r100.c:662-663AIC_HI_ADDR(window inverts: hi < lo),r100.c:3864-3865,r300.c:1334-1335,r520.c:153-154MC_AGP_TOP,evergreen.c:2892-2894MC_VM_AGP_TOP/BOT,r600.c:1085-1086; and the TTM GTT heap is sized 2^20x too big (radeon_ttm.c:940-941). GATT binds beyond the real aperture are still rejected bysys/dev/agp/agp.c:520-522, so the kernel-visible impact of the wronggtt_sizeis functional corruption of the GPU DMA window programming plus failed/DoS GTT allocations β not a direct GATT OOB write.
How to reproduce the analysis (no AGP hardware needed)
On the audit DragonFly guest (or any DF box with /usr/src):
vm.sh run_root 'cc -include /usr/src/sys/dev/drm/kconfig.h \
-I/usr/src/sys/dev/drm/include -E /tmp/iscfg2.c | grep -v "^#" | grep -v "^$"'
cc -O2 -o /tmp/units_demo /tmp/units_demo.c && /tmp/units_demo
Expected (see run.log):
const char *agp = "AGP_DISABLED"; <- the buggy body is NOT compiled const char *pci = "PCI_ENABLED"; <- control const char *undef_ = "UNDEF_DISABLED"; <- control const char *cik = "CIK_ENABLED"; <- control aper= 64M base=0xd0000000 -> gtt_size=0x0000400000000000 (64 TB) ... AIC_HI_ADDR=0xcfffffff (LO=0xd0000000 β inverted)
Artifacts
iscfg2.cβ preprocessor reachability proof (radeon module's exact flags)units_demo.cβ impact arithmetic demo (gtt_size / truncated registers)build.sh,run.shβ exact commandsrun.logβ full decisive output;env.txtβ guest env + md5 match vs audit treefix.diffβ 3-line units fix (authored after verification; never applied to sys/)
Fix
Treat ai_aperture_size as bytes β see fix.diff.
DF-5084 β VERDICT
Status: not_reproduced (runtime) / bug certain (source) β LATENT, code not compiled on DragonFly. Impact on any shipped DragonFly build: none.
1. What was audited and how the bug was found
sys/dev/drm/radeon/radeon_agp.c (285 LOC), pass 2. The AGP init path was
checked acquire/release-balance, quirk-table termination, module-parameter
validation, and the aperture-size β mc.gtt_size math. All the conventional
classes came back clean (see final JSON negative_notes), but the units of
ai_aperture_size did not survive the port:
- DF tree-wide convention is BYTES:
sys/dev/agp/agpvar.h:50vm_size_t ai_aperture_size;sys/dev/agp/agp.c:904info->ai_aperture_size = rman_get_size(sc->as_aperture);(the aperture PCI BAR resource, i.e. bytes)sys/dev/drm/drm_agpsupport.c:500prints(int)(β¦ai_aperture_size >> 20)as "β¦M"radeon_agp.c:152compares it against32(intent: 32 MB, cf. the"(%juM) need at least 32M"message) β dead guard in byte units.radeon_agp.c:245β¦ai_aperture_size << 20(intent: MBβbytes, inherited from old Linuxaper_sizewhich was MB) β 2^20x inflation in byte units. Modern Linux usesaper_size(bytes) directly, with no shift.
2. Proof the buggy code is NOT compiled on DragonFly
sys/dev/drm/radeon/Makefile:148 force-includes sys/dev/drm/kconfig.h
(which does not define CONFIG_AGP) and -I sys/dev/drm/include supplies the
locally-modified IS_ENABLED() (sys/dev/drm/include/linux/kconfig.h:30-39).
On the audit guest (DragonFly 6.5-DEVELOPMENT, gcc 8.3 [DragonFly]), with the module's exact flags:
$ cc -include /usr/src/sys/dev/drm/kconfig.h -I/usr/src/sys/dev/drm/include -E /tmp/iscfg2.c const char *agp = "AGP_DISABLED"; <- #if IS_ENABLED(CONFIG_AGP) is FALSE const char *pci = "PCI_ENABLED"; <- control (kconfig.h defines it) const char *undef_ = "UNDEF_DISABLED"; <- control const char *cik = "CIK_ENABLED"; <- control
Hence radeon_agp_init == { return 0; }, radeon_agp_fini == {},
radeon_agp_resume == {} in every shipped build. Guest /usr/src
radeon_agp.c and kconfig.h are md5-identical to the audited tree
(env.txt), so this is not a guest-tree artifact.
3. What WOULD happen if CONFIG_AGP were ever defined (impact ceiling)
units_demo (userland arithmetic identical to radeon_agp.c:245-247, output
in run.log): every realistic AGP aperture yields
mc.gtt_size= 32β256 TB (e.g. 64 MB @ 0xd0000000 βgtt_end = 0x4000cfffffff),RADEON_AIC_HI_ADDR(r100.c:662-663) = low-32 ofgtt_end= 0xcfffffff <AIC_LO_ADDR0xd0000000 β inverted GPU DMA window,MC_AGP_TOP(r100.c:3864-3865,r300.c:1334-1335,r520.c:153-154) =0x2000cfff-style truncated garbage,- TTM GTT heap sized 2^20x (
radeon_ttm.c:940-941).
GATT binds past the real aperture still fail closed at
sys/dev/agp/agp.c:520-522 (offset + mem->am_size > AGP_GET_APERTURE β
EINVAL), so the kernel-side consequence is mis-programmed GPU address-window
registers + unallocatable GTT (functional DoS on AGP hardware); a
chipset-mediated DMA-window corruption is speculative.
Related shipped-code note (not a separate finding): because the stub returns
0 = "success" (radeon_agp.c:256-258), on real AGP radeon hardware the ASIC
init keeps RADEON_IS_AGP with mc.gtt_size == 0; the TT heap is then empty
(radeon_ttm.c:940-941) and the !rdev->ddev->agp guard at
radeon_ttm.c:147-160 is itself compiled out β the driver fails closed
(no GTT objects), it does not corrupt. The guest has no AGP/ATI hardware
(run.log: 7 PCI devices, QEMU std VGA only, no drm modules), so none of
this is exercisable here.
4. Why verification stops here
- Memory-corruption escalation chain: N/A β the code is not in the kernel; there is no primitive to groom.
- Runtime reproduction: impossible on this guest (no AGP bridge, no radeon ASIC β QEMU does not emulate them) and meaningless while the code is compiled out.
- Fix validation (
fix.diff):not_testableβ the patched lines are inside the same#if IS_ENABLED(CONFIG_AGP)and do not compile into any DF build today; a kernel build would demonstrate nothing observable. The fix is a 3-line units correction matching modern Linux and the DF AGP layer's byte convention.
5. Bottom line
File as Info / latent: a certain, tree-inconsistent units bug inherited
from an old Linux port, sitting behind a config gate that DragonFly never
opens. It becomes a real functional/DoS bug (and a speculative
hardware-DMA-window hazard) the moment someone adds #define CONFIG_AGP 1
to sys/dev/drm/kconfig.h and boots AGP radeon hardware. One-line fix;
apply fix.diff or leave documented as latent.
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_testablenot_testable: the patched lines live inside #if IS_ENABLED(CONFIG_AGP) which is 0 on DragonFly (proven this run), so baseline and patched builds compile to identical stubs - no observable behavior difference can be demonstrated on any DF build or on this guest (no AGP/radeon hardware). The fix is a 3-line units correction matching modern Linux (aper_size in bytes, no shift) and DF's own byte-unit AGP layer (drm_agpsupport.c:500).
fix.diff authored against read-only sys/ tree, never applied; reachability proof run.log:2 (AGP_DISABLED) explains why fix validation is not possible.
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log: 'agp = AGP_DISABLED' with controls pci/cik=ENABLED, undef=DISABLED (decisive: code not compiled); run.log units_demo table: 64MB@0xd0000000 -> gtt_size=0x400000000000 (64TB), AIC_HI_ADDR=0xcfffffff < AIC_LO=0xd0000000 (inverted DMA window); env.txt: guest md5 of radeon_agp.c/kconfig.h matches audit tree; VERDICT.md sections 2-4.
PoC changes
No seed PoC existed (finding discovered this pass). Built two artifacts: iscfg2.c (preprocessor reachability proof with positive/negative controls) and units_demo.c (exact radeon_agp.c:245-247 arithmetic + truncated 32-bit register values), both run on the QEMU guest with the radeon module's own -include/-I flags.
Verified recommended fix
Treat ai_aperture_size as bytes: compare against (32U<<20) at :152 (print >>20) and drop the <<20 at :245 - see fix.diff.
Verdict
Source-level units bug is CERTAIN (ai_aperture_size is BYTES tree-wide per agpvar.h:50 + agp.c:904 + drm_agpsupport.c:500, but radeon_agp.c:152 compares it to 32-as-MB and :245 shifts it <<20 as if MB), yet the entire buggy body is NOT COMPILED on DragonFly: proven on the guest with the radeon module's exact build flags (cc -include /usr/src/sys/dev/drm/kconfig.h -> IS_ENABLED(CONFIG_AGP)==0, controls PCI/CIK=1, UNDEF=0), guest /usr/src md5-identical to the audited tree. radeon_agp_init therefore compiles to { return 0; }. No runtime manifestation exists in any shipped build; the PoC demonstrates the latency (AGP_DISABLED) and, arithmetically, the 2^20x-inflated gtt_size + inverted AIC_HI_ADDR window that would result if CONFIG_AGP is ever defined. Kernel-visible impact ceiling if enabled: dead minimum-aperture guard, 64MB->64TB TTM GTT heap (radeon_ttm.c:940-941), truncated/inverted GPU DMA-window registers (r100.c:662-663, r100.c:3864-3865, r300.c:1334-1335, r520.c:153-154, evergreen.c:2892-2894) -> functional DoS on AGP radeon hardware; GATT OOB binds remain blocked by agp.c:520-522, so no direct kernel memory corruption. Filed as Info/latent.
No comments yet.