]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
string-util: Prevent infinite loop pegging CPU on malformed ESC input
authorChris Down <chris@chrisdown.name>
Sat, 14 Feb 2026 16:40:14 +0000 (00:40 +0800)
committerMike Yuan <me@yhndnzj.com>
Sat, 14 Feb 2026 20:49:24 +0000 (21:49 +0100)
string_has_ansi_sequence() currently does this to look for ESC input:

    t = memchr(s, 0x1B, ...)

So each iteration re-searches from the original start pointer. But if we
find an ESC byte that does *not* start a valid ANSI sequence (like "\x1B
", or an ESC at the end of the string), then ansi_sequence_length()
returns 0, and if that ESC is still in the search window, we will just
spin consuming 100% CPU forever.

Fix this by always advancing past rejected ESC bytes.

src/basic/string-util.c
src/test/test-ellipsize.c

index ecd0277577d07eb25d041925624404ea93ced1bf..055e571afb680d59c7b072f2fe8b70af9af08ffa 100644 (file)
@@ -267,9 +267,11 @@ static size_t ansi_sequence_length(const char *s, size_t len) {
 static bool string_has_ansi_sequence(const char *s, size_t len) {
         const char *t = s;
 
-        while ((t = memchr(s, 0x1B, len - (t - s))))
+        while ((t = memchr(t, 0x1B, len - (t - s)))) {
                 if (ansi_sequence_length(t, len - (t - s)) > 0)
                         return true;
+                t++;
+        }
         return false;
 }
 
index 83978446e18de9b0b8b116d0532852020417af08..2efb123ac2b7318813036235fc6addaf89a94b1b 100644 (file)
@@ -156,4 +156,14 @@ TEST(ellipsize_ansi_cats) {
         ASSERT_STREQ(h, "🐱…" ANSI_NORMAL "🐱" ANSI_NORMAL);
 }
 
+TEST(ellipsize_esc_infinite_loop) {
+        /* Make sure we don't infinite loop on an ESC in the first half */
+        static const char s[] = { 'A', 'B', 0x1B, ' ', 'D', '\0' };
+        _cleanup_free_ char *t = NULL;
+
+        t = ellipsize_mem(s, 5, 5, 50);
+        assert_se(t);
+        assert_se(memcmp(t, s, 5) == 0);
+}
+
 DEFINE_TEST_MAIN(LOG_INFO);