[mutter/wip/texture-purge-on-nvidia: 27/71] wayland/keyboard: Create a separate keymap shm file per resource



commit 0dd58540b2b20647011e1b06ed61009d8d45f65f
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Thu Jun 29 12:22:47 2017 +0800

    wayland/keyboard: Create a separate keymap shm file per resource
    
    By using the shm file when sending the keymap to all clients, we
    effectively allows any client to change the keymap, as any client has
    the ability to change the content of the file. Sending a read-only file
    descriptor, or making the file itself read-only before unlinking, can
    be worked around by the client by using chmod(2) and open(2) on
    /proc/<pid>/<fd>.
    
    Using memfd could potentially solve this issue, but as the usage of
    mmap with MAP_SHARED is wide spread among clients, such a change can
    not be introduced without causing wide spread compatibility issues.
    
    So, to avoid allowing clients to interfere with each other, create a
    separate shm file for each wl_keyboard resource when sending the
    keymap. We could eventually do this per client, but in most cases,
    there will only be one wl_keyboard resource per client anyway.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=784206

 src/wayland/meta-wayland-keyboard.c | 136 +++++++++++++++---------------------
 src/wayland/meta-wayland-keyboard.h |   3 +-
 2 files changed, 56 insertions(+), 83 deletions(-)
---
diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c
index d4ae4508d..e3ba4f000 100644
--- a/src/wayland/meta-wayland-keyboard.c
+++ b/src/wayland/meta-wayland-keyboard.c
@@ -127,34 +127,65 @@ create_anonymous_file (off_t size,
 }
 
 static void
-inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard)
+send_keymap (MetaWaylandKeyboard *keyboard,
+             struct wl_resource  *resource)
 {
-  struct wl_resource *keyboard_resource;
+  MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info;
+  GError *error = NULL;
+  int fd;
+  char *keymap_area;
 
-  wl_resource_for_each (keyboard_resource, &keyboard->resource_list)
+  if (!xkb_info->keymap_string)
+    return;
+
+  fd = create_anonymous_file (xkb_info->keymap_size, &error);
+  if (fd < 0)
     {
-      wl_keyboard_send_keymap (keyboard_resource,
-                              WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
-                              keyboard->xkb_info.keymap_fd,
-                              keyboard->xkb_info.keymap_size);
+      g_warning ("Creating a keymap file for %lu bytes failed: %s",
+                 (unsigned long) xkb_info->keymap_size,
+                 error->message);
+      g_clear_error (&error);
+      return;
     }
-  wl_resource_for_each (keyboard_resource, &keyboard->focus_resource_list)
+
+
+  keymap_area = mmap (NULL, xkb_info->keymap_size,
+                      PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (keymap_area == MAP_FAILED)
     {
-      wl_keyboard_send_keymap (keyboard_resource,
-                               WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
-                               keyboard->xkb_info.keymap_fd,
-                               keyboard->xkb_info.keymap_size);
+      g_warning ("Failed to mmap() %lu bytes\n",
+                 (unsigned long) xkb_info->keymap_size);
+      close (fd);
+      return;
     }
+
+  strcpy (keymap_area, xkb_info->keymap_string);
+
+  munmap (keymap_area, xkb_info->keymap_size);
+
+  wl_keyboard_send_keymap (resource,
+                           WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+                           fd,
+                           keyboard->xkb_info.keymap_size);
+  close (fd);
+}
+
+static void
+inform_clients_of_new_keymap (MetaWaylandKeyboard *keyboard)
+{
+  struct wl_resource *keyboard_resource;
+
+  wl_resource_for_each (keyboard_resource, &keyboard->resource_list)
+    send_keymap (keyboard, keyboard_resource);
+  wl_resource_for_each (keyboard_resource, &keyboard->focus_resource_list)
+    send_keymap (keyboard, keyboard_resource);
 }
 
 static void
 meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
                                   struct xkb_keymap   *keymap)
 {
-  MetaWaylandXkbInfo  *xkb_info = &keyboard->xkb_info;
-  GError *error = NULL;
-  char *keymap_str;
-  size_t previous_size;
+  MetaWaylandXkbInfo *xkb_info = &keyboard->xkb_info;
 
   if (keymap == NULL)
     {
@@ -162,60 +193,24 @@ meta_wayland_keyboard_take_keymap (MetaWaylandKeyboard *keyboard,
       return;
     }
 
+  g_clear_pointer (&xkb_info->keymap_string, g_free);
   xkb_keymap_unref (xkb_info->keymap);
   xkb_info->keymap = xkb_keymap_ref (keymap);
 
   meta_wayland_keyboard_update_xkb_state (keyboard);
 
-  keymap_str = xkb_map_get_as_string (xkb_info->keymap);
-  if (keymap_str == NULL)
+  xkb_info->keymap_string =
+    xkb_keymap_get_as_string (xkb_info->keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
+  if (!xkb_info->keymap_string)
     {
-      g_warning ("failed to get string version of keymap");
+      g_warning ("Failed to get string version of keymap");
       return;
     }
-  previous_size = xkb_info->keymap_size;
-  xkb_info->keymap_size = strlen (keymap_str) + 1;
-
-  if (xkb_info->keymap_fd >= 0)
-    close (xkb_info->keymap_fd);
-
-  xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error);
-  if (xkb_info->keymap_fd < 0)
-    {
-      g_warning ("creating a keymap file for %lu bytes failed: %s",
-                 (unsigned long) xkb_info->keymap_size,
-                 error->message);
-      g_clear_error (&error);
-      goto err_keymap_str;
-    }
-
-  if (xkb_info->keymap_area)
-    munmap (xkb_info->keymap_area, previous_size);
-
-  xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size,
-                                PROT_READ | PROT_WRITE,
-                                MAP_SHARED, xkb_info->keymap_fd, 0);
-  if (xkb_info->keymap_area == MAP_FAILED)
-    {
-      g_warning ("failed to mmap() %lu bytes\n",
-                 (unsigned long) xkb_info->keymap_size);
-      goto err_dev_zero;
-    }
-  strcpy (xkb_info->keymap_area, keymap_str);
-  free (keymap_str);
+  xkb_info->keymap_size = strlen (xkb_info->keymap_string) + 1;
 
   inform_clients_of_new_keymap (keyboard);
 
   notify_modifiers (keyboard);
-
-  return;
-
-err_dev_zero:
-  close (xkb_info->keymap_fd);
-  xkb_info->keymap_fd = -1;
-err_keymap_str:
-  free (keymap_str);
-  return;
 }
 
 static xkb_mod_mask_t
@@ -707,28 +702,12 @@ meta_wayland_keyboard_enable (MetaWaylandKeyboard *keyboard)
   maybe_restore_numlock_state (keyboard);
 }
 
-static void
-meta_wayland_xkb_info_init (MetaWaylandXkbInfo *xkb_info)
-{
-  xkb_info->keymap_fd = -1;
-}
-
 static void
 meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
 {
   g_clear_pointer (&xkb_info->keymap, xkb_keymap_unref);
   g_clear_pointer (&xkb_info->state, xkb_state_unref);
-
-  if (xkb_info->keymap_area)
-    {
-      munmap (xkb_info->keymap_area, xkb_info->keymap_size);
-      xkb_info->keymap_area = NULL;
-    }
-  if (xkb_info->keymap_fd >= 0)
-    {
-      close (xkb_info->keymap_fd);
-      xkb_info->keymap_fd = -1;
-    }
+  g_clear_pointer (&xkb_info->keymap_string, g_free);
 }
 
 void
@@ -1001,10 +980,7 @@ meta_wayland_keyboard_create_new_resource (MetaWaylandKeyboard *keyboard,
   wl_resource_set_implementation (resource, &keyboard_interface,
                                   keyboard, unbind_resource);
 
-  wl_keyboard_send_keymap (resource,
-                           WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
-                           keyboard->xkb_info.keymap_fd,
-                           keyboard->xkb_info.keymap_size);
+  send_keymap (keyboard, resource);
 
   notify_key_repeat_for_resource (keyboard, resource);
 
@@ -1050,8 +1026,6 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard)
   wl_list_init (&keyboard->resource_list);
   wl_list_init (&keyboard->focus_resource_list);
 
-  meta_wayland_xkb_info_init (&keyboard->xkb_info);
-
   keyboard->default_grab.interface = &default_keyboard_grab_interface;
   keyboard->default_grab.keyboard = keyboard;
   keyboard->grab = &keyboard->default_grab;
diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h
index 39f06ef17..dba9fda0c 100644
--- a/src/wayland/meta-wayland-keyboard.h
+++ b/src/wayland/meta-wayland-keyboard.h
@@ -74,9 +74,8 @@ typedef struct
 {
   struct xkb_keymap *keymap;
   struct xkb_state *state;
-  int keymap_fd;
   size_t keymap_size;
-  char *keymap_area;
+  char *keymap_string;
 } MetaWaylandXkbInfo;
 
 struct _MetaWaylandKeyboard


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]