]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: pattern: do not match a string with an embedded \0 on its prefix
authorFrederic Lecaille <flecaille@haproxy.com>
Fri, 11 Sep 2026 09:50:50 +0000 (11:50 +0200)
committerFrederic Lecaille <flecaille@haproxy.com>
Fri, 11 Sep 2026 09:58:51 +0000 (11:58 +0200)
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 <data> = 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)
src/pattern.c

index f4ed2791d7ecc62a11f346b61e07b5034b0da406..656ffeade2650210d6c340ff6cad1f2ee2024901 100644 (file)
@@ -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))