mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-06-10 02:08:20 +02:00
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 Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1486>
This commit is contained in:
parent
af084f375c
commit
71a2c5cae2
2 changed files with 34 additions and 6 deletions
|
|
@ -545,7 +545,10 @@ 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)
|
||||
|
|
@ -553,19 +556,34 @@ 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';
|
||||
|
||||
|
|
|
|||
|
|
@ -2201,6 +2201,16 @@ START_TEST(strsanitize_test)
|
|||
{ "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 */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue