From: Frederic Lecaille Date: Thu, 10 Sep 2026 12:57:30 +0000 (+0200) Subject: BUG/MEDIUM: map: do not overwrite the fetch context in pat_match_regm() X-Git-Tag: v3.5-dev7~46 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=7646c657af79b304c6bff76564d310af5c7de67f;p=haproxy.git BUG/MEDIUM: map: do not overwrite the fetch context in pat_match_regm() pat_match_regm() stored the address of the thread-local array into 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 ctx>. On the second pass the fetch reads back the 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 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 . 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. --- diff --git a/src/map.c b/src/map.c index bad758362..4a9379741 100644 --- 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) diff --git a/src/pattern.c b/src/pattern.c index d62718210..f4ed2791d 100644 --- a/src/pattern.c +++ b/src/pattern.c @@ -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; } }