From: Christopher Faulet Date: Tue, 16 Jun 2026 06:07:45 +0000 (+0200) Subject: BUG/MEDIUM: http-act: Make a copy of the sample expr in (set/add)-headers-bin X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43932db8513611407c024c7268f6018bbe8bdaf2;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: http-act: Make a copy of the sample expr in (set/add)-headers-bin For set-headers-bin and add-header-bin actions, the new HTX headers to add or set are extracted from the result of a sample expression evaluation. This result must be copied because it is based a static trash chunk and internal functions manipulating HTX messages also use static chunks. So to not overwrite the sample expression, for instance because a defrag is performed, it must be copied into a dynamically allocated chunk. It is also important because the sample expression may be based on part of the HTX message itself. This patch must be backported to 3.4. --- diff --git a/src/http_act.c b/src/http_act.c index 9f6b1871e..7b6914909 100644 --- a/src/http_act.c +++ b/src/http_act.c @@ -1490,6 +1490,7 @@ static enum act_return http_action_set_headers_bin(struct act_rule *rule, struct struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn.http->req : &s->txn.http->rsp); struct htx *htx = htxbuf(&msg->chn->buf); struct sample *hdrs_bin; + struct buffer *copy = NULL; char *p, *end; enum act_return ret = ACT_RET_CONT; struct http_hdr_ctx ctx; @@ -1500,8 +1501,19 @@ static enum act_return http_action_set_headers_bin(struct act_rule *rule, struct if (!hdrs_bin) return ACT_RET_CONT; - p = b_orig(&hdrs_bin->data.u.str); - end = b_tail(&hdrs_bin->data.u.str); + /* The sample may point into the very HTX message we're about to modify + * (e.g. req.body) or into a rotating trash chunk that http_add_header() + * reuses internally; either way a defrag/realloc would leave our p/end/ + * n/v pointers dangling. Work on a private copy to stay safe. + */ + copy = alloc_trash_chunk(); + if (!copy || b_data(&hdrs_bin->data.u.str) > b_size(copy)) + goto fail_rewrite; + memcpy(b_orig(copy), b_orig(&hdrs_bin->data.u.str), b_data(&hdrs_bin->data.u.str)); + b_set_data(copy, b_data(&hdrs_bin->data.u.str)); + + p = b_orig(copy); + end = b_tail(copy); while (p < end) { if (decode_varint(&p, end, &sz) == -1) goto fail_rewrite; @@ -1546,6 +1558,7 @@ static enum act_return http_action_set_headers_bin(struct act_rule *rule, struct ret = ACT_RET_ERR; leave: + free_trash_chunk(copy); return ret; fail_rewrite: