Le 09/04/2026 à 1:06 PM, Greg Kroah-Hartman a écrit :
exp_replace() returns int and returns -1 when the back-reference expansion overflows the output buffer (regex.c:51). output->data is size_t, so -1 becomes SIZE_MAX. There was no error check.The subsequent comparisons interpret SIZE_MAX as a huge length: "output->data > b_room(trash)" tries to grow trash, then "max > output->data" is false so max stays at trash->size, and memcpy(trash, output->area, trash->size) copies the full chunk. output->area is a pool_alloc()'d chunk that is NOT zeroed; the bytes after the partial exp_replace output are stale data from a prior pool user (request headers, response bodies from the same worker thread). Trigger with a backreference whose expansion exceeds bufsize: http-request set-header X %[req.hdr(In),regsub('(.+)','\1\1')] and a request with In: of ~9000 bytes. The X header sent to the backend then contains ~9KB of stale heap data. With tune.bufsize.large set, get_larger_trash_chunk() upgrades trash and the memcpy reads up to ~50KB past the (smaller) output->area allocation. http_ana.c:2728 and http_act.c:551 already check exp_replace() for -1; this call site was missed when backreferences were added. --- src/sample.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sample.c b/src/sample.c index 42f211ad4af6..28a039584f9c 100644 --- a/src/sample.c +++ b/src/sample.c @@ -3300,7 +3300,12 @@ static int sample_conv_regsub(const struct arg *arg_p, struct sample *smp, void if (!output) break;- output->data = exp_replace(output->area, output->size, start, arg_p[1].data.str.area, pmatch);+ max = exp_replace(output->area, output->size, start, arg_p[1].data.str.area, pmatch); + if ((int)max < 0) { + free_trash_chunk(output); + break; + } + output->data = max;/* If too many data to copy try to get a larger chunk */if (output->data > b_room(trash)) {
Mergedn, thanks ! -- Christopher Faulet

