⬢ DragonFlyBSD Kernel Audit
DF-5033 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/amd/amdgpu/amdgpu_bo_list.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -164,15 +164,22 @@
 int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id,
 		       struct amdgpu_bo_list **result)
 {
-	rcu_read_lock();
+	/*
+	 * The DragonFly idr (sys/libkern/linux_idr.c) is not RCU-safe for
+	 * lookups: idr_find() takes no lock, and idr_grow() swaps in a new
+	 * node array and kfree()s the old one synchronously.  Serialize
+	 * against idr_alloc()/idr_remove()/idr_replace() with bo_list_lock
+	 * instead of rcu_read_lock().
+	 */
+	mutex_lock(&fpriv->bo_list_lock);
 	*result = idr_find(&fpriv->bo_list_handles, id);
 
 	if (*result && kref_get_unless_zero(&(*result)->refcount)) {
-		rcu_read_unlock();
+		mutex_unlock(&fpriv->bo_list_lock);
 		return 0;
 	}
 
-	rcu_read_unlock();
+	mutex_unlock(&fpriv->bo_list_lock);
 	return -ENOENT;
 }