From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <michel.daenzer@amd.com>
Date: Fri, 3 Nov 2017 16:00:35 +0100
Subject: drm/ttm: Always and only destroy bo->ttm_resv in ttm_bo_release_list
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Git-commit: e1fc12c5d9ad06a2a74e97a91f1b0c5f4c723b50
Patch-mainline: v4.15-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166
Fixes a use-after-free due to a race condition in
ttm_bo_cleanup_refs_and_unlock, which allows one task to reserve a BO
and destroy its ttm_resv while another task is waiting for it to signal
in reservation_object_wait_timeout_rcu.
v2:
* Always initialize bo->ttm_resv in ttm_bo_init_reserved
(Christian König)
Fixes: 0d2bd2ae045d "drm/ttm: fix memory leak while individualizing BOs"
Reviewed-by: Chunming Zhou <david1.zhou@amd.com> # v1
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
drivers/gpu/drm/ttm/ttm_bo.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -150,8 +150,7 @@ static void ttm_bo_release_list(struct k
ttm_tt_destroy(bo->ttm);
atomic_dec(&bo->glob->bo_count);
dma_fence_put(bo->moving);
- if (bo->resv == &bo->ttm_resv)
- reservation_object_fini(&bo->ttm_resv);
+ reservation_object_fini(&bo->ttm_resv);
mutex_destroy(&bo->wu_mutex);
if (bo->destroy)
bo->destroy(bo);
@@ -402,14 +401,11 @@ static int ttm_bo_individualize_resv(str
if (bo->resv == &bo->ttm_resv)
return 0;
- reservation_object_init(&bo->ttm_resv);
BUG_ON(!reservation_object_trylock(&bo->ttm_resv));
r = reservation_object_copy_fences(&bo->ttm_resv, bo->resv);
- if (r) {
+ if (r)
reservation_object_unlock(&bo->ttm_resv);
- reservation_object_fini(&bo->ttm_resv);
- }
return r;
}
@@ -457,10 +453,8 @@ static void ttm_bo_cleanup_refs_or_queue
if (reservation_object_test_signaled_rcu(&bo->ttm_resv, true)) {
ttm_bo_del_from_lru(bo);
spin_unlock(&glob->lru_lock);
- if (bo->resv != &bo->ttm_resv) {
+ if (bo->resv != &bo->ttm_resv)
reservation_object_unlock(&bo->ttm_resv);
- reservation_object_fini(&bo->ttm_resv);
- }
ttm_bo_cleanup_memtype_use(bo);
return;
@@ -560,8 +554,6 @@ static int ttm_bo_cleanup_refs_and_unloc
}
ttm_bo_del_from_lru(bo);
- if (!list_empty(&bo->ddestroy) && (bo->resv != &bo->ttm_resv))
- reservation_object_fini(&bo->ttm_resv);
list_del_init(&bo->ddestroy);
kref_put(&bo->list_kref, ttm_bo_ref_bug);
@@ -1210,8 +1202,8 @@ int ttm_bo_init_reserved(struct ttm_bo_d
lockdep_assert_held(&bo->resv->lock.base);
} else {
bo->resv = &bo->ttm_resv;
- reservation_object_init(&bo->ttm_resv);
}
+ reservation_object_init(&bo->ttm_resv);
atomic_inc(&bo->glob->bo_count);
drm_vma_node_reset(&bo->vma_node);
bo->priority = 0;