i915_gem_fault missing offset bounds check and partial-view GMADR misaddressing allow cross-object GPU memory read/write
Summary
i915_gem_fault at i915_gem.c:2263: page_offset computed from fault offset with NO bounds check against obj->base.size. drm_gem_mmap_single passes user mmap length straight to cdev_pager_allocate so user can mmap a tiny GEM object with giant length -> faults past obj size read/write adjacent GTT slots in GMADR aperture. Additionally :2391-2392 GMADR address computed as gmadr.start+vma->node.start+offset omits subtraction of view.partial.offset for I915_GGTT_VIEW_PARTIAL VMAs, returning pages from neighboring GTT slots. Both defects unique to DragonFly port (Linux uses remap_io_mapping). vm_phys_fictitious_to_vm_page returns valid fictitious page for any address in registered GMADR segment. Attacker: any local user with /dev/dri/card0 access (video group). Impact: cross-object GPU memory disclosure and corruption, plus NULL-deref DoS via i915_gem_object_get_sg OOB sg walk. Fix: bounds-check offset against obj->base.size and subtract partial.offset from GMADR address.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1146 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | add obj-size bounds check + partial-VMA GMADR offset subtraction (git-apply-able) | 1.7 KB | view raw |
| build.sh | build-script | apply fix.diff + incremental compile of i915 i915_gem.o | 439 B | view raw |
| run.sh | run-script | documents runtime-unreachable (no Intel GPU on guest) | 551 B | view raw |
| VERDICT.md | verdict | full source-trace + mechanism + fix rationale | 4.3 KB | β raw |
| env.txt | environment | guest uname, pci, driver build status | 2.0 KB | view raw |
| build.log | build-log | fix compile-validation output (patched i915_gem.o, -Werror clean) | 1.5 KB | view raw |
| README.md | readme | human repro summary | 2.0 KB | β 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 |
DF-1146 β i915_gem_fault missing offset bounds + partial-VMA GMADR offset (i915_gem.c)
Status: REPRODUCED at code level β latent at runtime on this guest (no Intel GPU). Severity (finding): High Β· CWE-787 OOB Write + CWE-125 OOB Read
What the bug is (two DragonFly-port defects)
- Missing bounds check:
i915_gem_fault(sys/dev/drm/i915/i915_gem.c:2229) computespage_offset = offset >> PAGE_SHIFT(:2263) with no check thatoffset < obj->base.size.drm_gem_mmap_single(drm_gem.c:1099) passes the user mmap length straight tocdev_pager_allocatewithout clamping to the GEM object size, so a process can mmap a tiny object with a huge length and fault past it. Upstream Linux has the guard; the DFly port dropped it. - Partial-VMA GMADR miscompute: for an
I915_GGTT_VIEW_PARTIALVMA the GMADR address at:2391-2392(ggtt->gmadr.start + vma->node.start + offset) does not subtractvma->ggtt_view.partial.offset * PAGE_SIZE, returning pages from neighbouring GTT slots. (The correct idiom exists ati915_vma.c:905.)
Why it does not trigger here
Only QEMU std VGA (0x1234:0x1111) on the guest β not an Intel i915; i915 is
not in X86_64_GENERIC (only in LINT64 as a test config). Latent on
Intel-graphics hardware.
What was validated
- Source trace confirmed (see VERDICT.md
kernel_refs). - Baseline
i915.ko(incl.i915_gem.o) builds clean under-Werror. - Fix
fix.diffapplies (2 hunks) and patchedi915_gem.orebuilds clean under-Werror(i915_gem.o: 117984 -> 118080 bytes).
Reproduce (compile-validation only)
scp this-folder/fix.diff root@guest:/root/df1146.diff cd /usr/src && patch -p1 --forward < /root/df1146.diff cd sys/dev/drm/i915 && rm -f i915_gem.o && make i915_gem.o # -Werror clean
Fix
fix.diff adds if (offset >= obj->base.size) return VM_PAGER_ERROR; after
page_offset is computed, and subtracts partial.offset << PAGE_SHIFT from the
GMADR address for PARTIAL views.
DF-1146 β i915_gem_fault missing offset bounds + partial-VMA GMADR offset (i915_gem.c)
Verdict
REPRODUCED (code-level, latent at runtime). The DragonFly-specific port of
i915_gem_fault omits the object-size bounds check that upstream Linux
performs, and miscomputes the GMADR address for partial GGTT views. Both
confirmed by source trace. Not triggerable at runtime on this guest (no
Intel i915 GPU; i915 not in GENERIC) -> runtime not_testable. fix.diff
validated to apply + compile under -Werror.
Mechanism (trigger -> primitive -> effect)
Defect 1 β missing object-size bounds on the fault offset
i915_gem_fault(sys/dev/drm/i915/i915_gem.c:2229) computespage_offset = (unsigned long)offset >> PAGE_SHIFT;at:2263and uses it throughout with no check thatoffset < obj->base.size.- Reachability amplifier:
drm_gem_mmap_single(sys/dev/drm/drm_gem.c:1083-1109) passes the user's mmapsizestraight intocdev_pager_allocate(... size ...)(:1099-1100) without clamping togem_obj->size. So a process canmmap()a tiny GEM object with a giant length; the backingvm_objectthen covers more than the object, and faults atoffset >= obj->base.sizereachi915_gem_faultunguarded. - Upstream Linux guards this:
if (page_offset >= round_up(obj->base.size, PAGE_SIZE) / PAGE_SHIFT) return VM_FAULT_SIGBUS;in itsi915_gem_fault. The DragonFly port dropped it. - Effect: the GMADR address computed at
:2391-2392(ggtt->gmadr.start + vma->node.start + offset) goes past this object's GTT slot, returning/writing pages from neighbouring GTT slots in the GMADR aperture (read+write of unrelated GPU mappings).
Defect 2 β partial-VMA GMADR offset not subtracted
- For an
I915_GGTT_VIEW_PARTIALVMA,compute_partial_view(:2129-2149) setsview.partial.offset = rounddown(page_offset, chunk)and the VMA node maps only the chunk[partial.offset, partial.offset+size). - The GMADR computation
:2391-2392adds the object-relativeoffsetto the chunk-relativevma->node.startwithout subtractingpartial.offset * PAGE_SIZE. So a fault into a partial VMA returns the wrong page (offset bypartial.offsetpages) β i.e. pages from a neighbouring GTT slot. (Upstream usesremap_io_mappingwhich handles this; the DFly port's hand-rolledvm_phys_fictitious_to_vm_pagedoes not.) - The correct idiom already exists in the driver:
i915_vma.c:905usesvma->ggtt_view.partial.offset << PAGE_SHIFT.
Threat model / reachability
- Attacker: any unprivileged user on a machine with an Intel i915 GPU who
can open the dri render node and
mmap/I915_GEM_MMAP_GTTa GEM object with a length larger than the object, then fault past its end; or trigger the partial-VMA miscompute. Classic local privesc surface on laptops/desktops with Intel graphics. - On this guest: NOT reachable β only QEMU std VGA (
0x1234:0x1111), i915 not in GENERIC. Valid hard blocker: runtime-unreachable here, latent on Intel-i915-equipped HW.
Exploit chain
None developed β valid hard blocker (no i915 GPU on this guest to attach the
driver, so the fault path is never reached). Demonstrated work is the
source-level confirmation + compiling fix. On real i915 HW the chain would be:
open dri render node -> I915_GEM_CREATE a small object -> mmap with an
oversized length -> touch pages past obj->base.size to read/write
neighbouring GTT slots. No exploit.c (cannot run on this guest).
PoC changes
No trigger PoC seeded. This folder adds fix.diff, build.sh, run.sh,
VERDICT.md, manifest.json, env.txt, build.log, README.md.
Recommended fix
In i915_gem_fault, add if (offset >= obj->base.size) { ...; return
VM_PAGER_ERROR; } right after computing page_offset, and subtract
vma->ggtt_view.partial.offset << PAGE_SHIFT from the GMADR address when the
VMA is a PARTIAL view. Implemented in fix.diff (2 hunks). (An optional
additional defense-in-depth β clamping the mmap size in drm_gem_mmap_single
to gem_obj->size β is noted but left out of this per-finding diff because
drm_gem.c is shared by all DRM drivers and the fault-handler bounds check
alone fully closes the i915 OOB.) Supersedes a partial fix; matches
the finding's cited root cause at i915_gem.c:2263 and :2391-2392.
Fix verification
not_testablecompile validated -Werror
module build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed+compile. i915_gem_fault missing offset>=obj->base.size guard + partial VMA GMADR offset. i915 not in GENERIC.
No comments yet.