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
<check->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.
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.