[Mesa-dev] [PATCH] nouveau: Use dup fd as key in drm-winsys hash table to fix ZaphodHeads.

Mario Kleiner mario.kleiner.de at gmail.com
Fri Jun 5 06:36:52 PDT 2015

The dup'ed fd owned by the nouveau_screen for a device node
must also be used as key for the winsys hash table, instead
of using the original fd passed in for a screen, to make
multi-x-screen ZaphodHeads configurations work on nouveau.

This prevents the following crash scenario that was observed
when a dynamically loaded rendering plugin used OpenGL on a
ZaphodHeads setup, e.g., on a dual x-screen setup. At first
load the plugin worked, but after unloading and reloading it,
the next rendering operation crashed:

1. Client, e.g., a plugin, calls glXQueryVersion.

2. DRI screens for the x-screens 0 and 1 are created, one shared
   nouveau_screen is created for the shared device node of both
   screens, but the original fd of x-screen 0 is used as identifying
   key in the hash table, instead of the dup()ed fd of x-screen 0
   which is owned by the nouveau_screen. nouveau_screen's refcount
   is now 2.

3. Regular rendering happens by the client plugin, then the plugin
   gets unloaded.

4. XCloseDisplay(). x-screen 0 gets its DRI screen destroyed,
   nouveau_drm_screen_unref() drops the refcount to 1, calling mesa
   code then closes the fd of x-screen 0, so now the fd which is
   used as key in the hash table is invalid. x-screen 1 gets
   destroyed, nouveau_drm_screen_unref() drops the refcount to 0,
   the nouveau_screen gets destroyed, but removal of its entry
   in the hash table fails, because the invalid fd in the hash
   table no longer matches anything (fstat() on the fd is used
   for hashing and key comparison, but fstat() on an already closed
   fd fails and returns bogus results). x-screen 1 closes its fd.

   Now all fd's are closed, the nouveau_screen destroyed, but
   there is a dangling reference to the nouveau_screen in the
   hash table.

5. Some OpenGL client plugin gets loaded again and calls
   glXQueryVersion. Step 2 above repeats, but because a
   dangling reference with a matching fd is found in the winsys
   hash table, no new nouveau_screen is created this time. Instead
   the invalid pointer to the old nouveau_screen is recycled,
   which points to nirvana -> Crash.

This problem is avoided by use of the dup()ed fd which is
owned by the nouveau_screen and has the same lifetime as
the nouveau_screen itself.

Cc: "10.3 10.4 10.5 10.6" <mesa-stable at lists.freedesktop.org>

Signed-off-by: Mario Kleiner <mario.kleiner.de at gmail.com>
Cc: Ilia Mirkin <imirkin at alum.mit.edu>
 src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
index 0635246..dbc3cae 100644
--- a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
+++ b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
@@ -120,7 +120,8 @@ nouveau_drm_screen_create(int fd)
 	if (!screen)
 		goto err;
-	util_hash_table_set(fd_tab, intptr_to_pointer(fd), screen);
+	/* Use dupfd in hash table, to avoid crashes in ZaphodHeads configs */
+	util_hash_table_set(fd_tab, intptr_to_pointer(dupfd), screen);
 	screen->refcount = 1;
 	return &screen->base;

More information about the mesa-dev mailing list