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.
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));
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));