net: compare received length to sizeof(ip_hdr), not sizeof(ip_udp_hdr)
authorRasmus Villemoes <rasmus.villemoes@prevas.dk>
Fri, 14 Oct 2022 17:43:38 +0000 (19:43 +0200)
committerTom Rini <trini@konsulko.com>
Mon, 28 Nov 2022 15:25:18 +0000 (10:25 -0500)
commitad359d89ec5424fc18a289fa5fcc1a4947930dba
tree293c0fe662fb4e217d270421b85bbaceae83bf9c
parentb0fcc48cb37057ccbe29481d3297f7b9243a4b92
net: compare received length to sizeof(ip_hdr), not sizeof(ip_udp_hdr)

While the code mostly/only handles UDP packets, it's possible for the
last fragment of a fragmented UDP packet to be smaller than 28 bytes;
it can be as small as 21 bytes (an IP header plus one byte of
payload). So until we've performed the defragmentation step and thus
know whether we're now holding a full packet, we should only check for
the existence of the fields in the ip header, i.e. that there are at
least 20 bytes present.

In practice, we always seem to be handed a "len" of minimum 60 from the
device layer, i.e. minimal ethernet frame length minus FCS, so this is
mostly theoretical.

After we've fetched the header's claimed length and used that to
update the len variable, check that the header itself claims to be the
minimal possible length.

This is probably how CVE-2022-30552 should have been dealt with in the
first place, because net_defragment() is not the only place that wants
to know the size of the IP datagram payload: If we receive a
non-fragmented ICMP packet, we pass "len" to receive_icmp() which in
turn may pass it to ping_receive() which does

  compute_ip_checksum(icmph, len - IP_HDR_SIZE)

and due to the signature of compute_ip_checksum(), that would then
lead to accessing ~4G of address space, very likely leading to a
crash.

Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
net/net.c