diff mbox series

[meta,dunfell] libinput: Add fix for CVE-2022-1215

Message ID 20220509062438.12448-1-badganchipv@gmail.com
State New, archived
Headers show
Series [meta,dunfell] libinput: Add fix for CVE-2022-1215 | expand

Commit Message

Pawan Badganchi May 9, 2022, 6:24 a.m. UTC
From: Pawan Badganchi <badganchipv@gmail.com>

Add below patch to fix CVE-2022-1215

CVE-2022-1215.patch
Link: https://gitlab.freedesktop.org/libinput/libinput/-/commit/2a8b8fde90d63d48ce09ddae44142674bbca1c28

Signed-off-by: Pawan Badganchi<badganchipv@gmail.com>
---
 .../wayland/libinput/CVE-2022-1215.patch      | 361 ++++++++++++++++++
 .../wayland/libinput_1.15.2.bb                |   1 +
 2 files changed, 362 insertions(+)
 create mode 100644 meta/recipes-graphics/wayland/libinput/CVE-2022-1215.patch
diff mbox series

Patch

diff --git a/meta/recipes-graphics/wayland/libinput/CVE-2022-1215.patch b/meta/recipes-graphics/wayland/libinput/CVE-2022-1215.patch
new file mode 100644
index 0000000000..5f8f7a9894
--- /dev/null
+++ b/meta/recipes-graphics/wayland/libinput/CVE-2022-1215.patch
@@ -0,0 +1,361 @@ 
+From 2a8b8fde90d63d48ce09ddae44142674bbca1c28 Mon Sep 17 00:00:00 2001
+From: Peter Hutterer <peter.hutterer@who-t.net>
+Date: Wed, 30 Mar 2022 09:25:22 +1000
+Subject: [PATCH] evdev: strip the device name of format directives
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This fixes a format string vulnerabilty.
+
+evdev_log_message() composes a format string consisting of a fixed
+prefix (including the rendered device name) and the passed-in format
+buffer. This format string is then passed with the arguments to the
+actual log handler, which usually and eventually ends up being printf.
+
+If the device name contains a printf-style format directive, these ended
+up in the format string and thus get interpreted correctly, e.g. for a
+device "Foo%sBar" the log message vs printf invocation ends up being:
+  evdev_log_message(device, "some message %s", "some argument");
+  printf("event9 - Foo%sBar: some message %s", "some argument");
+
+This can enable an attacker to execute malicious code with the
+privileges of the process using libinput.
+
+To exploit this, an attacker needs to be able to create a kernel device
+with a malicious name, e.g. through /dev/uinput or a Bluetooth device.
+
+To fix this, convert any potential format directives in the device name
+by duplicating percentages.
+
+Pre-rendering the device to avoid the issue altogether would be nicer
+but the current log level hooks do not easily allow for this. The device
+name is the only user-controlled part of the format string.
+
+A second potential issue is the sysname of the device which is also
+sanitized.
+
+This issue was found by Albin Eldstål-Ahrens and Benjamin Svensson from
+Assured AB, and independently by Lukas Lamster.
+
+Fixes #752
+
+Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
+(cherry picked from commit a423d7d3269dc32a87384f79e29bb5ac021c83d1)
+
+CVE: CVE-2022-1215
+Upstream Status: Backport [https://gitlab.freedesktop.org/libinput/libinput/-/commit/2a8b8fde90d63d48ce09ddae44142674bbca1c28]
+Signed-off-by: Pawan Badganchi <Pawan.Badganchi@kpit.com>
+
+---
+ meson.build                        |  1 +
+ src/evdev.c                        | 31 +++++++++++------
+ src/evdev.h                        |  6 ++--
+ src/util-strings.h                 | 30 ++++++++++++++++
+ test/litest-device-format-string.c | 56 ++++++++++++++++++++++++++++++
+ test/litest.h                      |  1 +
+ test/test-utils.c                  | 26 ++++++++++++++
+ 7 files changed, 139 insertions(+), 12 deletions(-)
+ create mode 100644 test/litest-device-format-string.c
+
+diff --git a/meson.build b/meson.build
+index 90f528e6..1f6159e7 100644
+--- a/meson.build
++++ b/meson.build
+@@ -787,6 +787,7 @@
+ 		'test/litest-device-dell-canvas-totem-touch.c',
+ 		'test/litest-device-elantech-touchpad.c',
+ 		'test/litest-device-elan-tablet.c',
++		'test/litest-device-format-string.c',
+ 		'test/litest-device-generic-singletouch.c',
+ 		'test/litest-device-gpio-keys.c',
+ 		'test/litest-device-huion-pentablet.c',
+diff --git a/src/evdev.c b/src/evdev.c
+index 6d81f58f..d1c35c07 100644
+--- a/src/evdev.c
++++ b/src/evdev.c
+@@ -2356,19 +2356,19 @@ evdev_device_create(struct libinput_seat *seat,
+ 	struct libinput *libinput = seat->libinput;
+ 	struct evdev_device *device = NULL;
+ 	int rc;
+-	int fd;
++	int fd = -1;
+ 	int unhandled_device = 0;
+ 	const char *devnode = udev_device_get_devnode(udev_device);
+-	const char *sysname = udev_device_get_sysname(udev_device);
++	char *sysname = str_sanitize(udev_device_get_sysname(udev_device));
+ 
+ 	if (!devnode) {
+ 		log_info(libinput, "%s: no device node associated\n", sysname);
+-		return NULL;
++		goto err;
+ 	}
+ 
+ 	if (udev_device_should_be_ignored(udev_device)) {
+ 		log_debug(libinput, "%s: device is ignored\n", sysname);
+-		return NULL;
++		goto err;
+ 	}
+ 
+ 	/* Use non-blocking mode so that we can loop on read on
+@@ -2382,13 +2382,15 @@ evdev_device_create(struct libinput_seat *seat,
+ 			 sysname,
+ 			 devnode,
+ 			 strerror(-fd));
+-		return NULL;
++		goto err;
+ 	}
+ 
+ 	if (!evdev_device_have_same_syspath(udev_device, fd))
+ 		goto err;
+ 
+ 	device = zalloc(sizeof *device);
++	device->sysname = sysname;
++	sysname = NULL;
+ 
+ 	libinput_device_init(&device->base, seat);
+ 	libinput_seat_ref(seat);
+@@ -2411,6 +2413,9 @@ evdev_device_create(struct libinput_seat *seat,
+ 	device->dispatch = NULL;
+ 	device->fd = fd;
+ 	device->devname = libevdev_get_name(device->evdev);
++	/* the log_prefix_name is used as part of a printf format string and
++	 * must not contain % directives, see evdev_log_msg */
++	device->log_prefix_name = str_sanitize(device->devname);
+ 	device->scroll.threshold = 5.0; /* Default may be overridden */
+ 	device->scroll.direction_lock_threshold = 5.0; /* Default may be overridden */
+ 	device->scroll.direction = 0;
+@@ -2238,9 +2238,14 @@
+ 	return device;
+ 
+ err:
+-	close_restricted(libinput, fd);
+-	if (device)
+-		evdev_device_destroy(device);
++	if (fd >= 0) {
++		close_restricted(libinput, fd);
++		if (device) {
++			unhandled_device = device->seat_caps == 0;
++			evdev_device_destroy(device);
++		}
++            }
++        free(sysname);
+ 
+ 	return unhandled_device ? EVDEV_UNHANDLED_DEVICE :  NULL;
+ }
+
+@@ -2469,7 +2478,7 @@ evdev_device_get_output(struct evdev_device *device)
+ const char *
+ evdev_device_get_sysname(struct evdev_device *device)
+ {
+-	return udev_device_get_sysname(device->udev_device);
++	return device->sysname;
+ }
+ 
+ const char *
+@@ -3066,6 +3075,8 @@ evdev_device_destroy(struct evdev_device *device)
+ 	if (device->base.group)
+ 		libinput_device_group_unref(device->base.group);
+ 
++	free(device->log_prefix_name);
++	free(device->sysname);
+ 	free(device->output_name);
+ 	filter_destroy(device->pointer.filter);
+ 	libinput_timer_destroy(&device->scroll.timer);
+diff --git a/src/evdev.h b/src/evdev.h
+index c7d130f8..980c5943 100644
+--- a/src/evdev.h
++++ b/src/evdev.h
+@@ -169,6 +169,8 @@ struct evdev_device {
+ 	struct udev_device *udev_device;
+ 	char *output_name;
+ 	const char *devname;
++	char *log_prefix_name;
++	char *sysname;
+ 	bool was_removed;
+ 	int fd;
+ 	enum evdev_device_seat_capability seat_caps;
+@@ -786,7 +788,7 @@ evdev_log_msg(struct evdev_device *device,
+ 		 sizeof(buf),
+ 		 "%-7s - %s%s%s",
+ 		 evdev_device_get_sysname(device),
+-		 (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ?  device->devname : "",
++		 (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ?  device->log_prefix_name : "",
+ 		 (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ?  ": " : "",
+ 		 format);
+ 
+@@ -824,7 +826,7 @@ evdev_log_msg_ratelimit(struct evdev_device *device,
+ 		 sizeof(buf),
+ 		 "%-7s - %s%s%s",
+ 		 evdev_device_get_sysname(device),
+-		 (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ?  device->devname : "",
++		 (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ?  device->log_prefix_name : "",
+ 		 (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ?  ": " : "",
+ 		 format);
+ 
+diff --git a/src/util-strings.h b/src/util-strings.h
+index 2a15fab3..d5a84146 100644
+--- a/src/util-strings.h
++++ b/src/util-strings.h
+@@ -42,6 +42,7 @@
+ #ifdef HAVE_XLOCALE_H
+ #include <xlocale.h>
+ #endif
++#include "util-macros.h"
+ 
+ #define streq(s1, s2) (strcmp((s1), (s2)) == 0)
+ #define strneq(s1, s2, n) (strncmp((s1), (s2), (n)) == 0)
+@@ -312,3 +313,31 @@
+ 	free(result);
+ 	return -1;
+ }
++
++/**
++ * Return a copy of str with all % converted to %% to make the string
++ * acceptable as printf format.
++ */
++static inline char *
++str_sanitize(const char *str)
++{
++	if (!str)
++		return NULL;
++
++	if (!strchr(str, '%'))
++		return strdup(str);
++
++	size_t slen = min(strlen(str), 512);
++	char *sanitized = zalloc(2 * slen + 1);
++	const char *src = str;
++	char *dst = sanitized;
++
++	for (size_t i = 0; i < slen; i++) {
++		if (*src == '%')
++			*dst++ = '%';
++		*dst++ = *src++;
++	}
++	*dst = '\0';
++
++	return sanitized;
++}
+diff --git a/test/litest-device-format-string.c b/test/litest-device-format-string.c
+new file mode 100644
+index 00000000..aed15db4
+--- /dev/null
++++ b/test/litest-device-format-string.c
+@@ -0,0 +1,56 @@
++
++/*
++ * Copyright © 2013 Red Hat, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ */
++
++#include "config.h"
++
++#include "litest.h"
++#include "litest-int.h"
++
++static struct input_id input_id = {
++	.bustype = 0x3,
++	.vendor = 0x0123,
++	.product = 0x0456,
++};
++
++static int events[] = {
++	EV_KEY, BTN_LEFT,
++	EV_KEY, BTN_RIGHT,
++	EV_KEY, BTN_MIDDLE,
++	EV_REL, REL_X,
++	EV_REL, REL_Y,
++	EV_REL, REL_WHEEL,
++	EV_REL, REL_WHEEL_HI_RES,
++	-1 , -1,
++};
++
++TEST_DEVICE("mouse-format-string",
++	.type = LITEST_MOUSE_FORMAT_STRING,
++	.features = LITEST_RELATIVE | LITEST_BUTTON | LITEST_WHEEL,
++	.interface = NULL,
++
++	.name = "Evil %s %d %x Mouse %p %",
++	.id = &input_id,
++	.absinfo = NULL,
++	.events = events,
++)
+diff --git a/test/litest.h b/test/litest.h
+index 4982e516..1b1daa90 100644
+--- a/test/litest.h
++++ b/test/litest.h
+@@ -303,6 +303,7 @@
+ 	LITEST_ALPS_3FG,
+ 	LITEST_ELAN_TABLET,
+ 	LITEST_ABSINFO_OVERRIDE,
++        LITEST_MOUSE_FORMAT_STRING,
+ };
+ 
+ #define LITEST_DEVICELESS	-2
+diff --git a/test/test-utils.c b/test/test-utils.c
+index 989adecd..e80754be 100644
+--- a/test/test-utils.c
++++ b/test/test-utils.c
+@@ -1267,6 +1267,31 @@ START_TEST(strstartswith_test)
+ }
+ END_TEST
+ 
++START_TEST(strsanitize_test)
++{
++	struct strsanitize_test {
++		const char *string;
++		const char *expected;
++	} tests[] = {
++		{ "foobar", "foobar" },
++		{ "", "" },
++		{ "%", "%%" },
++		{ "%%%%", "%%%%%%%%" },
++		{ "x %s", "x %%s" },
++		{ "x %", "x %%" },
++		{ "%sx", "%%sx" },
++		{ "%s%s", "%%s%%s" },
++		{ NULL, NULL },
++	};
++
++	for (struct strsanitize_test *t = tests; t->string; t++) {
++		char *sanitized = str_sanitize(t->string);
++		ck_assert_str_eq(sanitized, t->expected);
++		free(sanitized);
++	}
++}
++END_TEST
++
+ START_TEST(list_test_insert)
+ {
+ 	struct list_test {
+@@ -1138,6 +1138,7 @@
+ 	tcase_add_test(tc, strsplit_test);
+ 	tcase_add_test(tc, kvsplit_double_test);
+ 	tcase_add_test(tc, strjoin_test);
++	tcase_add_test(tc, strsanitize_test);
+ 	tcase_add_test(tc, time_conversion);
+ 
+ 	tcase_add_test(tc, list_test_insert);
+
+-- 
+GitLab
+
diff --git a/meta/recipes-graphics/wayland/libinput_1.15.2.bb b/meta/recipes-graphics/wayland/libinput_1.15.2.bb
index 810532774e..d7927d132a 100644
--- a/meta/recipes-graphics/wayland/libinput_1.15.2.bb
+++ b/meta/recipes-graphics/wayland/libinput_1.15.2.bb
@@ -14,6 +14,7 @@  DEPENDS = "libevdev udev mtdev"
 
 SRC_URI = "http://www.freedesktop.org/software/${BPN}/${BP}.tar.xz \
            file://determinism.patch \
+           file://CVE-2022-1215.patch \
            "
 SRC_URI[md5sum] = "eb6bd2907ad33d53954d70dfb881a643"
 SRC_URI[sha256sum] = "971c3fbfb624f95c911adeb2803c372e4e3647d1b98f278f660051f834597747"