DF-4444 / verdict.json
{ "finding_id": "DF-4444", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Static proof is certain: the DragonFly-only drm_vma_node_unmap() (sys/dev/drm/i915/i915_vma.c:857-890) cannot revoke a single user mapping \u2014 OBJT_MGTDEVICE aperture pages are entered directly into the pmap and never inserted into the device vm_object (i915_gem.c:57 #undef USE_INSERT, i915_gem.c:2405-2425 disabled, vm_fault.c:2027-2033/2170-2174), so both vm_object_page_remove() and the vm_page_lookup_busy_wait() loop operate on an empty object and the only remaining statement drops the lookup reference. It is the sole revocation hook in the whole DF drm tree (rg pmap_remove|pmap_qremove|pmap_page_protect over sys/dev/drm returns nothing), yet the caller clears the USERFAULT bookkeeping as if mappings were revoked (i915_vma.c:915-917). Consequence on real Intel-GPU hardware: user CPU PTEs into the physical GGTT aperture survive VMA unbind/evict (i915_vma.c:1146), fence steal (i915_gem_fence_reg.c:248), GPU reset (i915_gem_fence_reg.c:459) and object free (twin no-op at i915_gem.c:2149-2165), and read/write whichever objects pages later occupy the reused aperture range \u2014 unprivileged cross-object/cross-user GPU memory disclosure+corruption (High). Runtime verification impossible on the audit guest: only QEMU virtio-gpu 0x1234:1111 is present, i915.ko can never attach; the self-contained trigger compiles cleanly on the guest (build.log) and runs to exactly that hardware gate (run.log: no DRI device, exit=2, env.txt). fix.diff implements the pmap-level zap (fictitious-page + pmap_page_protect over the VMAs mappable aperture window); fix validation is not_testable for the same hardware reason.", "exploit_chain": "render-node open -> GEM_CREATE(A) -> I915_MMAP_GTT(A) + touch (PTEs->aperture, USERFAULT set) -> GGTT pressure via ~384 GTT-mapped 1MiB objects -> MM evicts inactive A -> i915_vma_unbind -> revoke_mmap no-op (stale PTEs stay valid) -> victim V (other process, e.g. root framebuffer) rebinds into As freed drm_mm range -> read/write As stale mapping == read/write Vs memory; no fault occurs so no revalidation", "evidence": "VERDICT.md (line-cited proof + attack chain); run.log (trigger runs to the hardware gate on the guest); build.log (compiles clean); env.txt (no /dev/dri, virtio-gpu only); fix.diff (pmap-level revocation)", "kernel_refs": [ "sys/dev/drm/i915/i915_vma.c:857-890", "sys/dev/drm/i915/i915_vma.c:892-918", "sys/dev/drm/i915/i915_vma.c:1130-1150", "sys/dev/drm/i915/i915_gem.c:57", "sys/dev/drm/i915/i915_gem.c:2193-2229", "sys/dev/drm/i915/i915_gem.c:2405-2428", "sys/dev/drm/i915/i915_gem.c:2440", "sys/dev/drm/i915/i915_gem.c:2149-2165", "sys/dev/drm/i915/i915_gem_fence_reg.c:248", "sys/dev/drm/i915/i915_gem_fence_reg.c:459", "sys/dev/drm/drm_gem.c:1099", "sys/vm/device_pager.c:97-107", "sys/vm/device_pager.c:184-194", "sys/vm/vm_pager.c:359-374", "sys/vm/vm_fault.c:2027-2033", "sys/vm/vm_fault.c:2162-2174" ], "poc_changes": "self-contained trigger written from scratch (inline DRM/i915 uapi structs and ioctl numbers \u2014 no libdrm on the guest); builds clean on DF cc", "attempts": 1, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 42, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o /tmp/df4444 /tmp/df4444_trigger.c", "run_cmd": "/tmp/df4444 (on-guest; on Intel-GPU hardware expect exit 0 + VULNERABLE markers)", "code_hash": "cf68ffe2c7db09ed408ab7afad5021bda06a426c1b65373aa0d8d6784a7799b6", "notes": "status=inconclusive because the audit guest has no Intel GPU (virtio-gpu only) \u2014 the allowed enum has no hardware-absent value; static certainty is high and every cited line was re-verified in-tree. Same-family second site: __i915_gem_object_release_mmap at i915_gem.c:2149-2165 needs the analogous per-GGTT-VMA zap (walk obj->vma_list ggtt vmas with still-allocated nodes at release time). Fixed-kernel success criterion: post-eviction touch of A re-faults or SIGBUSes; Vs marker is never observable through A.", "recommended_fix": "Replace the object-walk in the DF drm_vma_node_unmap with a pmap_page_protect(VM_PROT_NONE) sweep over the VMAs fictitious aperture pages [gmadr+node.start, +node.size) \u2014 see fix.diff", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "not_testable: no Intel GPU in the QEMU guest, so neither baseline nor patched kernel can exercise the revocation path; the fix is validated by construction (pmap_page_protect is the same primitive cdev_pager_free_page uses, applied to the exact fictitious pages the fault path entered).", "fix_evidence": "fix.diff; sys/vm/device_pager.c:184-194 (pmap_page_protect idiom); i915_gem.c:2418-2428 (fictitious page source of the same addresses)" } |