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