CVE-2026-50292: sanitize phys before printing it in libinput-device-group
Resolves: RHEL-182371
This commit is contained in:
parent
acba013430
commit
2f51356f3e
124
0001-util-sanitize-control-characters-in-str_sanitize.patch
Normal file
124
0001-util-sanitize-control-characters-in-str_sanitize.patch
Normal file
@ -0,0 +1,124 @@
|
||||
From fc2262e1c1847021239065e84f39f15492ef05cc Mon Sep 17 00:00:00 2001
|
||||
From: Peter Hutterer <peter.hutterer@who-t.net>
|
||||
Date: Mon, 1 Jun 2026 10:12:29 +1000
|
||||
Subject: [PATCH] util: sanitize control characters in str_sanitize()
|
||||
|
||||
str_sanitize() only escaped '%' characters for format string safety.
|
||||
Device names from uinput devices can contain arbitrary bytes including
|
||||
ANSI escape sequences (ESC, 0x1b) and other control characters. When
|
||||
these strings are included in log messages and printed to a terminal,
|
||||
the escape sequences are interpreted by the terminal emulator. This
|
||||
could allow an attacker to manipulate terminal output (change colors,
|
||||
set window title, clear screen) when an administrator views libinput
|
||||
logs.
|
||||
|
||||
Replace all control characters (0x00-0x1f and 0x7f) with '?' in
|
||||
addition to the existing '%' escaping. This prevents terminal escape
|
||||
sequence injection through device names in log output.
|
||||
|
||||
Assisted-by: Claude:claude-opus-4-6
|
||||
(cherry picked from commit 71a2c5cae2a80a1e3bb29e3f3a07ccc3f3de5acb)
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1489>
|
||||
---
|
||||
src/util-strings.h | 30 ++++++++++++++++++++++++------
|
||||
test/test-utils.c | 10 ++++++++++
|
||||
2 files changed, 34 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/util-strings.h b/src/util-strings.h
|
||||
index 94236c481706..3c6626331a91 100644
|
||||
--- a/src/util-strings.h
|
||||
+++ b/src/util-strings.h
|
||||
@@ -538,34 +538,52 @@ strstartswith(const char *str, const char *prefix)
|
||||
const char *
|
||||
safe_basename(const char *filename);
|
||||
|
||||
char *
|
||||
trunkname(const char *filename);
|
||||
|
||||
/**
|
||||
* Return a copy of str with all % converted to %% to make the string
|
||||
- * acceptable as printf format.
|
||||
+ * acceptable as printf format, and all non-NUL control characters
|
||||
+ * (bytes 0x01-0x1f, 0x7f) replaced with '?' to prevent terminal
|
||||
+ * escape sequence injection. NUL bytes are excluded implicitly
|
||||
+ * because the string is null-terminated.
|
||||
*/
|
||||
static inline char *
|
||||
str_sanitize(const char *str)
|
||||
{
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
- if (!strchr(str, '%'))
|
||||
- return strdup(str);
|
||||
-
|
||||
size_t slen = strlen(str);
|
||||
slen = min(slen, 512);
|
||||
+
|
||||
+ bool needs_sanitization = false;
|
||||
+ for (size_t i = 0; i < slen; i++) {
|
||||
+ unsigned char c = str[i];
|
||||
+ if (c == '%' || c < 0x20 || c == 0x7f) {
|
||||
+ needs_sanitization = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!needs_sanitization)
|
||||
+ return strdup(str);
|
||||
+
|
||||
char *sanitized = zalloc(2 * slen + 1);
|
||||
const char *src = str;
|
||||
char *dst = sanitized;
|
||||
|
||||
for (size_t i = 0; i < slen; i++) {
|
||||
- if (*src == '%')
|
||||
+ unsigned char c = *src++;
|
||||
+ if (c == '%') {
|
||||
*dst++ = '%';
|
||||
- *dst++ = *src++;
|
||||
+ *dst++ = '%';
|
||||
+ } else if (c < 0x20 || c == 0x7f) {
|
||||
+ *dst++ = '?';
|
||||
+ } else {
|
||||
+ *dst++ = c;
|
||||
+ }
|
||||
}
|
||||
*dst = '\0';
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
diff --git a/test/test-utils.c b/test/test-utils.c
|
||||
index 7c938b0af8ac..ee61ba13cc9c 100644
|
||||
--- a/test/test-utils.c
|
||||
+++ b/test/test-utils.c
|
||||
@@ -2081,16 +2081,26 @@ START_TEST(strsanitize_test)
|
||||
{ "foobar", "foobar" },
|
||||
{ "", "" },
|
||||
{ "%", "%%" },
|
||||
{ "%%%%", "%%%%%%%%" },
|
||||
{ "x %s", "x %%s" },
|
||||
{ "x %", "x %%" },
|
||||
{ "%sx", "%%sx" },
|
||||
{ "%s%s", "%%s%%s" },
|
||||
+ { "\t", "?" },
|
||||
+ { "\n", "?" },
|
||||
+ { "\r", "?" },
|
||||
+ { "\x1b[31m", "?[31m" },
|
||||
+ { "foo\tbar", "foo?bar" },
|
||||
+ { "foo\nbar", "foo?bar" },
|
||||
+ { "\x01\x1f\x7f", "???" },
|
||||
+ { "clean", "clean" },
|
||||
+ { "a\x1b[0mb", "a?[0mb" },
|
||||
+ { "%\n", "%%?" },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
for (struct strsanitize_test *t = tests; t->string; t++) {
|
||||
char *sanitized = str_sanitize(t->string);
|
||||
litest_assert_str_eq(sanitized, t->expected);
|
||||
free(sanitized);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
116
0002-libinput-device-group-sanitize-phys-before-printing-.patch
Normal file
116
0002-libinput-device-group-sanitize-phys-before-printing-.patch
Normal file
@ -0,0 +1,116 @@
|
||||
From b2bde9504d42a5976d76e1f27c640dc561fbd99b Mon Sep 17 00:00:00 2001
|
||||
From: Peter Hutterer <peter.hutterer@who-t.net>
|
||||
Date: Mon, 1 Jun 2026 10:48:24 +1000
|
||||
Subject: [PATCH] libinput-device-group: sanitize phys before printing it
|
||||
|
||||
A malicious uinput device could set the phys value (via UI_SET_PHYS)
|
||||
to contain a '\n'. When the value is printed as part of the device group
|
||||
the udev rules will interpret it as separate property.
|
||||
|
||||
Depending on the property this can cause local privilege escalation.
|
||||
|
||||
Closes #1296
|
||||
|
||||
Found-by: Csome
|
||||
(cherry picked from commit 76f0d8a7f57e2868882864b4611281f12f704b55)
|
||||
|
||||
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1489>
|
||||
---
|
||||
udev/libinput-device-group.c | 13 +++++++------
|
||||
1 file changed, 7 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/udev/libinput-device-group.c b/udev/libinput-device-group.c
|
||||
index cdb38c0beb98..f9188406d4de 100644
|
||||
--- a/udev/libinput-device-group.c
|
||||
+++ b/udev/libinput-device-group.c
|
||||
@@ -102,61 +102,63 @@ wacom_handle_ekr(struct udev_device *device,
|
||||
udev = udev_device_get_udev(device);
|
||||
e = udev_enumerate_new(udev);
|
||||
udev_enumerate_add_match_subsystem(e, "input");
|
||||
udev_enumerate_add_match_sysname(e, "input*");
|
||||
udev_enumerate_scan_devices(e);
|
||||
|
||||
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
|
||||
struct udev_device *d;
|
||||
- const char *path, *phys;
|
||||
+ _autofree_ char *phys = NULL;
|
||||
+ const char *path;
|
||||
const char *pidstr, *vidstr;
|
||||
int pid, vid, dist;
|
||||
|
||||
/* Find and use the closest Wacom device on the system,
|
||||
* relying on wacom_handle_paired() to fix our ID later
|
||||
* if needed.
|
||||
*/
|
||||
path = udev_list_entry_get_name(entry);
|
||||
d = udev_device_new_from_syspath(udev, path);
|
||||
if (!d)
|
||||
continue;
|
||||
|
||||
vidstr = udev_device_get_property_value(d, "ID_VENDOR_ID");
|
||||
pidstr = udev_device_get_property_value(d, "ID_MODEL_ID");
|
||||
- phys = udev_device_get_sysattr_value(d, "phys");
|
||||
+ phys = str_sanitize(udev_device_get_sysattr_value(d, "phys"));
|
||||
|
||||
if (vidstr && pidstr && phys && safe_atoi_base(vidstr, &vid, 16) &&
|
||||
safe_atoi_base(pidstr, &pid, 16) && vid == VENDOR_ID_WACOM &&
|
||||
pid != PRODUCT_ID_WACOM_EKR) {
|
||||
dist = find_tree_distance(device, d);
|
||||
if (dist > 0 && (dist < best_dist || best_dist < 0)) {
|
||||
*vendor_id = vid;
|
||||
*product_id = pid;
|
||||
best_dist = dist;
|
||||
|
||||
free(*phys_attr);
|
||||
- *phys_attr = safe_strdup(phys);
|
||||
+ *phys_attr = steal(&phys);
|
||||
}
|
||||
}
|
||||
|
||||
udev_device_unref(d);
|
||||
}
|
||||
|
||||
udev_enumerate_unref(e);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int rc = 1;
|
||||
struct udev *udev = NULL;
|
||||
struct udev_device *device = NULL;
|
||||
- const char *syspath, *phys = NULL;
|
||||
+ _autofree_ char *phys = NULL;
|
||||
+ const char *syspath = NULL;
|
||||
const char *product;
|
||||
int bustype, vendor_id, product_id, version;
|
||||
char group[1024];
|
||||
char *str;
|
||||
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
@@ -170,18 +172,17 @@ main(int argc, char **argv)
|
||||
if (!device)
|
||||
goto out;
|
||||
|
||||
/* Find the first parent with ATTRS{phys} set. For tablets that
|
||||
* value looks like usb-0000:00:14.0-1/input1. Drop the /input1
|
||||
* bit and use the remainder as device group identifier */
|
||||
while (device != NULL) {
|
||||
struct udev_device *parent;
|
||||
-
|
||||
- phys = udev_device_get_sysattr_value(device, "phys");
|
||||
+ phys = str_sanitize(udev_device_get_sysattr_value(device, "phys"));
|
||||
if (phys)
|
||||
break;
|
||||
|
||||
parent = udev_device_get_parent(device);
|
||||
udev_device_ref(parent);
|
||||
udev_device_unref(device);
|
||||
device = parent;
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
From a487280e095e376a40354e69c01593153d61f126 Mon Sep 17 00:00:00 2001
|
||||
From: Josiah Vehrs <jvehrs@amazon.com>
|
||||
Date: Wed, 10 Jun 2026 18:17:53 -0700
|
||||
Subject: [PATCH] util: fix possible return of unsanitized input in
|
||||
str_sanitize
|
||||
|
||||
Fixes: 71a2c5cae2a8 ("util: sanitize control characters in str_sanitize()")
|
||||
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1493>
|
||||
---
|
||||
src/util-strings.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/util-strings.h b/src/util-strings.h
|
||||
index 6186c16784d5..a6ff440bd24b 100644
|
||||
--- a/src/util-strings.h
|
||||
+++ b/src/util-strings.h
|
||||
@@ -567,17 +567,17 @@ str_sanitize(const char *str)
|
||||
for (size_t i = 0; i < slen; i++) {
|
||||
unsigned char c = str[i];
|
||||
if (c == '%' || c < 0x20 || c == 0x7f) {
|
||||
needs_sanitization = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!needs_sanitization)
|
||||
- return strdup(str);
|
||||
+ return strndup(str, slen);
|
||||
|
||||
char *sanitized = zalloc(2 * slen + 1);
|
||||
const char *src = str;
|
||||
char *dst = sanitized;
|
||||
|
||||
for (size_t i = 0; i < slen; i++) {
|
||||
unsigned char c = *src++;
|
||||
if (c == '%') {
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
Name: libinput
|
||||
Version: 1.30.1
|
||||
Release: 1%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist}
|
||||
Release: 2%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist}
|
||||
Summary: Input device library
|
||||
|
||||
# SPDX
|
||||
@ -20,6 +20,10 @@ Source0: https://gitlab.freedesktop.org/libinput/libinput/-/archive/%{ver
|
||||
%endif
|
||||
|
||||
Patch0002: 0001-RHEL-map-dials-to-rings-on-the-Intuos-Pro-3rd-Gen-de.patch
|
||||
# CVE-2026-50292 (RHEL-182371)
|
||||
Patch0003: 0001-util-sanitize-control-characters-in-str_sanitize.patch
|
||||
Patch0004: 0002-libinput-device-group-sanitize-phys-before-printing-.patch
|
||||
Patch0005: 0003-util-fix-possible-return-of-unsanitized-input-in-str.patch
|
||||
|
||||
BuildRequires: git-core
|
||||
BuildRequires: gcc
|
||||
@ -162,6 +166,10 @@ intended to be run by users.
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Jun 12 2026 Peter Hutterer <peter.hutterer@redhat.com> - 1.30.1-2
|
||||
- CVE-2026-50292: sanitize phys before printing it in libinput-device-group
|
||||
Resolves: RHEL-182371
|
||||
|
||||
* Wed Dec 17 2025 Peter Hutterer <peter.hutterer@redhat.com> - 1.30.1-1
|
||||
- libinput 1.30.1
|
||||
Resolves: RHEL-136390
|
||||
|
||||
Loading…
Reference in New Issue
Block a user