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.
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)
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;
}
}