diff options
| author | Pawan Badganchi <badganchipv@gmail.com> | 2022-05-09 11:54:38 +0530 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2022-05-14 20:26:34 +0100 |
| commit | 5daf9735c90906e537155dee74c022831995ca34 (patch) | |
| tree | 3dda88a0e6bab5665a857824490c8a6ebb3c7825 | |
| parent | de244668232fe76a9164f1b41fe54a34b7e67382 (diff) | |
| download | poky-5daf9735c90906e537155dee74c022831995ca34.tar.gz | |
libinput: Add fix for CVE-2022-1215
Add below patch to fix CVE-2022-1215
CVE-2022-1215.patch
Link: https://gitlab.freedesktop.org/libinput/libinput/-/commit/2a8b8fde90d63d48ce09ddae44142674bbca1c28
(From OE-Core rev: 3f899844b383bfd13f176d86181d9219b3dbe345)
Signed-off-by: Pawan Badganchi<badganchipv@gmail.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
| -rw-r--r-- | meta/recipes-graphics/wayland/libinput/CVE-2022-1215.patch | 360 | ||||
| -rw-r--r-- | meta/recipes-graphics/wayland/libinput_1.15.2.bb | 1 |
2 files changed, 361 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 @@ | |||
| 1 | From 2a8b8fde90d63d48ce09ddae44142674bbca1c28 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Peter Hutterer <peter.hutterer@who-t.net> | ||
| 3 | Date: Wed, 30 Mar 2022 09:25:22 +1000 | ||
| 4 | Subject: [PATCH] evdev: strip the device name of format directives | ||
| 5 | MIME-Version: 1.0 | ||
| 6 | Content-Type: text/plain; charset=UTF-8 | ||
| 7 | Content-Transfer-Encoding: 8bit | ||
| 8 | |||
| 9 | This fixes a format string vulnerabilty. | ||
| 10 | |||
| 11 | evdev_log_message() composes a format string consisting of a fixed | ||
| 12 | prefix (including the rendered device name) and the passed-in format | ||
| 13 | buffer. This format string is then passed with the arguments to the | ||
| 14 | actual log handler, which usually and eventually ends up being printf. | ||
| 15 | |||
| 16 | If the device name contains a printf-style format directive, these ended | ||
| 17 | up in the format string and thus get interpreted correctly, e.g. for a | ||
| 18 | device "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 | |||
| 22 | This can enable an attacker to execute malicious code with the | ||
| 23 | privileges of the process using libinput. | ||
| 24 | |||
| 25 | To exploit this, an attacker needs to be able to create a kernel device | ||
| 26 | with a malicious name, e.g. through /dev/uinput or a Bluetooth device. | ||
| 27 | |||
| 28 | To fix this, convert any potential format directives in the device name | ||
| 29 | by duplicating percentages. | ||
| 30 | |||
| 31 | Pre-rendering the device to avoid the issue altogether would be nicer | ||
| 32 | but the current log level hooks do not easily allow for this. The device | ||
| 33 | name is the only user-controlled part of the format string. | ||
| 34 | |||
| 35 | A second potential issue is the sysname of the device which is also | ||
| 36 | sanitized. | ||
| 37 | |||
| 38 | This issue was found by Albin Eldstål-Ahrens and Benjamin Svensson from | ||
| 39 | Assured AB, and independently by Lukas Lamster. | ||
| 40 | |||
| 41 | Fixes #752 | ||
| 42 | |||
| 43 | Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> | ||
| 44 | (cherry picked from commit a423d7d3269dc32a87384f79e29bb5ac021c83d1) | ||
| 45 | |||
| 46 | CVE: CVE-2022-1215 | ||
| 47 | Upstream Status: Backport [https://gitlab.freedesktop.org/libinput/libinput/-/commit/2a8b8fde90d63d48ce09ddae44142674bbca1c28] | ||
| 48 | Signed-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 | |||
| 61 | diff --git a/meson.build b/meson.build | ||
| 62 | index 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', | ||
| 73 | diff --git a/src/evdev.c b/src/evdev.c | ||
| 74 | index 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); | ||
| 164 | diff --git a/src/evdev.h b/src/evdev.h | ||
| 165 | index 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 | |||
| 195 | diff --git a/src/util-strings.h b/src/util-strings.h | ||
| 196 | index 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 | +} | ||
| 239 | diff --git a/test/litest-device-format-string.c b/test/litest-device-format-string.c | ||
| 240 | new file mode 100644 | ||
| 241 | index 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 | +) | ||
| 301 | diff --git a/test/litest.h b/test/litest.h | ||
| 302 | index 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 | ||
| 313 | diff --git a/test/test-utils.c b/test/test-utils.c | ||
| 314 | index 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 | -- | ||
| 359 | GitLab | ||
| 360 | |||
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" | |||
| 14 | 14 | ||
| 15 | SRC_URI = "http://www.freedesktop.org/software/${BPN}/${BP}.tar.xz \ | 15 | SRC_URI = "http://www.freedesktop.org/software/${BPN}/${BP}.tar.xz \ |
| 16 | file://determinism.patch \ | 16 | file://determinism.patch \ |
| 17 | file://CVE-2022-1215.patch \ | ||
| 17 | " | 18 | " |
| 18 | SRC_URI[md5sum] = "eb6bd2907ad33d53954d70dfb881a643" | 19 | SRC_URI[md5sum] = "eb6bd2907ad33d53954d70dfb881a643" |
| 19 | SRC_URI[sha256sum] = "971c3fbfb624f95c911adeb2803c372e4e3647d1b98f278f660051f834597747" | 20 | SRC_URI[sha256sum] = "971c3fbfb624f95c911adeb2803c372e4e3647d1b98f278f660051f834597747" |
