Skip to content

Commit e531fdb

Browse files
robclarkChristianKoenigAMD
authored andcommitted
dma-buf/sw_sync: Avoid recursive lock during fence signal
If a signal callback releases the sw_sync fence, that will trigger a deadlock as the timeline_fence_release recurses onto the fence->lock (used both for signaling and the the timeline tree). To avoid that, temporarily hold an extra reference to the signalled fences until after we drop the lock. (This is an alternative implementation of https://patchwork.kernel.org/patch/11664717/ which avoids some potential UAF issues with the original patch.) v2: Remove now obsolete comment, use list_move_tail() and list_del_init() Reported-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl> Fixes: d3c6dd1 ("dma-buf/sw_sync: Synchronize signal vs syncpt free") Signed-off-by: Rob Clark <robdclark@chromium.org> Link: https://patchwork.freedesktop.org/patch/msgid/20230818145939.39697-1-robdclark@gmail.com Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Christian König <christian.koenig@amd.com>
1 parent 5ad1ab3 commit e531fdb

File tree

1 file changed

+9
-9
lines changed

1 file changed

+9
-9
lines changed

drivers/dma-buf/sw_sync.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ static const struct dma_fence_ops timeline_fence_ops = {
191191
*/
192192
static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
193193
{
194+
LIST_HEAD(signalled);
194195
struct sync_pt *pt, *next;
195196

196197
trace_sync_timeline(obj);
@@ -203,21 +204,20 @@ static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
203204
if (!timeline_fence_signaled(&pt->base))
204205
break;
205206

206-
list_del_init(&pt->link);
207+
dma_fence_get(&pt->base);
208+
209+
list_move_tail(&pt->link, &signalled);
207210
rb_erase(&pt->node, &obj->pt_tree);
208211

209-
/*
210-
* A signal callback may release the last reference to this
211-
* fence, causing it to be freed. That operation has to be
212-
* last to avoid a use after free inside this loop, and must
213-
* be after we remove the fence from the timeline in order to
214-
* prevent deadlocking on timeline->lock inside
215-
* timeline_fence_release().
216-
*/
217212
dma_fence_signal_locked(&pt->base);
218213
}
219214

220215
spin_unlock_irq(&obj->lock);
216+
217+
list_for_each_entry_safe(pt, next, &signalled, link) {
218+
list_del_init(&pt->link);
219+
dma_fence_put(&pt->base);
220+
}
221221
}
222222

223223
/**

0 commit comments

Comments
 (0)