]> git.kaiwu.me - haproxy.git/commitdiff
REGTESTS: map: check map_regm inside an ACL over an iterating fetch
authorFrederic Lecaille <flecaille@haproxy.com>
Thu, 10 Sep 2026 13:37:17 +0000 (15:37 +0200)
committerFrederic Lecaille <flecaille@haproxy.com>
Thu, 10 Sep 2026 13:40:28 +0000 (15:40 +0200)
This test covers the bug fixed by this commit:

    7646c657a BUG/MEDIUM: map: do not overwrite the fetch context in pat_match_regm()

It uses map_regm in an ACL over req.hdr() with no occurrence. The first
value does not match, so the ACL runs a second iteration of the fetch,
which crashed the process before the fix. A request with two header
values checks that the fetch cursor survives the first iteration.

Thank you to @Michael-JRead for having produced the first version of this reg
test.

This must be backported with the fix above.

reg-tests/http-rules/map_regm_in_acl.map [new file with mode: 0644]
reg-tests/http-rules/map_regm_in_acl.vtc [new file with mode: 0644]

diff --git a/reg-tests/http-rules/map_regm_in_acl.map b/reg-tests/http-rules/map_regm_in_acl.map
new file mode 100644 (file)
index 0000000..48e543f
--- /dev/null
@@ -0,0 +1,2 @@
+^Mozilla/.*    browser
+^name-(.*)$    \1
diff --git a/reg-tests/http-rules/map_regm_in_acl.vtc b/reg-tests/http-rules/map_regm_in_acl.vtc
new file mode 100644 (file)
index 0000000..2284d07
--- /dev/null
@@ -0,0 +1,53 @@
+#commit 7646c657af79b304c6bff76564d310af5c7de67f
+#    BUG/MEDIUM: map: do not overwrite the fetch context in pat_match_regm()
+#
+#    pat_match_regm() stored the address of the thread-local <pmatch> array
+#    into <smp->ctx.a[0]>. This slot belongs to the sample fetch, which uses
+#    it to keep an iteration cursor. When map_regm is used inside an ACL over
+#    an iterating fetch (req.hdr() with no occurrence), the second iteration
+#    read the <pmatch> pointer as its cursor and crashed the process.
+
+varnishtest "map_regm inside an ACL over an iterating fetch"
+feature ignore_unknown_macro
+
+#REGTEST_TYPE=bug
+
+haproxy h1 -conf {
+  global
+    .if feature(THREAD)
+        thread-groups 1
+    .endif
+
+  defaults
+    mode http
+    timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
+    timeout client  "${HAPROXY_TEST_TIMEOUT-5s}"
+    timeout server  "${HAPROXY_TEST_TIMEOUT-5s}"
+
+  frontend fe
+    bind "fd@${fe}"
+    # req.hdr() with no occurrence iterates over all X-Agent values.
+    acl is_bot req.hdr(X-Agent),map_regm(${testdir}/map_regm_in_acl.map,unknown) -m str bot
+    http-request deny deny_status 403 if is_bot
+    http-request return status 200 content-type text/plain hdr x-mapped "%[req.hdr(X-Agent),map_regm(${testdir}/map_regm_in_acl.map,unknown)]" string "OK\n"
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+    # One value mapped to "browser": the ACL does not match and runs a
+    # second iteration of the fetch. This crashed before the fix.
+    txreq -hdr "X-Agent: Mozilla/5.0"
+    rxresp
+    expect resp.status == 200
+    expect resp.http.x-mapped == "browser"
+
+    # Back-reference: "name-bot" is mapped to "\1", that is "bot".
+    txreq -hdr "X-Agent: name-bot"
+    rxresp
+    expect resp.status == 403
+
+    # Two values: the first one does not match, the second one does.
+    # The 403 proves the fetch cursor survived the first iteration.
+    txreq -hdr "X-Agent: Mozilla/5.0" -hdr "X-Agent: name-bot"
+    rxresp
+    expect resp.status == 403
+} -run