diff --git a/sys/dev/drm/i915/i915_gem.c b/sys/dev/drm/i915/i915_gem.c --- a/sys/dev/drm/i915/i915_gem.c +++ b/sys/dev/drm/i915/i915_gem.c @@ -2263,6 +2263,20 @@ page_offset = (unsigned long)offset >> PAGE_SHIFT; /* + * Reject faults beyond the GEM object's size. drm_gem_mmap_single() + * passes the user mmap length straight through to cdev_pager_allocate(), + * so the backing vm_object can be larger than the GEM object; without + * this check an oversized mmap would let us compute a GMADR address + * past this object's GTT slot and read/write neighbouring slots. + */ + if (offset >= obj->base.size) { +#ifdef __DragonFly__ + up_read(&area->vm_mm->mmap_sem); +#endif + return VM_PAGER_ERROR; + } + + /* * vm_fault() has supplied us with a busied page placeholding * the operation. This presents a lock order reversal issue * again i915_gem_release_mmap() for our device mutex. @@ -2388,8 +2402,23 @@ #endif /* Finally, remap it using the new GTT offset */ - m = vm_phys_fictitious_to_vm_page(ggtt->gmadr.start + - vma->node.start + offset); + { + uint64_t ggtt_addr = ggtt->gmadr.start + + vma->node.start + offset; + + /* + * For I915_GGTT_VIEW_PARTIAL VMAs the node maps only a chunk + * of the object starting at view.partial.offset, so the + * object-relative fault offset must be shifted to be + * chunk-relative before adding the node address, otherwise we + * return pages from neighbouring GTT slots. + */ + if (vma->ggtt_view.type == I915_GGTT_VIEW_PARTIAL) + ggtt_addr -= (uint64_t)vma->ggtt_view.partial.offset << + PAGE_SHIFT; + + m = vm_phys_fictitious_to_vm_page(ggtt_addr); + } if (m == NULL) { kprintf("i915: caught bug() (phys_fict_to_vm)\n");