aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Vetter <[email protected]>2021-01-19 14:03:18 +0100
committerDaniel Vetter <[email protected]>2021-01-20 10:28:39 +0100
commita37eef63bc9e16e06361b539e528058146af80ab (patch)
treef293a8ba69184675d764d4497c77a7cacf189422
parentabbc4d6ecd07fa246fd597b5d8fced28f0bcc606 (diff)
drm/syncobj: Fix use-after-free
While reviewing Christian's annotation patch I noticed that we have a user-after-free for the WAIT_FOR_SUBMIT case: We drop the syncobj reference before we've completed the waiting. Of course usually there's nothing bad happening here since userspace keeps the reference, but we can't rely on userspace to play nice here! Signed-off-by: Daniel Vetter <[email protected]> Fixes: bc9c80fe01a2 ("drm/syncobj: use the timeline point in drm_syncobj_find_fence v4") Reviewed-by: Christian König <[email protected]> Cc: Christian König <[email protected]> Cc: Lionel Landwerlin <[email protected]> Cc: Maarten Lankhorst <[email protected]> Cc: Maxime Ripard <[email protected]> Cc: Thomas Zimmermann <[email protected]> Cc: David Airlie <[email protected]> Cc: Daniel Vetter <[email protected]> Cc: [email protected] Cc: <[email protected]> # v5.2+ Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
-rw-r--r--drivers/gpu/drm/drm_syncobj.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 6e74e6745eca..349146049849 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -388,19 +388,18 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
return -ENOENT;
*fence = drm_syncobj_fence_get(syncobj);
- drm_syncobj_put(syncobj);
if (*fence) {
ret = dma_fence_chain_find_seqno(fence, point);
if (!ret)
- return 0;
+ goto out;
dma_fence_put(*fence);
} else {
ret = -EINVAL;
}
if (!(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
- return ret;
+ goto out;
memset(&wait, 0, sizeof(wait));
wait.task = current;
@@ -432,6 +431,9 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
if (wait.node.next)
drm_syncobj_remove_wait(syncobj, &wait);
+out:
+ drm_syncobj_put(syncobj);
+
return ret;
}
EXPORT_SYMBOL(drm_syncobj_find_fence);