⬢ DragonFlyBSD Kernel Audit
DF-5186 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/drm_gem.c b/sys/dev/drm/drm_gem.c
--- a/sys/dev/drm/drm_gem.c
+++ b/sys/dev/drm/drm_gem.c
@@ -529,18 +529,24 @@ EXPORT_SYMBOL(drm_gem_create_mmap_offset_size);
 void
 drm_gem_free_mmap_offset(struct drm_gem_object *obj)
 {
 	struct drm_device *dev = obj->dev;
 
 	struct drm_gem_mm *mm = dev->mm_private;
 	struct drm_hash_item *list;
 
+	/* Serialize against concurrent drm_gem_create_mmap_offset*(). */
+	mutex_lock(&dev->object_name_lock);
 	if (!obj->on_map)
-		return;
+		goto out;
 	list = &obj->map_list;
 
 	drm_ht_remove_item(&mm->offset_hash, list);
 	free_unr(mm->idxunr, list->key);
 	obj->on_map = false;
 
 	drm_vma_offset_remove(dev->vma_offset_manager, &obj->vma_node);
+out:
+	mutex_unlock(&dev->object_name_lock);
 }
 EXPORT_SYMBOL(drm_gem_free_mmap_offset);
 
 /**
@@ -567,19 +573,28 @@ EXPORT_SYMBOL(drm_gem_free_mmap_offset);
 int
 drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size)
 {
 	struct drm_device *dev = obj->dev;
 	struct drm_gem_mm *mm = dev->mm_private;
 	int ret = 0;
 
+	/*
+	 * The legacy offset_hash/idxunr publication is not RCU-safe on
+	 * DragonFly and is consumed under DRM_LOCK by
+	 * drm_gem_object_from_offset().  Two DRM_UNLOCKED MAP_DUMB (or
+	 * i915 MMAP_GTT) calls race here otherwise.  object_name_lock is
+	 * LK_CANRECURSE and sleepable (alloc_unr may sleep).
+	 */
+	mutex_lock(&dev->object_name_lock);
 	if (obj->on_map)
-		return (0);
+		goto out_unlocked_vma;
  
 	obj->map_list.key = alloc_unr(mm->idxunr);
 	ret = drm_ht_insert_item(&mm->offset_hash, &obj->map_list);
 	if (ret != 0) {
 		DRM_ERROR("failed to add to map hash\n");
 		free_unr(mm->idxunr, obj->map_list.key);
-		return (ret);
+		mutex_unlock(&dev->object_name_lock);
+		return (ret);
 	}
 	obj->on_map = true;
+	mutex_unlock(&dev->object_name_lock);
 
 	return drm_vma_offset_add(dev->vma_offset_manager, &obj->vma_node,
 				  size / PAGE_SIZE);
+out_unlocked_vma:
+	mutex_unlock(&dev->object_name_lock);
+	return (0);
 }
 EXPORT_SYMBOL(drm_gem_create_mmap_offset_size);