From 5da93f35ea6b55d639d276a78af4432a2ad825bf Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Mon, 17 Feb 2025 15:54:49 +0100 Subject: [PATCH] BUG/MEDIUM: filters: Handle filters registered on data with no payload callback An HTTP filter with no http_payload callback function may be registered on data. In that case, this filter is obviously not called when some data are received but it remains important to update its internal state to be sure to keep it synchronized on the stream, especially its offet value. Otherwise, the wrong calculation on the global offset may be performed in flt_http_end(), leading to an integer overflow when data are moved from input to output. This overflow triggers a BUG_ON() in c_adv(). The same is true for TCP filters with no tcp_payload callback function. This patch must be backport to all stable versions. (cherry picked from commit 34542d5ec29c89ec45b63107f9330f185f0bfd40) Signed-off-by: Willy Tarreau (cherry picked from commit 6633abae2a17f969754504f2aca37bbfa12f3ca4) [ad: remove reference to non existant members in 3.0] Signed-off-by: Amaury Denoyelle --- src/filters.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/filters.c b/src/filters.c index cc89469..6bccf6a 100644 --- a/src/filters.c +++ b/src/filters.c @@ -671,19 +671,17 @@ flt_http_payload(struct stream *s, struct http_msg *msg, unsigned int len) /* Call http_payload for filters only. Forward all data for * others and update the filter offset */ - if (!IS_DATA_FILTER(filter, msg->chn)) { + if (!IS_DATA_FILTER(filter, msg->chn) || !FLT_OPS(filter)->http_payload) { *flt_off += data - offset; continue; } - if (FLT_OPS(filter)->http_payload) { - DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s); - ret = FLT_OPS(filter)->http_payload(s, filter, msg, out + offset, data - offset); - if (ret < 0) - goto end; - data = ret + *flt_off - *strm_off; - *flt_off += ret; - } + DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s); + ret = FLT_OPS(filter)->http_payload(s, filter, msg, out + offset, data - offset); + if (ret < 0) + goto end; + data = ret + *flt_off - *strm_off; + *flt_off += ret; } /* If nothing was forwarded yet, we take care to hold the headers if @@ -957,20 +955,17 @@ flt_tcp_payload(struct stream *s, struct channel *chn, unsigned int len) /* Call tcp_payload for filters only. Forward all data for * others and update the filter offset */ - if (!IS_DATA_FILTER(filter, chn)) { + if (!IS_DATA_FILTER(filter, chn) || !FLT_OPS(filter)->tcp_payload) { *flt_off += data - offset; continue; } - if (FLT_OPS(filter)->tcp_payload) { - - DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_TCP_ANA|STRM_EV_FLT_ANA, s); - ret = FLT_OPS(filter)->tcp_payload(s, filter, chn, out + offset, data - offset); - if (ret < 0) - goto end; - data = ret + *flt_off - *strm_off; - *flt_off += ret; - } + DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_TCP_ANA|STRM_EV_FLT_ANA, s); + ret = FLT_OPS(filter)->tcp_payload(s, filter, chn, out + offset, data - offset); + if (ret < 0) + goto end; + data = ret + *flt_off - *strm_off; + *flt_off += ret; } /* Only forward data if the last filter decides to forward something */ -- 1.7.10.4