From: Frederic Lecaille Date: Fri, 11 Sep 2026 09:50:50 +0000 (+0200) Subject: BUG/MINOR: pattern: do not match a string with an embedded \0 on its prefix X-Git-Tag: v3.5-dev7~27 X-Git-Url: https://git.kaiwu.me/$%7BGITURL%7D$%7Bcid%7D?a=commitdiff_plain;h=442f583f4fd2934ecc8f03c673d72a448073baaf;p=haproxy.git BUG/MINOR: pattern: do not match a string with an embedded \0 on its prefix pat_match_str() looks the sample up in the pattern tree with ebst_lookup(), which reads it as a C string and stops at the first \0. A sample "/public\0/admin" with = 14 was thus matched as "/public" by the default case-sensitive "-m str" exact match, while the case-insensitive match, which uses the list, compares the length and rejected it. Such samples are produced by converters that decode client data, e.g. url_dec ("%00") or json_query ("\u0000"), so an allow-list written as "http-request deny unless { path,url_dec -m str /public }" could be bypassed with "/public%00/admin". Maps (map, map_str) use the same matcher and were affected too. Patterns are loaded as C strings and never contain a \0, so such a sample cannot be an exact match. Check it once at the top of pat_match_str() and return no match. Note that a deny-list such as "-m str /admin" used to reject "/admin%00zz" by accident and now lets it through, since it is not an exact match. The has_ctl() converter can be used to reject any decoded \0. This is the same issue as the one fixed for the ssl_*_dn() fetches in commit 449133cba ("BUG/MINOR: ssl: reject an embedded \0 in the ssl_*_dn(entry) fetches"), fixed here in the matcher so that all producers are covered. This must be backported to all stable branches. Reported-by: Mike Read (@Michael-JRead) --- diff --git a/src/pattern.c b/src/pattern.c index f4ed2791d..656ffeade 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -499,6 +499,13 @@ struct pattern *pat_match_str(struct sample *smp, struct pattern_expr *expr, int struct pattern *ret = NULL; struct lru64 *lru = NULL; + /* Patterns never contain a NUL byte, so a sample with an embedded + * NUL cannot be an exact match. Without this check, the tree lookup + * would stop at the NUL and match on the prefix only. + */ + if (memchr(smp->data.u.str.area, 0, smp->data.u.str.data)) + return NULL; + /* Lookup a string in the expression's pattern tree. */ if (!eb_is_empty(&expr->pattern_tree)) { if (!pat_match_ensure_str(smp))