CVE-2026-50292: sanitize phys before printing it in libinput-device-group

Resolves: RHEL-182371
This commit is contained in:
Peter Hutterer 2026-06-12 08:59:12 +10:00
parent acba013430
commit 2f51356f3e
4 changed files with 287 additions and 1 deletions

View 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

View 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

View File

@ -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

View File

@ -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