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

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