From ac14d741ee25ae13ab6271b5181c1e415164695f Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Wed, 5 Mar 2014 22:25:55 -0500 Subject: [PATCH] nouveau: fix fence waiting logic in screen destroy nouveau_fence_wait has the expectation that an external entity is holding onto the fence being waited on, not that it is merely held onto by the current pointer. Fixes a use-after-free in nouveau_fence_wait when used on the screen's current fence. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=75279 Signed-off-by: Ilia Mirkin Reviewed-by: Christoph Bumiller Cc: "9.2 10.0 10.1" (cherry picked from commit 507f0230d4ca2238c818006499e21abb4c133203) Conflicts: src/gallium/drivers/nouveau/nv30/nv30_screen.c --- src/gallium/drivers/nouveau/nv30/nv30_screen.c | 14 ++++++++++---- src/gallium/drivers/nouveau/nv50/nv50_screen.c | 11 +++++++++-- src/gallium/drivers/nouveau/nvc0/nvc0_screen.c | 9 ++++++++- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/gallium/drivers/nouveau/nv30/nv30_screen.c b/src/gallium/drivers/nouveau/nv30/nv30_screen.c index 1be37cc09ca..8ec6c3b32af 100644 --- a/src/gallium/drivers/nouveau/nv30/nv30_screen.c +++ b/src/gallium/drivers/nouveau/nv30/nv30_screen.c @@ -302,10 +302,16 @@ nv30_screen_destroy(struct pipe_screen *pscreen) { struct nv30_screen *screen = nv30_screen(pscreen); - if (screen->base.fence.current && - screen->base.fence.current->state >= NOUVEAU_FENCE_STATE_EMITTED) { - nouveau_fence_wait(screen->base.fence.current); - nouveau_fence_ref (NULL, &screen->base.fence.current); + if (screen->base.fence.current) { + struct nouveau_fence *current = NULL; + + /* nouveau_fence_wait will create a new current fence, so wait on the + * _current_ one, and remove both. + */ + nouveau_fence_ref(screen->base.fence.current, ¤t); + nouveau_fence_wait(current); + nouveau_fence_ref(NULL, ¤t); + nouveau_fence_ref(NULL, &screen->base.fence.current); } nouveau_object_del(&screen->query); diff --git a/src/gallium/drivers/nouveau/nv50/nv50_screen.c b/src/gallium/drivers/nouveau/nv50/nv50_screen.c index 96a35ffbb18..4b23677e845 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_screen.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_screen.c @@ -290,8 +290,15 @@ nv50_screen_destroy(struct pipe_screen *pscreen) struct nv50_screen *screen = nv50_screen(pscreen); if (screen->base.fence.current) { - nouveau_fence_wait(screen->base.fence.current); - nouveau_fence_ref (NULL, &screen->base.fence.current); + struct nouveau_fence *current = NULL; + + /* nouveau_fence_wait will create a new current fence, so wait on the + * _current_ one, and remove both. + */ + nouveau_fence_ref(screen->base.fence.current, ¤t); + nouveau_fence_wait(current); + nouveau_fence_ref(NULL, ¤t); + nouveau_fence_ref(NULL, &screen->base.fence.current); } if (screen->base.pushbuf) screen->base.pushbuf->user_priv = NULL; diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c index 79d2ab99a1a..137cdb1742e 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c @@ -334,7 +334,14 @@ nvc0_screen_destroy(struct pipe_screen *pscreen) struct nvc0_screen *screen = nvc0_screen(pscreen); if (screen->base.fence.current) { - nouveau_fence_wait(screen->base.fence.current); + struct nouveau_fence *current = NULL; + + /* nouveau_fence_wait will create a new current fence, so wait on the + * _current_ one, and remove both. + */ + nouveau_fence_ref(screen->base.fence.current, ¤t); + nouveau_fence_wait(current); + nouveau_fence_ref(NULL, ¤t); nouveau_fence_ref(NULL, &screen->base.fence.current); } if (screen->base.pushbuf)