From: Willy Tarreau Date: Wed, 30 Sep 2026 09:58:32 +0000 (+0200) Subject: BUG/MEDIUM: tcpcheck: do not run a regex on an unallocated buffer X-Git-Tag: v3.5-dev8~79 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=84e4da5cdf68430c87f2dc42f31c470eefd8bb95;p=haproxy.git BUG/MEDIUM: tcpcheck: do not run a regex on an unallocated buffer 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. --- diff --git a/src/tcpcheck.c b/src/tcpcheck.c index e924155d9..1e245e0c8 100644 --- a/src/tcpcheck.c +++ b/src/tcpcheck.c @@ -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 +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: