Intel graphics stolen-memory reservation is compiled out; drm/i915 trusts the unreserved firmware values and its only conflict guard is a no-op rman stub
Summary
intel_graphics_stolen computes the stolen base/size at init386 but the RESERVATION call is commented out and phys_avail_reserve does not exist anywhere in the tree (live-proven grep) - while i915_module.c still publishes the range and i915_gem_stolen adopts it as GPU-exclusive; the only overlap check (devm_request_mem_region) is a DFly self-scoped no-op rman stub that always succeeds. On buggy-BIOS Intel platforms (~200 gen3+ device IDs) the kernel page allocator and the GPU own the SAME DRAM pages: GPU DMA silently corrupts live kernel memory - exactly the misbehavior the file's own comment says it exists to prevent, shipped disabled. QEMU hard blocker documented (no Intel VGA device model - Bochs 1234:1111 fails the vendor gate), not_reproduced with code-certain root cause. Zero-size-the-resource fix (activates i915's own safe fallback) git-applies cleanly; complete follow-up is implementing the reservation KPI.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5581 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.8 KB | β raw | |
| VERDICT.md | β | 7.1 KB | β raw | |
| probe.sh | β | 1.2 KB | view raw | |
| run.log | β | 353 B | view raw | |
| fix.diff | β | 1.6 KB | view raw | |
| manifest.json | β | 1.4 KB | view raw | |
| verdict.json | β | 4.6 KB | view raw |
DF-5581 β Intel graphics stolen-memory reservation is compiled out; drm/i915 trusts unreserved firmware values
What to run
dfbsd-qemu/vm.sh status # must be 'up' (vm.sh up otherwise)
sh probe.sh # on the host: the equivalent commands are
# vm.sh run_user / vm.sh run_root sequences
The decisive run captured in run.log:
dfbsd-qemu/vm.sh run_user 'id; sysctl hw.intel_graphics_stolen_base hw.intel_graphics_stolen_size'
dfbsd-qemu/vm.sh run_root 'pciconf -l | grep pci0:0:2:0; \
grep -rn phys_avail_reserve /usr/src/sys/ --include=*.c --include=*.h; \
kldstat | grep i915'
Expected output (on the QEMU rig)
hw.intel_graphics_stolen_base: 0/hw.intel_graphics_stolen_size: 0, readable byuid=1001β the sysctl surface is world-readable; the quirk is inert here because the VGA at 0:2:0 is Bochs/QEMU (chip=0x11111234, vendor 0x1234), which the vendor gate atpci_early_quirks.c:288rejects.- The full-tree grep returns exactly ONE hit: the commented-out call at
pci_early_quirks.c:309β no reservation mechanism exists anywhere insys/. i915: not loaded(no Intel GPU).
Why this is the finding, not a negative
The finding is a code-proven defect, not a guest-runtime one:
pci_early_quirks()(called frominit386(),machdep.c:2760, beforecninit()) computes the Intel stolen-memory base/size from firmware-programmed config registers β the stated purpose is to reserve that range (pci_early_quirks.c:264-271).- The reservation is commented out (
:308-310) andphys_avail_reservedoes not exist anywhere in the tree (live-proven on the guest's full/usr/src; include also commented at:35-36). i915_module.c:18-30copies the values intointel_graphics_stolen_res;i915_gem_stolen.c:414-417adopts them as the GPU-exclusivedsmrange and allocates GPU objects from it.- The only overlap guard,
devm_request_mem_region, is a DragonFly stub (i915_gem_stolen.c:85-102) that manages a static rman containing only the requested region itself β it cannot detect any conflict and always succeeds. The Linux conflict semantics are gone.
Net effect: on the exact buggy-BIOS platforms the quirk exists for (firmware did not hide stolen memory from the OS memory map β or BSM/GMS disagree with the memory map), the kernel page allocator and the i915 stolen allocator own the same physical pages. GPU writes to stolen objects silently corrupt live kernel memory.
The QEMU rig cannot manifest this: QEMU has no Intel VGA device model, so
0:2:0 can never read 8086:<table id> without patching QEMU itself β a
documented hard blocker (see VERDICT.md). Code-reading is decisive here.
DF-5581 VERDICT β not_reproduced on rig (hardware absent); root cause code-certain
Status: not_reproduced on the available QEMU rig β the triggering
hardware (Intel gen3+ integrated GPU at PCI 0:2:0) does not exist in QEMU and
cannot be emulated without patching QEMU itself. The root cause is proven
with line-accurate code reading plus live guest probes of the observable
surface.
The finding (code-certain)
intel_graphics_stolen() runs at init386() time
(sys/platform/pc64/x86_64/machdep.c:2760, before cninit()), reads the
firmware-programmed BSM (0x5c / gen11 0xc0/0xc4) and GMCH (0x50/0x52)
registers of the Intel iGPU at 0:2:0, and stores base/size into
intel_graphics_stolen_base/size (pci_early_quirks.c:303-304).
The function's own comment (:264-271) states its purpose: buggy BIOSes do
not reserve the GPU's stolen memory, so the OS can claim it before the GPU
driver loads; the function is supposed to reserve it. It does not:
- The only reservation call is commented out (
pci_early_quirks.c:308-310). phys_avail_reservedoes not exist anywhere in the tree β live-proven on the guest over the full/usr/src: exactly one hit, the comment itself (run.log). Thex86/physmem.hinclude is commented out too (:35-36).
The consumer side (why "inert globals" are not the end of the story)
sys/dev/drm/i915/i915_module.c:18-30(i915_init, SI_SUB_DRIVERS):intel_graphics_stolen_res = DEFINE_RES_MEM(intel_graphics_stolen_base, intel_graphics_stolen_size)and prints both values.sys/dev/drm/i915/i915_gem_stolen.c:414-417(i915_gem_init_stolen): non-zero size βdev_priv->dsm = intel_graphics_stolen_resβ the driver adopts the range as GPU-exclusive and allocates GPU objects (ringbuffers, contexts, framebuffersβ¦) from it viadrm_mm.- The only overlap check on the whole path is
devm_request_mem_region()ati915_gem_stolen.c:177-189β whose DragonFly implementation (i915_gem_stolen.c:85-102) builds a static rman scoped to exactly[start, start+n)(the region being requested),rman_manage_regions that same range, and returns success. It cannot see any other resource; the "conflict detected" branch is unreachable in practice. Upstream Linux semantics (fail if any kernel/driver resource occupies the range) are not present.
Impact chain (conditional, stated exactly)
Preconditions: Intel gen3+ iGPU at 0:2:0 (the table
pci_early_quirks.c:227-262 covers ~200 Intel device IDs), i915 drm module
in use, AND firmware that fails to hide the stolen range from the OS memory
map (the exact bug class this quirk exists for β real-world occurrences are
documented in the Linux early-quirks history this code was ported from), or
BSM/GMS register values inconsistent with the memory map.
Consequence: the kernel physical page allocator and the i915 stolen allocator own the same DRAM pages. The GPU then DMAs over live kernel data structures β silent kernel memory corruption (integrity/confidentiality of kernel memory from the GPU's perspective, availability certain). No unprivileged-local software trigger exists: the inputs are firmware-programmed config registers; local unprivileged users cannot reach them (config access requires root via /dev/pci, which is FWRITE-gated).
Severity: Medium (kernel memory corruption consequence, but requires the specific hardware + misbehaving firmware precondition; not attacker-actioned from an unprivileged shell). Confidence: certain for the code gap; the population of affected machines is the uncertainty.
What was run on the guest (run.log)
sysctl hw.intel_graphics_stolen_base hw.intel_graphics_stolen_sizeasuid=1001β both readable (world-readable sysctl surface), value0.pciconf -lβvgapci0@pci0:0:2:0: class=0x030000 chip=0x11111234β passes the class gate (pci_early_quirks.c:291-292), fails the vendor gate (:287-289, vendor 0x1234 β 0x8086) β quirk correctly inert on this rig; i915 not loaded.- Full
/usr/srcgrep forphys_avail_reserveβ only the comment atpci_early_quirks.c:309.
Attempts: 3 distinct guest probes (sysctl / pciconf / tree grep), all consistent with the code analysis.
Why no escalation chain was pursued
The corruption primitive is GPU-DMA-based and requires an Intel iGPU device
model at 0:2:0. QEMU ships none (VGA = 1234:1111, vmware-svga = 15ad:0405,
virtio-gpu = 1af4:1050); making 0:2:0 read 8086:<id> requires patching
QEMU device models (out of scope for this rig). There is no
unprivileged-local software path into the inputs. "No gadget / hardening
blocks me" does NOT apply here β the blocker is hardware availability, and
it is total on this rig.
Fix
fix.diff: stop advertising the unreserved range to drm/i915 (zero-size the
resource in i915_init), which activates the driver's own documented safe
fallback (i915_gem_stolen.c:414-415: zero size β stolen memory disabled β
the same fallback Linux uses under DMAR/vGPU). Kernel-side diagnostic sysctls
keep the raw firmware values. The complete fix (implement the
phys_avail_reserve KPI at init386 and re-enable advertising) is the
follow-up maintainer work; the diff removes the unsafe trust now.
Fix validation: fix_status=not_testable β the baseline harmful behavior
cannot be reproduced on this rig (no Intel GPU), so a baselineβpatched
comparison is impossible here. The patched consumer path was verified by
code: DEFINE_RES_MEM(0,0) β end=-1 β resource_size()==0
(sys/dev/drm/include/linux/pci.h:621-637) β early return 0.
Negative sweep (classes considered and killed)
- Table matching (
:299-306): bounded bynitems(), all entries fully initialized byINTEL_VGA_DEVICE(vendor 0x8086, device, ops); per-entry.vendoris ignored but pre-validated once at:288β equivalent, safe. - Early cfgreg access: every read uses fixed (bus,slot,func) β {(0,2,0),
(0,0,0)} and reg β {0x00,0x02,0x0a,0x50,0x52,0x5c,0xc0,0xc4} with bytes
β {2,4} aligned β all pass
pci_cfgenablebounds (pci_cfgreg.c:181-196); the ECAM width/alignment asymmetry is DF-5570 (sibling file), not reachable from this file's call sites. - Integer overflow: sizes are
vm_paddr_t(64-bit) Γ max 0xEFΒ·32MiB β 7.5GiB β no overflow;MiB()shifts inunsigned long. - Uninitialized reads / type confusion:
opsonly dereferenced after table match; table fully const-initialized; no writes to config space anywhere in this file. - Races: single-threaded BSP boot before SMP start; globals written once, consumed at SI_SUB_DRIVERS β no race window.
- Info leak:
hw.intel_graphics_stolen_base/_sizeare world-readable sysctls exposing a firmware-programmed physical address β noted as an Info-grade hardening nit (not filed; value is not a kernel pointer, no demonstrated impact; also inert at 0 on rigs without Intel GPU).
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_testableBaseline harmful behavior cannot be reproduced on this rig (no Intel iGPU), so a baseline-vs-patched comparison is impossible here. fix.diff is a minimal consumer gate whose semantics were verified by code: DEFINE_RES_MEM(0,0) gives end=-1 hence resource_size()==0 (sys/dev/drm/include/linux/pci.h:621-637), and i915_gem_init_stolen returns early (stolen disabled) on zero size (i915_gem_stolen.c:414-415) - the same fallback Linux uses under DMAR/vGPU. diff git-applies cleanly from repo root; sys/ untouched.
findings/poc/DF-5581/fix.diff (git apply --check OK from repo root); sys/dev/drm/include/linux/pci.h:626-637 (DEFINE_RES_MEM/resource_size); sys/dev/drm/i915/i915_gem_stolen.c:414-415 (zero-size fallback)
Confirmed kernel references
Detail
Evidence (decisive lines)
findings/poc/DF-5581/run.log (unpriv sysctl read of both globals as uid=1001; pciconf showing 0:2:0 = class 0x0300 chip 0x11111234 so the vendor gate rejects it on this rig; full-tree grep: phys_avail_reserve appears ONLY as the comment at pci_early_quirks.c:309; i915 not loaded) + VERDICT.md chain with the no-op devm_request_mem_region stub at i915_gem_stolen.c:85-102 and the trust sink at i915_gem_stolen.c:414-417
PoC changes
no seeded PoC existed; authored probe.sh (guest verification probes) from scratch - the finding's trigger class is firmware/hardware, so evidence = boot-rig probes + line-accurate code reading
Verified recommended fix
Implement the phys_avail reservation KPI at init386 and reserve the stolen range; until then stop advertising the unreserved range to drm/i915 (fix.diff: zero-size intel_graphics_stolen_res, activating i915_gem_init_stolen's zero-size fallback)
Verdict
Root cause is code-certain: intel_graphics_stolen() runs at init386 (machdep.c:2760) and computes the Intel stolen range from firmware-programmed config registers, but its stated purpose - reserving that range - is compiled out (pci_early_quirks.c:308-310; phys_avail_reserve exists nowhere in the tree, live-proven by full-/usr/src grep on the guest). drm/i915 then blindly adopts the values as a GPU-exclusive range (i915_module.c:18-30, i915_gem_stolen.c:414-417) and its only overlap guard, devm_request_mem_region, is a DragonFly stub that manages a rman scoped to the requested region itself and can never detect a conflict (i915_gem_stolen.c:85-102). On buggy-BIOS Intel platforms (firmware failed to hide stolen memory from the OS map) the kernel page allocator and the GPU stolen allocator own the same physical pages, so GPU objects silently corrupt live kernel memory. Not reproduced on the QEMU rig because QEMU has no Intel iGPU device model: 0:2:0 is Bochs VGA 1234:1111, fails the vendor gate at pci_early_quirks.c:288, sysctls stay 0, i915 not loaded. No unprivileged-local software trigger exists (inputs are firmware-owned config registers).
No comments yet.