⬢ DragonFlyBSD Kernel Audit
DF-4604 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/radeon/radeon_gem.c
+++ b/sys/dev/drm/radeon/radeon_gem.c
@@ -547,10 +547,12 @@ int radeon_gem_get_tiling_ioctl(struct d
 /**
  * radeon_gem_va_update_vm -update the bo_va in its VM
  *
  * @rdev: radeon_device pointer
- * @bo_va: bo_va to update
+ * @vm:    vm of the calling file
+ * @rbo:   radeon_bo the ioctl operates on (ref held by the caller's
+ *         drm_gem_object_lookup())
  *
- * Update the bo_va directly after setting it's address. Errors are not
- * vital here, so they are not reported back to userspace.
+ * Update the bo_va directly after setting its address. Errors are not
+ * vital here, so they are not reported back to userspace.
+ *
+ * Must not be handed a raw bo_va: see radeon_gem_va_ioctl().
  */
 static void radeon_gem_va_update_vm(struct radeon_device *rdev,
-				    struct radeon_bo_va *bo_va)
+				    struct radeon_vm *vm,
+				    struct radeon_bo *rbo)
 {
 	struct ttm_validate_buffer tv, *entry;
 	struct radeon_bo_list *vm_bos;
@@ -563,7 +565,7 @@ static void radeon_gem_va_update_vm(stru
 
-	tv.bo = &bo_va->bo->tbo;
+	tv.bo = &rbo->tbo;
 	tv.shared = true;
 	list_add(&tv.head, &list);
 
-	vm_bos = radeon_vm_get_bos(rdev, bo_va->vm, &list);
+	vm_bos = radeon_vm_get_bos(rdev, vm, &list);
 	if (!vm_bos)
 		return;
 
 	r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL);
 	if (r)
 		goto error_free;
 
+	/*
+	 * radeon_vm_bo_set_addr() dropped the BO reservation on return, so a
+	 * concurrent GEM_CLOSE on this file could already have removed (and
+	 * freed) the bo_va.  Re-lookup under the reservation just established
+	 * by ttm_eu_reserve_buffers(); if it is gone there is nothing left to
+	 * update.
+	 */
+	bo_va = radeon_vm_bo_find(vm, rbo);
+	if (!bo_va)
+		goto error_unreserve;
+
 	list_for_each_entry(entry, &list, head) {
 		domain = radeon_mem_type_to_domain(entry->bo->mem.mem_type);
 		/* if anything is swapped out don't swap it in here,
@@ -582,9 +584,9 @@ static void radeon_gem_va_update_vm(stru
 	if (r)
 		goto error_unlock;
 
 	if (bo_va->it.start)
 		r = radeon_vm_bo_update(rdev, bo_va, &bo_va->bo->tbo.mem);
 
 error_unlock:
-	mutex_unlock(&bo_va->vm->mutex);
+	mutex_unlock(&vm->mutex);
 
 error_unreserve:
 	ttm_eu_backoff_reservation(&ticket, &list);
@@ -698,7 +700,7 @@ int radeon_gem_va_ioctl(struct drm_devic
 		r = radeon_vm_bo_set_addr(rdev, bo_va, 0, 0);
 		break;
 	}
 	if (!r)
-		radeon_gem_va_update_vm(rdev, bo_va);
+		radeon_gem_va_update_vm(rdev, &fpriv->vm, rbo);
 	args->operation = RADEON_VA_RESULT_OK;
 	if (r) {
 		args->operation = RADEON_VA_RESULT_ERROR;