]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: map: do not overwrite the fetch context in pat_match_regm()
authorFrederic Lecaille <flecaille@haproxy.com>
Thu, 10 Sep 2026 12:57:30 +0000 (14:57 +0200)
committerFrederic Lecaille <flecaille@haproxy.com>
Thu, 10 Sep 2026 13:28:32 +0000 (15:28 +0200)
pat_match_regm() stored the address of the thread-local <pmatch> array
into <smp->ctx.a[0]> so that sample_conv_map() could read the capture
offsets back for exp_replace(). But 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 (for example
req.hdr() with no occurrence), acl_exec_cond() re-runs the fetch to get
the next occurrence without clearing <smp->ctx>. On the second pass the
fetch reads back the <pmatch> pointer as its own cursor and dereferences
regex offsets as a pointer, which crashes the process. A single client
request is enough to trigger it.

Do not alias the slot: sample_conv_map() reads the thread-local <pmatch>
directly, since nothing runs another regex between pattern_exec_match()
filling it and this read. This is how http_replace_hdrs() and the
replace-path action already use <pmatch>.

Thank you to @Michael-JRead for having reported this issue.

This bug was introduced in 1.7 by commit 8feaa661b ("MINOR: map: Add
regex matching replacement").

This must be backported to all stable versions.

src/map.c
src/pattern.c

index bad7583627c676b464fab1888da3d294fff1e3b7..4a93797413cd5f1df9df428ecfc2fdc86a13fca8 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -236,7 +236,7 @@ static int sample_conv_map(const struct arg *arg_p, struct sample *smp, void *pr
                                len = exp_replace(str->area, str->size,
                                                  tmptrash->area,
                                                  pat->data->u.str.area,
-                                                 (regmatch_t *)smp->ctx.a[0]);
+                                                 pmatch);
                                free_trash_chunk(tmptrash);
 
                                if (len == -1)
index d62718210123b36a4e26fdfbeca5f0c322d227a8..f4ed2791d7ecc62a11f346b61e07b5034b0da406 100644 (file)
@@ -618,7 +618,6 @@ struct pattern *pat_match_regm(struct sample *smp, struct pattern_expr *expr, in
                if (regex_exec_match2(pattern->ptr.reg, smp->data.u.str.area, smp->data.u.str.data,
                                      MAX_MATCH, pmatch, 0)) {
                        ret = pattern;
-                       smp->ctx.a[0] = pmatch;
                        break;
                }
        }