In vma destruction, the following race may occur:
Thread 1: Thread 2: i915_vma_destroy();
... list_del_init(vma->vm_link); ... mutex_unlock(vma->vm->mutex); __i915_vm_release(); release_references();
And in release_reference() we dereference vma->vm to get to the vm gt pointer, leading to a use-after free.
However, __i915_vm_release() grabs the vm->mutex so the vm won't be destroyed before vma->vm->mutex is released, so extract the gt pointer under the vm->mutex to avoid the vma->vm dereference in release_references().
v2: Fix a typo in the commit message (Andi Shyti)
Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/5944 Fixes: e1a7ab4fca ("drm/i915: Remove the vm open count")
Cc: Niranjana Vishwanathapura niranjana.vishwanathapura@intel.com Cc: Matthew Auld matthew.auld@intel.com Signed-off-by: Thomas Hellström thomas.hellstrom@linux.intel.com --- drivers/gpu/drm/i915/i915_vma.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 0bffb70b3c5f..04d12f278f57 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -1637,10 +1637,10 @@ static void force_unbind(struct i915_vma *vma) GEM_BUG_ON(drm_mm_node_allocated(&vma->node)); }
-static void release_references(struct i915_vma *vma, bool vm_ddestroy) +static void release_references(struct i915_vma *vma, struct intel_gt *gt, + bool vm_ddestroy) { struct drm_i915_gem_object *obj = vma->obj; - struct intel_gt *gt = vma->vm->gt;
GEM_BUG_ON(i915_vma_is_active(vma));
@@ -1695,11 +1695,12 @@ void i915_vma_destroy_locked(struct i915_vma *vma)
force_unbind(vma); list_del_init(&vma->vm_link); - release_references(vma, false); + release_references(vma, vma->vm->gt, false); }
void i915_vma_destroy(struct i915_vma *vma) { + struct intel_gt *gt; bool vm_ddestroy;
mutex_lock(&vma->vm->mutex); @@ -1707,8 +1708,11 @@ void i915_vma_destroy(struct i915_vma *vma) list_del_init(&vma->vm_link); vm_ddestroy = vma->vm_ddestroy; vma->vm_ddestroy = false; + + /* vma->vm may be freed when releasing vma->vm->mutex. */ + gt = vma->vm->gt; mutex_unlock(&vma->vm->mutex); - release_references(vma, vm_ddestroy); + release_references(vma, gt, vm_ddestroy); }
void i915_vma_parked(struct intel_gt *gt)
Acked-by: Nirmoy Das nirmoy.das@intel.con
On 6/20/2022 2:36 PM, Thomas Hellström wrote:
In vma destruction, the following race may occur:
Thread 1: Thread 2: i915_vma_destroy();
... list_del_init(vma->vm_link); ... mutex_unlock(vma->vm->mutex); __i915_vm_release(); release_references();
And in release_reference() we dereference vma->vm to get to the vm gt pointer, leading to a use-after free.
However, __i915_vm_release() grabs the vm->mutex so the vm won't be destroyed before vma->vm->mutex is released, so extract the gt pointer under the vm->mutex to avoid the vma->vm dereference in release_references().
v2: Fix a typo in the commit message (Andi Shyti)
Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/5944 Fixes: e1a7ab4fca ("drm/i915: Remove the vm open count")
Cc: Niranjana Vishwanathapura niranjana.vishwanathapura@intel.com Cc: Matthew Auld matthew.auld@intel.com Signed-off-by: Thomas Hellström thomas.hellstrom@linux.intel.com
drivers/gpu/drm/i915/i915_vma.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 0bffb70b3c5f..04d12f278f57 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -1637,10 +1637,10 @@ static void force_unbind(struct i915_vma *vma) GEM_BUG_ON(drm_mm_node_allocated(&vma->node)); }
-static void release_references(struct i915_vma *vma, bool vm_ddestroy) +static void release_references(struct i915_vma *vma, struct intel_gt *gt,
{ struct drm_i915_gem_object *obj = vma->obj;bool vm_ddestroy)
struct intel_gt *gt = vma->vm->gt;
GEM_BUG_ON(i915_vma_is_active(vma));
@@ -1695,11 +1695,12 @@ void i915_vma_destroy_locked(struct i915_vma *vma)
force_unbind(vma); list_del_init(&vma->vm_link);
- release_references(vma, false);
release_references(vma, vma->vm->gt, false); }
void i915_vma_destroy(struct i915_vma *vma) {
struct intel_gt *gt; bool vm_ddestroy;
mutex_lock(&vma->vm->mutex);
@@ -1707,8 +1708,11 @@ void i915_vma_destroy(struct i915_vma *vma) list_del_init(&vma->vm_link); vm_ddestroy = vma->vm_ddestroy; vma->vm_ddestroy = false;
- /* vma->vm may be freed when releasing vma->vm->mutex. */
- gt = vma->vm->gt; mutex_unlock(&vma->vm->mutex);
- release_references(vma, vm_ddestroy);
release_references(vma, gt, vm_ddestroy); }
void i915_vma_parked(struct intel_gt *gt)
On 20.06.2022 14:36, Thomas Hellström wrote:
In vma destruction, the following race may occur:
Thread 1: Thread 2: i915_vma_destroy();
... list_del_init(vma->vm_link); ... mutex_unlock(vma->vm->mutex); __i915_vm_release(); release_references();
And in release_reference() we dereference vma->vm to get to the vm gt pointer, leading to a use-after free.
However, __i915_vm_release() grabs the vm->mutex so the vm won't be destroyed before vma->vm->mutex is released, so extract the gt pointer under the vm->mutex to avoid the vma->vm dereference in release_references().
v2: Fix a typo in the commit message (Andi Shyti)
Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/5944 Fixes: e1a7ab4fca ("drm/i915: Remove the vm open count")
Cc: Niranjana Vishwanathapura niranjana.vishwanathapura@intel.com Cc: Matthew Auld matthew.auld@intel.com Signed-off-by: Thomas Hellström thomas.hellstrom@linux.intel.com
drivers/gpu/drm/i915/i915_vma.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 0bffb70b3c5f..04d12f278f57 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -1637,10 +1637,10 @@ static void force_unbind(struct i915_vma *vma) GEM_BUG_ON(drm_mm_node_allocated(&vma->node)); }
-static void release_references(struct i915_vma *vma, bool vm_ddestroy) +static void release_references(struct i915_vma *vma, struct intel_gt *gt,
{ struct drm_i915_gem_object *obj = vma->obj;bool vm_ddestroy)
struct intel_gt *gt = vma->vm->gt;
GEM_BUG_ON(i915_vma_is_active(vma));
@@ -1695,11 +1695,12 @@ void i915_vma_destroy_locked(struct i915_vma *vma)
force_unbind(vma); list_del_init(&vma->vm_link);
- release_references(vma, false);
release_references(vma, vma->vm->gt, false); }
void i915_vma_destroy(struct i915_vma *vma) {
struct intel_gt *gt; bool vm_ddestroy;
mutex_lock(&vma->vm->mutex);
@@ -1707,8 +1708,11 @@ void i915_vma_destroy(struct i915_vma *vma) list_del_init(&vma->vm_link); vm_ddestroy = vma->vm_ddestroy; vma->vm_ddestroy = false;
- /* vma->vm may be freed when releasing vma->vm->mutex. */
- gt = vma->vm->gt; mutex_unlock(&vma->vm->mutex);
- release_references(vma, vm_ddestroy);
- release_references(vma, gt, vm_ddestroy);
Reviewed-by: Andrzej Hajda andrzej.hajda@intel.com
Regards Andrzej
}
void i915_vma_parked(struct intel_gt *gt)
dri-devel@lists.freedesktop.org