]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: tcpcheck: do not run a regex on an unallocated buffer
authorWilly Tarreau <w@1wt.eu>
Wed, 30 Sep 2026 09:58:32 +0000 (11:58 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 30 Sep 2026 14:11:24 +0000 (16:11 +0200)
A "tcp-check expect rstring" rule can be evaluated while the input
buffer of the check is not allocated, in which case b_head() returns
NULL, which is not compatible with regex_exec2() that wants a writable
buffer to write a trailing zero, and dies.

By luck, the surrounding cases work by chance because my_memmem()
returns NULL on NULL, and the binary regex works on a trash buffer
(hence always allocated). When using PCRE/PCRE2 it doesn't crash
either because both return an error for a NULL subject, so only a
pure build with libc regex fails.

It's not easy to reproduce, it requires to run many (~2*nproc) parallel
instances of reg-tests/checks/tcp-check_min-recv.vtc several times
(~200) to see it, but it does happend.

The rule now reports no match when no buffer is allocated, which is
what the string and binary cases already do in the same situation

This can be backported to stable versions.

src/tcpcheck.c

index e924155d9c48294bfafbff04c627f3e01da9a1c1..1e245e0c80f3603388384467db4c11c864a4e8e5 100644 (file)
@@ -2352,7 +2352,14 @@ enum tcpcheck_eval_ret tcpcheck_eval_expect(struct check *check, struct tcpcheck
                match = my_memmem(b_head(&check->bi), b_data(&check->bi), istptr(expect->data), istlen(expect->data)) != NULL;
                break;
        case TCPCHK_EXPECT_STRING_REGEX:
-               match = regex_exec2(expect->regex, b_head(&check->bi), MIN(b_data(&check->bi), b_size(&check->bi)-1));
+               /* The input buffer may not be allocated at all, in which case
+                * b_head() is NULL while regex_exec2() requires a writable
+                * area of at least <length>+1 bytes. There is nothing to match
+                * against in that case.
+                */
+               match = (b_size(&check->bi) &&
+                        regex_exec2(expect->regex, b_head(&check->bi),
+                                    MIN(b_data(&check->bi), b_size(&check->bi)-1)));
                break;
 
        case TCPCHK_EXPECT_BINARY_REGEX: