diff mbox series

drm/syncobj: Fix use-after-free

Message ID 20210119130318.615145-1-daniel.vetter@ffwll.ch (mailing list archive)
State New, archived
Headers show
Series drm/syncobj: Fix use-after-free | expand

Commit Message

Daniel Vetter Jan. 19, 2021, 1:03 p.m. UTC
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 <daniel.vetter@intel.com>
Fixes: bc9c80fe01a2 ("drm/syncobj: use the timeline point in drm_syncobj_find_fence v4")
Cc: Christian König <christian.koenig@amd.com>
Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: David Airlie <airlied@linux.ie>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: dri-devel@lists.freedesktop.org
Cc: <stable@vger.kernel.org> # v5.2+
---
 drivers/gpu/drm/drm_syncobj.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

Comments

Christian König Jan. 19, 2021, 1:08 p.m. UTC | #1
Am 19.01.21 um 14:03 schrieb Daniel Vetter:
> 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 <daniel.vetter@intel.com>
> Fixes: bc9c80fe01a2 ("drm/syncobj: use the timeline point in drm_syncobj_find_fence v4")
> Cc: Christian König <christian.koenig@amd.com>
> Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: Maxime Ripard <mripard@kernel.org>
> Cc: Thomas Zimmermann <tzimmermann@suse.de>
> Cc: David Airlie <airlied@linux.ie>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: dri-devel@lists.freedesktop.org
> Cc: <stable@vger.kernel.org> # v5.2+

Reviewed-by: Christian König <christian.koenig@amd.com>

> ---
>   drivers/gpu/drm/drm_syncobj.c | 8 +++++---
>   1 file 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);
Daniel Vetter Jan. 20, 2021, 9:28 a.m. UTC | #2
On Tue, Jan 19, 2021 at 02:08:12PM +0100, Christian König wrote:
> Am 19.01.21 um 14:03 schrieb Daniel Vetter:
> > 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 <daniel.vetter@intel.com>
> > Fixes: bc9c80fe01a2 ("drm/syncobj: use the timeline point in drm_syncobj_find_fence v4")
> > Cc: Christian König <christian.koenig@amd.com>
> > Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > Cc: Maxime Ripard <mripard@kernel.org>
> > Cc: Thomas Zimmermann <tzimmermann@suse.de>
> > Cc: David Airlie <airlied@linux.ie>
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Cc: dri-devel@lists.freedesktop.org
> > Cc: <stable@vger.kernel.org> # v5.2+
> 
> Reviewed-by: Christian König <christian.koenig@amd.com>

Pushed to drm-misc-fixes, thanks for reviewing.
-Daniel

> 
> > ---
> >   drivers/gpu/drm/drm_syncobj.c | 8 +++++---
> >   1 file 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);
>
diff mbox series

Patch

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);