summaryrefslogtreecommitdiffstats
path: root/meta/recipes-graphics/wayland/libinput/CVE-2022-1215.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-graphics/wayland/libinput/CVE-2022-1215.patch')
-rw-r--r--meta/recipes-graphics/wayland/libinput/CVE-2022-1215.patch360
1 files changed, 360 insertions, 0 deletions
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..313c0c5eb2
--- /dev/null
+++ b/meta/recipes-graphics/wayland/libinput/CVE-2022-1215.patch
@@ -0,0 +1,360 @@
1From 2a8b8fde90d63d48ce09ddae44142674bbca1c28 Mon Sep 17 00:00:00 2001
2From: Peter Hutterer <peter.hutterer@who-t.net>
3Date: Wed, 30 Mar 2022 09:25:22 +1000
4Subject: [PATCH] evdev: strip the device name of format directives
5MIME-Version: 1.0
6Content-Type: text/plain; charset=UTF-8
7Content-Transfer-Encoding: 8bit
8
9This fixes a format string vulnerabilty.
10
11evdev_log_message() composes a format string consisting of a fixed
12prefix (including the rendered device name) and the passed-in format
13buffer. This format string is then passed with the arguments to the
14actual log handler, which usually and eventually ends up being printf.
15
16If the device name contains a printf-style format directive, these ended
17up in the format string and thus get interpreted correctly, e.g. for a
18device "Foo%sBar" the log message vs printf invocation ends up being:
19 evdev_log_message(device, "some message %s", "some argument");
20 printf("event9 - Foo%sBar: some message %s", "some argument");
21
22This can enable an attacker to execute malicious code with the
23privileges of the process using libinput.
24
25To exploit this, an attacker needs to be able to create a kernel device
26with a malicious name, e.g. through /dev/uinput or a Bluetooth device.
27
28To fix this, convert any potential format directives in the device name
29by duplicating percentages.
30
31Pre-rendering the device to avoid the issue altogether would be nicer
32but the current log level hooks do not easily allow for this. The device
33name is the only user-controlled part of the format string.
34
35A second potential issue is the sysname of the device which is also
36sanitized.
37
38This issue was found by Albin Eldstål-Ahrens and Benjamin Svensson from
39Assured AB, and independently by Lukas Lamster.
40
41Fixes #752
42
43Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
44(cherry picked from commit a423d7d3269dc32a87384f79e29bb5ac021c83d1)
45
46CVE: CVE-2022-1215
47Upstream Status: Backport [https://gitlab.freedesktop.org/libinput/libinput/-/commit/2a8b8fde90d63d48ce09ddae44142674bbca1c28]
48Signed-off-by: Pawan Badganchi <Pawan.Badganchi@kpit.com>
49
50---
51 meson.build | 1 +
52 src/evdev.c | 31 +++++++++++------
53 src/evdev.h | 6 ++--
54 src/util-strings.h | 30 ++++++++++++++++
55 test/litest-device-format-string.c | 56 ++++++++++++++++++++++++++++++
56 test/litest.h | 1 +
57 test/test-utils.c | 26 ++++++++++++++
58 7 files changed, 139 insertions(+), 12 deletions(-)
59 create mode 100644 test/litest-device-format-string.c
60
61diff --git a/meson.build b/meson.build
62index 90f528e6..1f6159e7 100644
63--- a/meson.build
64+++ b/meson.build
65@@ -787,6 +787,7 @@
66 'test/litest-device-dell-canvas-totem-touch.c',
67 'test/litest-device-elantech-touchpad.c',
68 'test/litest-device-elan-tablet.c',
69+ 'test/litest-device-format-string.c',
70 'test/litest-device-generic-singletouch.c',
71 'test/litest-device-gpio-keys.c',
72 'test/litest-device-huion-pentablet.c',
73diff --git a/src/evdev.c b/src/evdev.c
74index 6d81f58f..d1c35c07 100644
75--- a/src/evdev.c
76+++ b/src/evdev.c
77@@ -2356,19 +2356,19 @@ evdev_device_create(struct libinput_seat *seat,
78 struct libinput *libinput = seat->libinput;
79 struct evdev_device *device = NULL;
80 int rc;
81- int fd;
82+ int fd = -1;
83 int unhandled_device = 0;
84 const char *devnode = udev_device_get_devnode(udev_device);
85- const char *sysname = udev_device_get_sysname(udev_device);
86+ char *sysname = str_sanitize(udev_device_get_sysname(udev_device));
87
88 if (!devnode) {
89 log_info(libinput, "%s: no device node associated\n", sysname);
90- return NULL;
91+ goto err;
92 }
93
94 if (udev_device_should_be_ignored(udev_device)) {
95 log_debug(libinput, "%s: device is ignored\n", sysname);
96- return NULL;
97+ goto err;
98 }
99
100 /* Use non-blocking mode so that we can loop on read on
101@@ -2382,13 +2382,15 @@ evdev_device_create(struct libinput_seat *seat,
102 sysname,
103 devnode,
104 strerror(-fd));
105- return NULL;
106+ goto err;
107 }
108
109 if (!evdev_device_have_same_syspath(udev_device, fd))
110 goto err;
111
112 device = zalloc(sizeof *device);
113+ device->sysname = sysname;
114+ sysname = NULL;
115
116 libinput_device_init(&device->base, seat);
117 libinput_seat_ref(seat);
118@@ -2411,6 +2413,9 @@ evdev_device_create(struct libinput_seat *seat,
119 device->dispatch = NULL;
120 device->fd = fd;
121 device->devname = libevdev_get_name(device->evdev);
122+ /* the log_prefix_name is used as part of a printf format string and
123+ * must not contain % directives, see evdev_log_msg */
124+ device->log_prefix_name = str_sanitize(device->devname);
125 device->scroll.threshold = 5.0; /* Default may be overridden */
126 device->scroll.direction_lock_threshold = 5.0; /* Default may be overridden */
127 device->scroll.direction = 0;
128@@ -2238,9 +2238,14 @@
129 return device;
130
131 err:
132- close_restricted(libinput, fd);
133- if (device)
134- evdev_device_destroy(device);
135+ if (fd >= 0) {
136+ close_restricted(libinput, fd);
137+ if (device) {
138+ unhandled_device = device->seat_caps == 0;
139+ evdev_device_destroy(device);
140+ }
141+ }
142+ free(sysname);
143
144 return unhandled_device ? EVDEV_UNHANDLED_DEVICE : NULL;
145 }
146@@ -2469,7 +2478,7 @@ evdev_device_get_output(struct evdev_device *device)
147 const char *
148 evdev_device_get_sysname(struct evdev_device *device)
149 {
150- return udev_device_get_sysname(device->udev_device);
151+ return device->sysname;
152 }
153
154 const char *
155@@ -3066,6 +3075,8 @@ evdev_device_destroy(struct evdev_device *device)
156 if (device->base.group)
157 libinput_device_group_unref(device->base.group);
158
159+ free(device->log_prefix_name);
160+ free(device->sysname);
161 free(device->output_name);
162 filter_destroy(device->pointer.filter);
163 libinput_timer_destroy(&device->scroll.timer);
164diff --git a/src/evdev.h b/src/evdev.h
165index c7d130f8..980c5943 100644
166--- a/src/evdev.h
167+++ b/src/evdev.h
168@@ -169,6 +169,8 @@ struct evdev_device {
169 struct udev_device *udev_device;
170 char *output_name;
171 const char *devname;
172+ char *log_prefix_name;
173+ char *sysname;
174 bool was_removed;
175 int fd;
176 enum evdev_device_seat_capability seat_caps;
177@@ -786,7 +788,7 @@ evdev_log_msg(struct evdev_device *device,
178 sizeof(buf),
179 "%-7s - %s%s%s",
180 evdev_device_get_sysname(device),
181- (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->devname : "",
182+ (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->log_prefix_name : "",
183 (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? ": " : "",
184 format);
185
186@@ -824,7 +826,7 @@ evdev_log_msg_ratelimit(struct evdev_device *device,
187 sizeof(buf),
188 "%-7s - %s%s%s",
189 evdev_device_get_sysname(device),
190- (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->devname : "",
191+ (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? device->log_prefix_name : "",
192 (priority > LIBINPUT_LOG_PRIORITY_DEBUG) ? ": " : "",
193 format);
194
195diff --git a/src/util-strings.h b/src/util-strings.h
196index 2a15fab3..d5a84146 100644
197--- a/src/util-strings.h
198+++ b/src/util-strings.h
199@@ -42,6 +42,7 @@
200 #ifdef HAVE_XLOCALE_H
201 #include <xlocale.h>
202 #endif
203+#include "util-macros.h"
204
205 #define streq(s1, s2) (strcmp((s1), (s2)) == 0)
206 #define strneq(s1, s2, n) (strncmp((s1), (s2), (n)) == 0)
207@@ -312,3 +313,31 @@
208 free(result);
209 return -1;
210 }
211+
212+/**
213+ * Return a copy of str with all % converted to %% to make the string
214+ * acceptable as printf format.
215+ */
216+static inline char *
217+str_sanitize(const char *str)
218+{
219+ if (!str)
220+ return NULL;
221+
222+ if (!strchr(str, '%'))
223+ return strdup(str);
224+
225+ size_t slen = min(strlen(str), 512);
226+ char *sanitized = zalloc(2 * slen + 1);
227+ const char *src = str;
228+ char *dst = sanitized;
229+
230+ for (size_t i = 0; i < slen; i++) {
231+ if (*src == '%')
232+ *dst++ = '%';
233+ *dst++ = *src++;
234+ }
235+ *dst = '\0';
236+
237+ return sanitized;
238+}
239diff --git a/test/litest-device-format-string.c b/test/litest-device-format-string.c
240new file mode 100644
241index 00000000..aed15db4
242--- /dev/null
243+++ b/test/litest-device-format-string.c
244@@ -0,0 +1,56 @@
245+
246+/*
247+ * Copyright © 2013 Red Hat, Inc.
248+ *
249+ * Permission is hereby granted, free of charge, to any person obtaining a
250+ * copy of this software and associated documentation files (the "Software"),
251+ * to deal in the Software without restriction, including without limitation
252+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
253+ * and/or sell copies of the Software, and to permit persons to whom the
254+ * Software is furnished to do so, subject to the following conditions:
255+ *
256+ * The above copyright notice and this permission notice (including the next
257+ * paragraph) shall be included in all copies or substantial portions of the
258+ * Software.
259+ *
260+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
261+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
262+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
263+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
264+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
265+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
266+ * DEALINGS IN THE SOFTWARE.
267+ */
268+
269+#include "config.h"
270+
271+#include "litest.h"
272+#include "litest-int.h"
273+
274+static struct input_id input_id = {
275+ .bustype = 0x3,
276+ .vendor = 0x0123,
277+ .product = 0x0456,
278+};
279+
280+static int events[] = {
281+ EV_KEY, BTN_LEFT,
282+ EV_KEY, BTN_RIGHT,
283+ EV_KEY, BTN_MIDDLE,
284+ EV_REL, REL_X,
285+ EV_REL, REL_Y,
286+ EV_REL, REL_WHEEL,
287+ EV_REL, REL_WHEEL_HI_RES,
288+ -1 , -1,
289+};
290+
291+TEST_DEVICE("mouse-format-string",
292+ .type = LITEST_MOUSE_FORMAT_STRING,
293+ .features = LITEST_RELATIVE | LITEST_BUTTON | LITEST_WHEEL,
294+ .interface = NULL,
295+
296+ .name = "Evil %s %d %x Mouse %p %",
297+ .id = &input_id,
298+ .absinfo = NULL,
299+ .events = events,
300+)
301diff --git a/test/litest.h b/test/litest.h
302index 4982e516..1b1daa90 100644
303--- a/test/litest.h
304+++ b/test/litest.h
305@@ -303,6 +303,7 @@
306 LITEST_ALPS_3FG,
307 LITEST_ELAN_TABLET,
308 LITEST_ABSINFO_OVERRIDE,
309+ LITEST_MOUSE_FORMAT_STRING,
310 };
311
312 #define LITEST_DEVICELESS -2
313diff --git a/test/test-utils.c b/test/test-utils.c
314index 989adecd..e80754be 100644
315--- a/test/test-utils.c
316+++ b/test/test-utils.c
317@@ -1267,6 +1267,31 @@ START_TEST(strstartswith_test)
318 }
319 END_TEST
320
321+START_TEST(strsanitize_test)
322+{
323+ struct strsanitize_test {
324+ const char *string;
325+ const char *expected;
326+ } tests[] = {
327+ { "foobar", "foobar" },
328+ { "", "" },
329+ { "%", "%%" },
330+ { "%%%%", "%%%%%%%%" },
331+ { "x %s", "x %%s" },
332+ { "x %", "x %%" },
333+ { "%sx", "%%sx" },
334+ { "%s%s", "%%s%%s" },
335+ { NULL, NULL },
336+ };
337+
338+ for (struct strsanitize_test *t = tests; t->string; t++) {
339+ char *sanitized = str_sanitize(t->string);
340+ ck_assert_str_eq(sanitized, t->expected);
341+ free(sanitized);
342+ }
343+}
344+END_TEST
345+
346 START_TEST(list_test_insert)
347 {
348 struct list_test {
349@@ -1138,6 +1138,7 @@
350 tcase_add_test(tc, strsplit_test);
351 tcase_add_test(tc, kvsplit_double_test);
352 tcase_add_test(tc, strjoin_test);
353+ tcase_add_test(tc, strsanitize_test);
354 tcase_add_test(tc, time_conversion);
355
356 tcase_add_test(tc, list_test_insert);
357
358--
359GitLab
360