DF-4458 / fix.diff
--- a/sys/dev/drm/drm_gem.c +++ b/sys/dev/drm/drm_gem.c @@ -1085,6 +1100,7 @@ { struct drm_gem_object *gem_obj; struct vm_object *vm_obj; + vm_ooffset_t maoff; DRM_LOCK(dev); gem_obj = drm_gem_object_from_offset(dev, *offset); @@ -1096,9 +1112,25 @@ drm_gem_object_reference(gem_obj); DRM_UNLOCK(dev); + + /* + * The caller (vm_mmap -> dev_dmmap_single) passes the mmap(2) + * length through verbatim, and the user directly controls bits + * 0..39 of the fake offset (the in-object byte offset). The + * upstream size clamp lives in drm_gem_mmap_obj() ("obj_size < + * vma->vm_end - vma->vm_start"), which is #if 0'd on DragonFly, + * so nothing else bounds the fault range against the object: + * enforce [maoff, maoff + size) within the object here before + * creating the device pager. + */ + maoff = DRM_GEM_MAPPING_MAPOFF(*offset); + if (size > gem_obj->size || maoff > gem_obj->size - size) { + drm_gem_object_unreference_unlocked(gem_obj); + return (EINVAL); + } vm_obj = cdev_pager_allocate(gem_obj, OBJT_MGTDEVICE, dev->driver->gem_vm_ops, size, nprot, - DRM_GEM_MAPPING_MAPOFF(*offset), curthread->td_ucred); + maoff, curthread->td_ucred); if (vm_obj == NULL) { drm_gem_object_unreference_unlocked(gem_obj); return (EINVAL); |