From: Greg Kroah-Hartman Date: Thu, 9 Apr 2026 11:06:43 +0000 (+0200) Subject: BUG/MINOR: sample: fix info leak in regsub when exp_replace fails X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e6c3660327f11787dddbc43c4efff4226ce88a54;p=thirdparty%2Fhaproxy.git BUG/MINOR: sample: fix info leak in regsub when exp_replace fails 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. This patch must be backported to all stable versions. --- diff --git a/src/sample.c b/src/sample.c index 22172a33f..d741716f8 100644 --- a/src/sample.c +++ b/src/sample.c @@ -3298,7 +3298,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)) {