Blame SOURCES/0001-wayland-Avoid-a-race-in-wl_seat-capabilities.patch

f7d48e
From 5e4a1290ce75ed94e3f0f457d35a225f2ef3878c Mon Sep 17 00:00:00 2001
f7d48e
From: Olivier Fourdan <ofourdan@redhat.com>
f7d48e
Date: Tue, 28 Nov 2017 10:54:08 +0100
f7d48e
Subject: [PATCH] wayland: Avoid a race in wl_seat capabilities
f7d48e
f7d48e
The way wl_seat capabilities work, by notifying clients of capabilities
f7d48e
changes, and clients consequently requesting the relevant interface
f7d48e
objects (pointer, keyboard, touch) is inherently racy.
f7d48e
f7d48e
On quick VT changes for example, capabilities on the seat will be added
f7d48e
and removed, and by the time the client receives the capability change
f7d48e
notification and requests the relevant keyboard, pointer or touch,
f7d48e
another VT switch might have occurred and the wl_pointer, wl_keyboard or
f7d48e
wl_touch already destroyed, leading to a protocol error which kills the
f7d48e
client.
f7d48e
f7d48e
To avoid this, create the objects when requested regardless of the
f7d48e
capabilities.
f7d48e
f7d48e
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1797
f7d48e
Related: https://bugzilla.gnome.org/show_bug.cgi?id=790932
f7d48e
---
f7d48e
 src/wayland/meta-wayland-pointer.c | 45 ++++++++++++++++++++++++------
f7d48e
 src/wayland/meta-wayland-seat.c    |  9 ++----
f7d48e
 src/wayland/meta-wayland-touch.c   |  8 ------
f7d48e
 3 files changed, 40 insertions(+), 22 deletions(-)
f7d48e
f7d48e
diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c
f7d48e
index 3132abfd2..abd779ad7 100644
f7d48e
--- a/src/wayland/meta-wayland-pointer.c
f7d48e
+++ b/src/wayland/meta-wayland-pointer.c
f7d48e
@@ -109,7 +109,7 @@ meta_wayland_pointer_client_new (void)
f7d48e
 }
f7d48e
 
f7d48e
 static void
f7d48e
-meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
f7d48e
+meta_wayland_pointer_make_resources_inert (MetaWaylandPointerClient *pointer_client)
f7d48e
 {
f7d48e
   struct wl_resource *resource, *next;
f7d48e
 
f7d48e
@@ -141,10 +141,25 @@ meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
f7d48e
       wl_list_init (wl_resource_get_link (resource));
f7d48e
       wl_resource_set_user_data (resource, NULL);
f7d48e
     }
f7d48e
+}
f7d48e
 
f7d48e
+static void
f7d48e
+meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
f7d48e
+{
f7d48e
+  meta_wayland_pointer_make_resources_inert (pointer_client);
f7d48e
   g_free (pointer_client);
f7d48e
 }
f7d48e
 
f7d48e
+static void
f7d48e
+make_resources_inert_foreach (gpointer key,
f7d48e
+                              gpointer value,
f7d48e
+                              gpointer data)
f7d48e
+{
f7d48e
+  MetaWaylandPointerClient *pointer_client = value;
f7d48e
+
f7d48e
+  meta_wayland_pointer_make_resources_inert (pointer_client);
f7d48e
+}
f7d48e
+
f7d48e
 static gboolean
f7d48e
 meta_wayland_pointer_client_is_empty (MetaWaylandPointerClient *pointer_client)
f7d48e
 {
f7d48e
@@ -158,8 +173,6 @@ MetaWaylandPointerClient *
f7d48e
 meta_wayland_pointer_get_pointer_client (MetaWaylandPointer *pointer,
f7d48e
                                          struct wl_client   *client)
f7d48e
 {
f7d48e
-  if (!pointer->pointer_clients)
f7d48e
-    return NULL;
f7d48e
   return g_hash_table_lookup (pointer->pointer_clients, client);
f7d48e
 }
f7d48e
 
f7d48e
@@ -475,10 +488,6 @@ meta_wayland_pointer_enable (MetaWaylandPointer *pointer)
f7d48e
   MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
f7d48e
   ClutterSeat *clutter_seat;
f7d48e
 
f7d48e
-  pointer->pointer_clients =
f7d48e
-    g_hash_table_new_full (NULL, NULL, NULL,
f7d48e
-                           (GDestroyNotify) meta_wayland_pointer_client_free);
f7d48e
-
f7d48e
   pointer->cursor_surface = NULL;
f7d48e
 
f7d48e
   clutter_seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
f7d48e
@@ -508,6 +517,10 @@ meta_wayland_pointer_disable (MetaWaylandPointer *pointer)
f7d48e
   ClutterBackend *clutter_backend = clutter_get_default_backend ();
f7d48e
   ClutterSeat *clutter_seat = clutter_backend_get_default_seat (clutter_backend);
f7d48e
 
f7d48e
+  g_hash_table_foreach (pointer->pointer_clients,
f7d48e
+                        make_resources_inert_foreach,
f7d48e
+                        NULL);
f7d48e
+
f7d48e
   g_signal_handlers_disconnect_by_func (cursor_tracker,
f7d48e
                                         (gpointer) meta_wayland_pointer_on_cursor_changed,
f7d48e
                                         pointer);
f7d48e
@@ -531,7 +544,6 @@ meta_wayland_pointer_disable (MetaWaylandPointer *pointer)
f7d48e
   meta_wayland_pointer_set_focus (pointer, NULL);
f7d48e
   meta_wayland_pointer_set_current (pointer, NULL);
f7d48e
 
f7d48e
-  g_clear_pointer (&pointer->pointer_clients, g_hash_table_unref);
f7d48e
   pointer->cursor_surface = NULL;
f7d48e
 }
f7d48e
 
f7d48e
@@ -1356,11 +1368,28 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer)
f7d48e
   pointer->default_grab.interface = &default_pointer_grab_interface;
f7d48e
   pointer->default_grab.pointer = pointer;
f7d48e
   pointer->grab = &pointer->default_grab;
f7d48e
+  pointer->pointer_clients =
f7d48e
+    g_hash_table_new_full (NULL, NULL, NULL,
f7d48e
+                           (GDestroyNotify) meta_wayland_pointer_client_free);
f7d48e
+}
f7d48e
+
f7d48e
+static void
f7d48e
+meta_wayland_pointer_finalize (GObject *object)
f7d48e
+{
f7d48e
+  MetaWaylandPointer *pointer = META_WAYLAND_POINTER (object);
f7d48e
+
f7d48e
+  g_clear_pointer (&pointer->pointer_clients, g_hash_table_unref);
f7d48e
+
f7d48e
+  G_OBJECT_CLASS (meta_wayland_pointer_parent_class)->finalize (object);
f7d48e
 }
f7d48e
 
f7d48e
 static void
f7d48e
 meta_wayland_pointer_class_init (MetaWaylandPointerClass *klass)
f7d48e
 {
f7d48e
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
f7d48e
+
f7d48e
+  object_class->finalize = meta_wayland_pointer_finalize;
f7d48e
+
f7d48e
   signals[FOCUS_SURFACE_CHANGED] = g_signal_new ("focus-surface-changed",
f7d48e
                                                  G_TYPE_FROM_CLASS (klass),
f7d48e
                                                  G_SIGNAL_RUN_LAST,
f7d48e
diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c
f7d48e
index c6390dde7..efce6d6d6 100644
f7d48e
--- a/src/wayland/meta-wayland-seat.c
f7d48e
+++ b/src/wayland/meta-wayland-seat.c
f7d48e
@@ -46,8 +46,7 @@ seat_get_pointer (struct wl_client *client,
f7d48e
   MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
f7d48e
   MetaWaylandPointer *pointer = seat->pointer;
f7d48e
 
f7d48e
-  if (meta_wayland_seat_has_pointer (seat))
f7d48e
-    meta_wayland_pointer_create_new_resource (pointer, client, resource, id);
f7d48e
+  meta_wayland_pointer_create_new_resource (pointer, client, resource, id);
f7d48e
 }
f7d48e
 
f7d48e
 static void
f7d48e
@@ -58,8 +57,7 @@ seat_get_keyboard (struct wl_client *client,
f7d48e
   MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
f7d48e
   MetaWaylandKeyboard *keyboard = seat->keyboard;
f7d48e
 
f7d48e
-  if (meta_wayland_seat_has_keyboard (seat))
f7d48e
-    meta_wayland_keyboard_create_new_resource (keyboard, client, resource, id);
f7d48e
+  meta_wayland_keyboard_create_new_resource (keyboard, client, resource, id);
f7d48e
 }
f7d48e
 
f7d48e
 static void
f7d48e
@@ -70,8 +68,7 @@ seat_get_touch (struct wl_client *client,
f7d48e
   MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
f7d48e
   MetaWaylandTouch *touch = seat->touch;
f7d48e
 
f7d48e
-  if (meta_wayland_seat_has_touch (seat))
f7d48e
-    meta_wayland_touch_create_new_resource (touch, client, resource, id);
f7d48e
+  meta_wayland_touch_create_new_resource (touch, client, resource, id);
f7d48e
 }
f7d48e
 
f7d48e
 static void
f7d48e
diff --git a/src/wayland/meta-wayland-touch.c b/src/wayland/meta-wayland-touch.c
f7d48e
index 002ff16f7..15f0312eb 100644
f7d48e
--- a/src/wayland/meta-wayland-touch.c
f7d48e
+++ b/src/wayland/meta-wayland-touch.c
f7d48e
@@ -521,16 +521,8 @@ meta_wayland_touch_create_new_resource (MetaWaylandTouch   *touch,
f7d48e
                                         struct wl_resource *seat_resource,
f7d48e
                                         uint32_t            id)
f7d48e
 {
f7d48e
-  MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
f7d48e
   struct wl_resource *cr;
f7d48e
 
f7d48e
-  if (!meta_wayland_seat_has_touch (seat))
f7d48e
-    {
f7d48e
-      wl_resource_post_error (seat_resource, WL_DISPLAY_ERROR_INVALID_METHOD,
f7d48e
-                              "Cannot retrieve touch interface without touch capability");
f7d48e
-      return;
f7d48e
-    }
f7d48e
-
f7d48e
   cr = wl_resource_create (client, &wl_touch_interface, wl_resource_get_version (seat_resource), id);
f7d48e
   wl_resource_set_implementation (cr, &touch_interface, touch, unbind_resource);
f7d48e
   wl_list_insert (&touch->resource_list, wl_resource_get_link (cr));
f7d48e
-- 
f7d48e
2.31.1
f7d48e