[PATCH 2/6] net: compare received length to sizeof(ip_hdr), not sizeof(ip_udp_hdr)

Rasmus Villemoes rasmus.villemoes at prevas.dk
Fri Oct 14 19:43:38 CEST 2022


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 at prevas.dk>
---
 net/net.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/net/net.c b/net/net.c
index 536731245b..86b1d90159 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1191,9 +1191,9 @@ void net_process_received_packet(uchar *in_packet, int len)
 	case PROT_IP:
 		debug_cond(DEBUG_NET_PKT, "Got IP\n");
 		/* Before we start poking the header, make sure it is there */
-		if (len < IP_UDP_HDR_SIZE) {
+		if (len < IP_HDR_SIZE) {
 			debug("len bad %d < %lu\n", len,
-			      (ulong)IP_UDP_HDR_SIZE);
+			      (ulong)IP_HDR_SIZE);
 			return;
 		}
 		/* Check the packet length */
@@ -1202,6 +1202,10 @@ void net_process_received_packet(uchar *in_packet, int len)
 			return;
 		}
 		len = ntohs(ip->ip_len);
+		if (len < IP_HDR_SIZE) {
+			debug("bad ip->ip_len %d < %d\n", len, (int)IP_HDR_SIZE);
+			return;
+		}
 		debug_cond(DEBUG_NET_PKT, "len=%d, v=%02x\n",
 			   len, ip->ip_hl_v & 0xff);
 
-- 
2.37.2



More information about the U-Boot mailing list