]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: filters: Handle filters registered on data with no payload callback
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 17 Feb 2025 14:54:49 +0000 (15:54 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 17 Feb 2025 15:16:29 +0000 (16:16 +0100)
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.

src/filters.c

index 792d6f3eede450b2e7af114340bbc70309c9635d..3b0662b3c383f8a4b5e662a01f0667d36b88d6e8 100644 (file)
@@ -700,23 +700,21 @@ 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);
-                       filter->calls++;
-                       ret = FLT_OPS(filter)->http_payload(s, filter, msg, out + offset, data - offset);
-                       if (ret < 0) {
-                               s->last_entity.type = STRM_ENTITY_FILTER;
-                               s->last_entity.ptr = filter;
-                               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);
+               filter->calls++;
+               ret = FLT_OPS(filter)->http_payload(s, filter, msg, out + offset, data - offset);
+               if (ret < 0) {
+                       s->last_entity.type = STRM_ENTITY_FILTER;
+                       s->last_entity.ptr = filter;
+                       goto end;
                }
+               data = ret + *flt_off - *strm_off;
+               *flt_off += ret;
        }
 
        /* If nothing was forwarded yet, we take care to hold the headers if
@@ -998,24 +996,21 @@ 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);
-                       filter->calls++;
-                       ret = FLT_OPS(filter)->tcp_payload(s, filter, chn, out + offset, data - offset);
-                       if (ret < 0) {
-                               s->last_entity.type = STRM_ENTITY_FILTER;
-                               s->last_entity.ptr = filter;
-                               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);
+               filter->calls++;
+               ret = FLT_OPS(filter)->tcp_payload(s, filter, chn, out + offset, data - offset);
+               if (ret < 0) {
+                       s->last_entity.type = STRM_ENTITY_FILTER;
+                       s->last_entity.ptr = filter;
+                       goto end;
                }
+               data = ret + *flt_off - *strm_off;
+               *flt_off += ret;
        }
 
        /* Only forward data if the last filter decides to forward something */