summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerek Foreman <derekf@osg.samsung.com>2017-06-28 12:17:46 -0500
committerDerek Foreman <derekf@osg.samsung.com>2018-08-17 09:25:24 -0500
commit76829fc4eaea329d2a525c3978271e13bd76c078 (patch)
treefe9e08bf3b47505ca21010f2b54d01159963c0e5
parentf8f7fd69df5bf318b2da9ec6ce964ac676eb2e29 (diff)
input: Send unique keymap file descriptors to clients
Client may map any file descriptor opened for writing with PROT_WRITE themselves. On linux, even a read-only file descriptor to an unlinked file can be re-opened with write permission through /proc/self/fd. The only way to prevent this is to create a memfd which is subsequently write-sealed. Unfortunately this prevents clients from mapping with MAP_SHARED, which is already in widespread usage. To isolate and protect the keymap, whilst allowing MAP_SHARED clients to continue to work, use a unique file descriptor for each wl_keyboard resource. Reviewed-by: Daniel Stone <daniels@collabora.com>
-rw-r--r--libweston/compositor.h3
-rw-r--r--libweston/input.c60
2 files changed, 28 insertions, 35 deletions
diff --git a/libweston/compositor.h b/libweston/compositor.h
index 82592eb2..8b7a1020 100644
--- a/libweston/compositor.h
+++ b/libweston/compositor.h
@@ -714,9 +714,8 @@ weston_touch_start_drag(struct weston_touch *touch,
struct weston_xkb_info {
struct xkb_keymap *keymap;
- int keymap_fd;
size_t keymap_size;
- char *keymap_area;
+ char *keymap_string;
int32_t ref_count;
xkb_mod_index_t shift_mod;
xkb_mod_index_t caps_mod;
diff --git a/libweston/input.c b/libweston/input.c
index ad1dfeb3..6579592b 100644
--- a/libweston/input.c
+++ b/libweston/input.c
@@ -2084,11 +2084,31 @@ WL_EXPORT void
weston_keyboard_send_keymap(struct weston_keyboard *kbd, struct wl_resource *resource)
{
struct weston_xkb_info *xkb_info = kbd->xkb_info;
+ void *area;
+ int fd;
+ fd = os_create_anonymous_file(xkb_info->keymap_size);
+ if (fd < 0) {
+ weston_log("creating a keymap file for %lu bytes failed: %m\n",
+ (unsigned long) xkb_info->keymap_size);
+ return;
+ }
+
+ area = mmap(NULL, xkb_info->keymap_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (area == MAP_FAILED) {
+ weston_log("failed to mmap() %lu bytes\n",
+ (unsigned long) xkb_info->keymap_size);
+ goto err_mmap;
+ }
+ strcpy(area, xkb_info->keymap_string);
+ munmap(area, xkb_info->keymap_size);
wl_keyboard_send_keymap(resource,
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
- xkb_info->keymap_fd,
+ fd,
xkb_info->keymap_size);
+err_mmap:
+ close(fd);
}
static void
@@ -3126,10 +3146,8 @@ weston_xkb_info_destroy(struct weston_xkb_info *xkb_info)
xkb_keymap_unref(xkb_info->keymap);
- if (xkb_info->keymap_area)
- munmap(xkb_info->keymap_area, xkb_info->keymap_size);
- if (xkb_info->keymap_fd >= 0)
- close(xkb_info->keymap_fd);
+ if (xkb_info->keymap_string)
+ free(xkb_info->keymap_string);
free(xkb_info);
}
@@ -3157,8 +3175,6 @@ weston_xkb_info_create(struct xkb_keymap *keymap)
xkb_info->keymap = xkb_keymap_ref(keymap);
xkb_info->ref_count = 1;
- char *keymap_str;
-
xkb_info->shift_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
XKB_MOD_NAME_SHIFT);
xkb_info->caps_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
@@ -3183,38 +3199,16 @@ weston_xkb_info_create(struct xkb_keymap *keymap)
xkb_info->scroll_led = xkb_keymap_led_get_index(xkb_info->keymap,
XKB_LED_NAME_SCROLL);
- keymap_str = xkb_keymap_get_as_string(xkb_info->keymap,
- XKB_KEYMAP_FORMAT_TEXT_V1);
- 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 == NULL) {
weston_log("failed to get string version of keymap\n");
goto err_keymap;
}
- xkb_info->keymap_size = strlen(keymap_str) + 1;
-
- xkb_info->keymap_fd = os_create_anonymous_file(xkb_info->keymap_size);
- if (xkb_info->keymap_fd < 0) {
- weston_log("creating a keymap file for %lu bytes failed: %m\n",
- (unsigned long) xkb_info->keymap_size);
- goto err_keymap_str;
- }
-
- 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) {
- weston_log("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;
return xkb_info;
-err_dev_zero:
- close(xkb_info->keymap_fd);
-err_keymap_str:
- free(keymap_str);
err_keymap:
xkb_keymap_unref(xkb_info->keymap);
free(xkb_info);