Blame SOURCES/0001-wayland-keyboard-Create-a-separate-keymap-shm-file-p.patch

776610
From 0d134522d83ee263cdc83ea899af59fd264bafa7 Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Thu, 29 Jun 2017 12:22:47 +0800
776610
Subject: [PATCH] wayland/keyboard: Create a separate keymap shm file per
776610
 resource
776610
776610
By using the shm file when sending the keymap to all clients, we
776610
effectively allows any client to change the keymap, as any client has
776610
the ability to change the content of the file. Sending a read-only file
776610
descriptor, or making the file itself read-only before unlinking, can
776610
be worked around by the client by using chmod(2) and open(2) on
776610
/proc/<pid>/<fd>.
776610
776610
Using memfd could potentially solve this issue, but as the usage of
776610
mmap with MAP_SHARED is wide spread among clients, such a change can
776610
not be introduced without causing wide spread compatibility issues.
776610
776610
So, to avoid allowing clients to interfere with each other, create a
776610
separate shm file for each wl_keyboard resource when sending the
776610
keymap. We could eventually do this per client, but in most cases,
776610
there will only be one wl_keyboard resource per client anyway.
776610
776610
https://bugzilla.gnome.org/show_bug.cgi?id=784206
776610
---
776610
 src/wayland/meta-wayland-keyboard.c | 136 +++++++++++-----------------
776610
 src/wayland/meta-wayland-keyboard.h |   3 +-
776610
 2 files changed, 56 insertions(+), 83 deletions(-)
776610
776610
diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c
776610
index 167293ca7..aca1fe411 100644
776610
--- a/src/wayland/meta-wayland-keyboard.c
776610
+++ b/src/wayland/meta-wayland-keyboard.c
776610
@@ -127,34 +127,65 @@ create_anonymous_file (off_t    size,
776610
 }
776610
 
776610
 static void
776610
-inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard)
776610
+send_keymap (MetaWaylandKeyboard *keyboard,
776610
+             struct wl_resource  *resource)
776610
 {
776610
-  struct wl_resource *keyboard_resource;
776610
+  MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info;
776610
+  GError *error = NULL;
776610
+  int fd;
776610
+  char *keymap_area;
776610
 
776610
-  wl_resource_for_each (keyboard_resource, &keyboard->resource_list)
776610
+  if (!xkb_info->keymap_string)
776610
+    return;
776610
+
776610
+  fd = create_anonymous_file (xkb_info->keymap_size, &error);
776610
+  if (fd < 0)
776610
     {
776610
-      wl_keyboard_send_keymap (keyboard_resource,
776610
-			       WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
776610
-			       keyboard->xkb_info.keymap_fd,
776610
-			       keyboard->xkb_info.keymap_size);
776610
+      g_warning ("Creating a keymap file for %lu bytes failed: %s",
776610
+                 (unsigned long) xkb_info->keymap_size,
776610
+                 error->message);
776610
+      g_clear_error (&error);
776610
+      return;
776610
     }
776610
-  wl_resource_for_each (keyboard_resource, &keyboard->focus_resource_list)
776610
+
776610
+
776610
+  keymap_area = mmap (NULL, xkb_info->keymap_size,
776610
+                      PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
776610
+  if (keymap_area == MAP_FAILED)
776610
     {
776610
-      wl_keyboard_send_keymap (keyboard_resource,
776610
-                               WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
776610
-                               keyboard->xkb_info.keymap_fd,
776610
-                               keyboard->xkb_info.keymap_size);
776610
+      g_warning ("Failed to mmap() %lu bytes\n",
776610
+                 (unsigned long) xkb_info->keymap_size);
776610
+      close (fd);
776610
+      return;
776610
     }
776610
+
776610
+  strcpy (keymap_area, xkb_info->keymap_string);
776610
+
776610
+  munmap (keymap_area, xkb_info->keymap_size);
776610
+
776610
+  wl_keyboard_send_keymap (resource,
776610
+                           WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
776610
+                           fd,
776610
+                           keyboard->xkb_info.keymap_size);
776610
+  close (fd);
776610
+}
776610
+
776610
+static void
776610
+inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard)
776610
+{
776610
+  struct wl_resource *keyboard_resource;
776610
+
776610
+  wl_resource_for_each (keyboard_resource, &keyboard->resource_list)
776610
+    send_keymap (keyboard, keyboard_resource);
776610
+  wl_resource_for_each (keyboard_resource, &keyboard->focus_resource_list)
776610
+    send_keymap (keyboard, keyboard_resource);
776610
 }
776610
 
776610
 static void
776610
 meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
776610
 				   struct xkb_keymap   *keymap)
776610
 {
776610
-  MetaWaylandXkbInfo  *xkb_info = &keyboard->xkb_info;
776610
-  GError *error = NULL;
776610
-  char *keymap_str;
776610
-  size_t previous_size;
776610
+  MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info;
776610
 
776610
   if (keymap == NULL)
776610
     {
776610
@@ -162,60 +193,24 @@ meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
776610
       return;
776610
     }
776610
 
776610
+  g_clear_pointer (&xkb_info->keymap_string, g_free);
776610
   xkb_keymap_unref (xkb_info->keymap);
776610
   xkb_info->keymap = xkb_keymap_ref (keymap);
776610
 
776610
   meta_wayland_keyboard_update_xkb_state (keyboard);
776610
 
776610
-  keymap_str = xkb_map_get_as_string (xkb_info->keymap);
776610
-  if (keymap_str == NULL)
776610
+  xkb_info->keymap_string =
776610
+    xkb_keymap_get_as_string (xkb_info->keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
776610
+  if (!xkb_info->keymap_string)
776610
     {
776610
-      g_warning ("failed to get string version of keymap");
776610
+      g_warning ("Failed to get string version of keymap");
776610
       return;
776610
     }
776610
-  previous_size = xkb_info->keymap_size;
776610
-  xkb_info->keymap_size = strlen (keymap_str) + 1;
776610
-
776610
-  if (xkb_info->keymap_fd >= 0)
776610
-    close (xkb_info->keymap_fd);
776610
-
776610
-  xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error);
776610
-  if (xkb_info->keymap_fd < 0)
776610
-    {
776610
-      g_warning ("creating a keymap file for %lu bytes failed: %s",
776610
-                 (unsigned long) xkb_info->keymap_size,
776610
-                 error->message);
776610
-      g_clear_error (&error);
776610
-      goto err_keymap_str;
776610
-    }
776610
-
776610
-  if (xkb_info->keymap_area)
776610
-    munmap (xkb_info->keymap_area, previous_size);
776610
-
776610
-  xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size,
776610
-                                PROT_READ | PROT_WRITE,
776610
-                                MAP_SHARED, xkb_info->keymap_fd, 0);
776610
-  if (xkb_info->keymap_area == MAP_FAILED)
776610
-    {
776610
-      g_warning ("failed to mmap() %lu bytes\n",
776610
-                 (unsigned long) xkb_info->keymap_size);
776610
-      goto err_dev_zero;
776610
-    }
776610
-  strcpy (xkb_info->keymap_area, keymap_str);
776610
-  free (keymap_str);
776610
+  xkb_info->keymap_size = strlen (xkb_info->keymap_string) + 1;
776610
 
776610
   inform_clients_of_new_keymap (keyboard);
776610
 
776610
   notify_modifiers (keyboard);
776610
-
776610
-  return;
776610
-
776610
-err_dev_zero:
776610
-  close (xkb_info->keymap_fd);
776610
-  xkb_info->keymap_fd = -1;
776610
-err_keymap_str:
776610
-  free (keymap_str);
776610
-  return;
776610
 }
776610
 
776610
 static xkb_mod_mask_t
776610
@@ -707,28 +702,12 @@ meta_wayland_keyboard_enable (MetaWaylandKeyboard *keyboard)
776610
   maybe_restore_numlock_state (keyboard);
776610
 }
776610
 
776610
-static void
776610
-meta_wayland_xkb_info_init (MetaWaylandXkbInfo *xkb_info)
776610
-{
776610
-  xkb_info->keymap_fd = -1;
776610
-}
776610
-
776610
 static void
776610
 meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
776610
 {
776610
   g_clear_pointer (&xkb_info->keymap, xkb_keymap_unref);
776610
   g_clear_pointer (&xkb_info->state, xkb_state_unref);
776610
-
776610
-  if (xkb_info->keymap_area)
776610
-    {
776610
-      munmap (xkb_info->keymap_area, xkb_info->keymap_size);
776610
-      xkb_info->keymap_area = NULL;
776610
-    }
776610
-  if (xkb_info->keymap_fd >= 0)
776610
-    {
776610
-      close (xkb_info->keymap_fd);
776610
-      xkb_info->keymap_fd = -1;
776610
-    }
776610
+  g_clear_pointer (&xkb_info->keymap_string, g_free);
776610
 }
776610
 
776610
 void
776610
@@ -1001,10 +980,7 @@ meta_wayland_keyboard_create_new_resource (MetaWaylandKeyboard *keyboard,
776610
   wl_resource_set_implementation (resource, &keyboard_interface,
776610
                                   keyboard, unbind_resource);
776610
 
776610
-  wl_keyboard_send_keymap (resource,
776610
-                           WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
776610
-                           keyboard->xkb_info.keymap_fd,
776610
-                           keyboard->xkb_info.keymap_size);
776610
+  send_keymap (keyboard, resource);
776610
 
776610
   notify_key_repeat_for_resource (keyboard, resource);
776610
 
776610
@@ -1050,8 +1026,6 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard)
776610
   wl_list_init (&keyboard->resource_list);
776610
   wl_list_init (&keyboard->focus_resource_list);
776610
 
776610
-  meta_wayland_xkb_info_init (&keyboard->xkb_info);
776610
-
776610
   keyboard->default_grab.interface = &default_keyboard_grab_interface;
776610
   keyboard->default_grab.keyboard = keyboard;
776610
   keyboard->grab = &keyboard->default_grab;
776610
diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h
776610
index 39f06ef17..dba9fda0c 100644
776610
--- a/src/wayland/meta-wayland-keyboard.h
776610
+++ b/src/wayland/meta-wayland-keyboard.h
776610
@@ -74,9 +74,8 @@ typedef struct
776610
 {
776610
   struct xkb_keymap *keymap;
776610
   struct xkb_state *state;
776610
-  int keymap_fd;
776610
   size_t keymap_size;
776610
-  char *keymap_area;
776610
+  char *keymap_string;
776610
 } MetaWaylandXkbInfo;
776610
 
776610
 struct _MetaWaylandKeyboard
776610
-- 
776610
2.19.0
776610