]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: net_helper: fix a remaining possibly infinite loop in converters
authorWilly Tarreau <w@1wt.eu>
Thu, 21 May 2026 13:00:12 +0000 (15:00 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 21 May 2026 13:05:39 +0000 (15:05 +0200)
The various tcp_option_* converters rely on tcp_fullhdr_find_opt() to
find the option. However, the same bug as fixed in commit dbf471f99a
("BUG/MAJOR: net_helper: ip.fp infinite loop on malformed tcp options")
was also present there, by which an option of length 0 could be looped
over indefinitely. In practice this does not happen since such options
are not valid, but if passed encoded in an HTTP header for example, it
could possibly be passed.

While fixing it, let's check for length >1 in all 3 locations insteead
of only non-zero, since there's no point processing a malformed option
that wouldn't even be properly skipped.

This fix doesn't need to be backported, unless the ip.fp series is.

Thanks to @Vincent55 for reporting this issue.

src/net_helper.c

index 84e6b86d86f602fcf0b8d705e281dd13c3466598..85990a289afe12b3c0adfc3ab90d3c98dc2cba1e 100644 (file)
@@ -447,8 +447,8 @@ static size_t tcp_fullhdr_find_opt(const struct sample *smp, uint8_t opt)
                /* kind1 = NOP and is a single byte, others have a length field */
                if (smp->data.u.str.area[next] == 1)
                        next++;
-               else if (next + 1 < len)
-                       next += smp->data.u.str.area[next + 1];
+               else if (next + 1 < len && smp->data.u.str.area[next + 1] > 1)
+                       next += (uchar)smp->data.u.str.area[next + 1];
                else
                        break;
                if (smp->data.u.str.area[curr] == opt && next <= len)
@@ -605,7 +605,7 @@ static int sample_conv_tcp_options_list(const struct arg *arg_p, struct sample *
                /* kind1 = NOP and is a single byte, others have a length field */
                if (smp->data.u.str.area[ofs] == 1)
                        ofs++;
-               else if (ofs + 1 < len && smp->data.u.str.area[ofs + 1])
+               else if (ofs + 1 < len && smp->data.u.str.area[ofs + 1] > 1)
                        ofs += (uchar)smp->data.u.str.area[ofs + 1];
                else
                        break;
@@ -780,7 +780,7 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
                /* kind1 = NOP and is a single byte, others have a length field */
                if (smp->data.u.str.area[ofs] == 1)
                        next = ofs + 1;
-               else if ((ofs + 1 < tcplen) && smp->data.u.str.area[ofs + 1]) /* optlen 0 will cause an infinite loop */
+               else if ((ofs + 1 < tcplen) && smp->data.u.str.area[ofs + 1] > 1)
                        next = ofs + (uchar)smp->data.u.str.area[ofs + 1];
                else
                        break;