From: Christopher Faulet Date: Mon, 27 Jul 2026 08:00:18 +0000 (+0200) Subject: BUG/MEDIUM: http-fetch: don't parse a non-HTTP check buffer as an HTX message X-Git-Tag: v3.5-dev4~117 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7be8f7a45a6e2da619ce8418a393e7651a433769;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: http-fetch: don't parse a non-HTTP check buffer as an HTX message In the health-check context, smp_prefetch_htx() unconditionally treats bi> as an HTX message: if (!s || !chn) { if (check) { htx = htxbuf(&check->bi); This is only true for an HTTP check, where the h1 mux fills the buffer with HTX blocks. For any other check ruleset (plain "tcp-check", or the default TCP connect check), the buffer holds the raw bytes received from the server. All the response-side HTTP sample fetches (res.body, res.hdr, res.hdrs, res.ver, status, res.cook...) are declared with SMP_SRC_HRSHV/HRSHP/HRSBO and the validity table in sample.c makes them usable at the SMP_CKP_BE_CHK_RUL checkpoint, so referencing one of them from a "tcp-check" rule (typically in an "on-error" log-format string, or in a "status-code" expression) is accepted at boot without any warning. When the check then runs, the first bytes of the server's answer are used as "struct htx" fields: ->size, ->head, ->tail and ->first are entirely provided by the peer. htx_get_first_blk() computes "htx->blocks + htx->size - (first + 1) * sizeof(struct htx_blk)" and the resulting block is dereferenced, which is a wild read that crashes the worker, and which may otherwise return arbitrary process memory as the fetched value. This can be reproduced with a backend using: option tcp-check tcp-check connect tcp-check expect string ZZZZ on-error "body=%[res.body]" and a server answering with 24 bytes crafted as a "struct htx" header with a large ->size (e.g. 0x40000000), ->head = 0, ->tail = 1 and ->first = 0, followed by any padding: the worker segfaults at the first check. Let's simply refuse to look at the buffer when the check is not relying on HTX. HTTP checks are unaffected, the fetches now simply return no sample on other checks. Note that this requires a hostile server, which is a trusted component for a reverse proxy, so this is not a security issue, but the parser must not be fed a buffer whose format it cannot assume. This should be backported to all supported versions. --- diff --git a/src/http_fetch.c b/src/http_fetch.c index de0688278..3f3cd09ba 100644 --- a/src/http_fetch.c +++ b/src/http_fetch.c @@ -207,6 +207,12 @@ struct htx *smp_prefetch_htx(struct sample *smp, struct channel *chn, struct che BUG_ON(check && (s || chn)); if (!s || !chn) { if (check) { + /* The check input buffer only contains an HTX message for + * an HTTP check. + */ + if (!IS_HTX_SC(check->sc)) + return NULL; + htx = htxbuf(&check->bi); /* Analyse not yet started */