]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: connection: check the IP header length in NetScaler CIP
authorMartin Mirchev <mmirchev@comp.nus.edu.sg>
Tue, 27 Oct 2026 06:17:35 +0000 (14:17 +0800)
committerWilly Tarreau <w@1wt.eu>
Wed, 28 Oct 2026 10:38:26 +0000 (11:38 +0100)
conn_recv_netscaler_cip() takes the TCP ports at ip_hl * 4 bytes after the
start of the IPv4 header without checking ip_hl nor that the announced
header length covers them:

  - with ip_hl < 5 the ports are taken from the IPv4 header itself (e.g.
    ip_hl=0 gives source port 16384 from the version/IHL byte);
  - with a header length shorter than ip_hl * 4 + 4 (e.g. ip_hl=15 and a
    40-byte header) they are taken from the payload or from bytes past the
    received data, which are leftovers of the previous use of the trash
    buffer, possibly from another connection.

The same applies to IPv6 with a header length shorter than 44 bytes. The
reads stay inside the trash buffer, so this is not a memory safety issue,
but the session addresses end up with wrong ports. Let's reject such
headers with CO_ER_CIP_BAD_PROTO.

This should be backported to all stable versions.

src/connection.c

index 52fe22038e0f58b10ee8721c17afc6964a6f0cc3..051efc22a1b6369590537d922a7298ae3e377f53 100644 (file)
@@ -1784,6 +1784,14 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag)
                        conn->err_code = CO_ER_CIP_BAD_PROTO;
                        goto fail;
                }
+               else if (hdr_ip4->ip_hl < 5 ||
+                        hdr_len < hdr_ip4->ip_hl * 4 + sizeof(struct my_tcphdr)) {
+                       /* The IPv4 header length is invalid or the announced
+                        * header is too short to contain the TCP ports.
+                        */
+                       conn->err_code = CO_ER_CIP_BAD_PROTO;
+                       goto fail;
+               }
 
                hdr_tcp = (struct my_tcphdr *)(line + (hdr_ip4->ip_hl * 4));
 
@@ -1815,6 +1823,11 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag)
                        conn->err_code = CO_ER_CIP_BAD_PROTO;
                        goto fail;
                }
+               else if (hdr_len < sizeof(struct ip6_hdr) + sizeof(struct my_tcphdr)) {
+                       /* The announced header is too short to contain the TCP ports */
+                       conn->err_code = CO_ER_CIP_BAD_PROTO;
+                       goto fail;
+               }
 
                hdr_tcp = (struct my_tcphdr *)(line + sizeof(struct ip6_hdr));