Blame SOURCES/0243-arp-icmp-Fix-handling-in-case-of-oversized-or-invali.patch

f731ee
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
f731ee
From: Vladimir Serbinenko <phcoder@gmail.com>
f731ee
Date: Fri, 20 Mar 2015 21:14:23 +0100
f731ee
Subject: [PATCH] arp, icmp: Fix handling in case of oversized or invalid
f731ee
 packets.
f731ee
f731ee
This restrict ARP handling to MAC and IP addresses but in practice we need
f731ee
only this case anyway and other cases are very rar if exist at all. It makes
f731ee
code much simpler and less error-prone.
f731ee
---
f731ee
 grub-core/net/arp.c        | 139 ++++++++++++++++++++++-----------------------
f731ee
 grub-core/net/icmp.c       |  14 +----
f731ee
 grub-core/net/netbuff.c    |  20 +++++++
f731ee
 include/grub/net/netbuff.h |   1 +
f731ee
 4 files changed, 90 insertions(+), 84 deletions(-)
f731ee
f731ee
diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c
f731ee
index 8cc390b0e28..6cc580d6f85 100644
f731ee
--- a/grub-core/net/arp.c
f731ee
+++ b/grub-core/net/arp.c
f731ee
@@ -37,12 +37,16 @@ enum
f731ee
     GRUB_NET_ARPHRD_ETHERNET = 1
f731ee
   };
f731ee
 
f731ee
-struct arphdr {
f731ee
+struct arppkt {
f731ee
   grub_uint16_t hrd;
f731ee
   grub_uint16_t pro;
f731ee
   grub_uint8_t hln;
f731ee
   grub_uint8_t pln;
f731ee
   grub_uint16_t op;
f731ee
+  grub_uint8_t sender_mac[6];
f731ee
+  grub_uint32_t sender_ip;
f731ee
+  grub_uint8_t recv_mac[6];
f731ee
+  grub_uint32_t recv_ip;
f731ee
 } GRUB_PACKED;
f731ee
 
f731ee
 static int have_pending;
f731ee
@@ -53,21 +57,14 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
f731ee
 			   const grub_net_network_level_address_t *proto_addr)
f731ee
 {
f731ee
   struct grub_net_buff nb;
f731ee
-  struct arphdr *arp_header;
f731ee
-  grub_net_link_level_address_t target_hw_addr;
f731ee
-  grub_uint8_t *aux, arp_data[128];
f731ee
+  struct arppkt *arp_packet;
f731ee
+  grub_net_link_level_address_t target_mac_addr;
f731ee
   grub_err_t err;
f731ee
   int i;
f731ee
-  grub_size_t addrlen;
f731ee
-  grub_uint16_t etherpro;
f731ee
   grub_uint8_t *nbd;
f731ee
+  grub_uint8_t arp_data[128];
f731ee
 
f731ee
-  if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
f731ee
-    {
f731ee
-      addrlen = 4;
f731ee
-      etherpro = GRUB_NET_ETHERTYPE_IP;
f731ee
-    }
f731ee
-  else
f731ee
+  if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
f731ee
     return grub_error (GRUB_ERR_BUG, "unsupported address family");
f731ee
 
f731ee
   /* Build a request packet.  */
f731ee
@@ -76,34 +73,28 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
f731ee
   grub_netbuff_clear (&nb);
f731ee
   grub_netbuff_reserve (&nb, 128);
f731ee
 
f731ee
-  err = grub_netbuff_push (&nb, sizeof (*arp_header) + 2 * (6 + addrlen));
f731ee
+  err = grub_netbuff_push (&nb, sizeof (*arp_packet));
f731ee
   if (err)
f731ee
     return err;
f731ee
 
f731ee
-  arp_header = (struct arphdr *) nb.data;
f731ee
-  arp_header->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
f731ee
-  arp_header->hln = 6;
f731ee
-  arp_header->pro = grub_cpu_to_be16 (etherpro);
f731ee
-  arp_header->pln = addrlen;
f731ee
-  arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
f731ee
-  aux = (grub_uint8_t *) arp_header + sizeof (*arp_header);
f731ee
+  arp_packet = (struct arppkt *) nb.data;
f731ee
+  arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
f731ee
+  arp_packet->hln = 6;
f731ee
+  arp_packet->pro = grub_cpu_to_be16 (GRUB_NET_ETHERTYPE_IP);
f731ee
+  arp_packet->pln = 4;
f731ee
+  arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
f731ee
   /* Sender hardware address.  */
f731ee
   grub_memcpy (aux, &inf->hwaddress.mac, 6);
f731ee
 
f731ee
-  aux += 6;
f731ee
-  /* Sender protocol address */
f731ee
-  grub_memcpy (aux, &inf->address.ipv4, 4);
f731ee
-  aux += addrlen;
f731ee
-  /* Target hardware address */
f731ee
-  for (i = 0; i < 6; i++)
f731ee
-    aux[i] = 0x00;
f731ee
-  aux += 6;
f731ee
+  grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6);
f731ee
+  arp_packet->sender_ip = inf->address.ipv4;
f731ee
+  grub_memset (arp_packet->recv_mac, 0, 6);
f731ee
+  arp_packet->recv_ip = proto_addr->ipv4;
f731ee
   /* Target protocol address */
f731ee
-  grub_memcpy (aux, &proto_addr->ipv4, 4);
f731ee
-  grub_memset (&target_hw_addr.mac, 0xff, 6);
f731ee
+  grub_memset (&target_mac_addr.mac, 0xff, 6);
f731ee
 
f731ee
   nbd = nb.data;
f731ee
-  send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
f731ee
+  send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP);
f731ee
   for (i = 0; i < GRUB_NET_TRIES; i++)
f731ee
     {
f731ee
       if (grub_net_link_layer_resolve_check (inf, proto_addr))
f731ee
@@ -115,7 +106,7 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
f731ee
       if (grub_net_link_layer_resolve_check (inf, proto_addr))
f731ee
 	return GRUB_ERR_NONE;
f731ee
       nb.data = nbd;
f731ee
-      send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
f731ee
+      send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP);
f731ee
     }
f731ee
 
f731ee
   return GRUB_ERR_NONE;
f731ee
@@ -125,63 +116,67 @@ grub_err_t
f731ee
 grub_net_arp_receive (struct grub_net_buff *nb,
f731ee
 		      struct grub_net_card *card)
f731ee
 {
f731ee
-  struct arphdr *arp_header = (struct arphdr *) nb->data;
f731ee
-  grub_uint8_t *sender_hardware_address;
f731ee
-  grub_uint8_t *target_hardware_address;
f731ee
+  struct arppkt *arp_packet = (struct arppkt *) nb->data;
f731ee
   grub_net_network_level_address_t sender_addr, target_addr;
f731ee
-  grub_net_link_level_address_t sender_hw_addr;
f731ee
+  grub_net_link_level_address_t sender_mac_addr;
f731ee
   struct grub_net_network_level_interface *inf;
f731ee
-  grub_uint8_t *sender_protocol_address, *target_protocol_address;
f731ee
 
f731ee
-  sender_hardware_address =
f731ee
-    (grub_uint8_t *) arp_header + sizeof (*arp_header);
f731ee
-  sender_protocol_address = sender_hardware_address + arp_header->hln;
f731ee
-  target_hardware_address = sender_protocol_address + arp_header->pln;
f731ee
-  target_protocol_address = target_hardware_address + arp_header->hln;
f731ee
-  if (grub_be_to_cpu16 (arp_header->pro) == GRUB_NET_ETHERTYPE_IP
f731ee
-      && arp_header->pln == 4)
f731ee
-    {
f731ee
-      sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
f731ee
-      target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
f731ee
-      grub_memcpy (&sender_addr.ipv4, sender_protocol_address, 4);
f731ee
-      grub_memcpy (&target_addr.ipv4, target_protocol_address, 4);
f731ee
-      if (grub_memcmp (sender_protocol_address, &pending_req, 4) == 0)
f731ee
-	have_pending = 1;
f731ee
-    }
f731ee
-  else
f731ee
+  if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP)
f731ee
+      || arp_packet->pln != 4 || arp_packet->hln != 6
f731ee
+      || nb->tail - nb->data < (int) sizeof (*arp_packet))
f731ee
     return GRUB_ERR_NONE;
f731ee
 
f731ee
-  sender_hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
f731ee
-  grub_memcpy (sender_hw_addr.mac, sender_hardware_address,
f731ee
-	       sizeof (sender_hw_addr.mac));
f731ee
-  grub_net_link_layer_add_address (card, &sender_addr, &sender_hw_addr, 1);
f731ee
+  sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
f731ee
+  target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
f731ee
+  sender_addr.ipv4 = arp_packet->sender_ip;
f731ee
+  target_addr.ipv4 = arp_packet->recv_ip;
f731ee
+  if (arp_packet->sender_ip == pending_req)
f731ee
+    have_pending = 1;
f731ee
+
f731ee
+  sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
f731ee
+  grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac,
f731ee
+	       sizeof (sender_mac_addr.mac));
f731ee
+  grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1);
f731ee
 
f731ee
   FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
f731ee
   {
f731ee
     /* Am I the protocol address target? */
f731ee
     if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
f731ee
-	&& grub_be_to_cpu16 (arp_header->op) == ARP_REQUEST)
f731ee
+	&& arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
f731ee
       {
f731ee
 	grub_net_link_level_address_t target;
f731ee
-	/* We've already checked that pln is either 4 or 16.  */
f731ee
-	char tmp[16];
f731ee
-	grub_size_t pln = arp_header->pln;
f731ee
+	struct grub_net_buff nb_reply;
f731ee
+	struct arppkt *arp_reply;
f731ee
+	grub_uint8_t arp_data[128];
f731ee
+	grub_err_t err;
f731ee
 
f731ee
-	if (pln > 16)
f731ee
-	  pln = 16;
f731ee
+	nb_reply.head = arp_data;
f731ee
+	nb_reply.end = arp_data + sizeof (arp_data);
f731ee
+	grub_netbuff_clear (&nb_reply);
f731ee
+	grub_netbuff_reserve (&nb_reply, 128);
f731ee
+
f731ee
+	err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet));
f731ee
+	if (err)
f731ee
+	  return err;
f731ee
+
f731ee
+	arp_reply = (struct arppkt *) nb_reply.data;
f731ee
+
f731ee
+	arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
f731ee
+	arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
f731ee
+	arp_reply->pln = 4;
f731ee
+	arp_reply->hln = 6;
f731ee
+	arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY);
f731ee
+	arp_reply->sender_ip = arp_packet->recv_ip;
f731ee
+	arp_reply->recv_ip = arp_packet->sender_ip;
f731ee
+	arp_reply->hln = 6;
f731ee
 
f731ee
 	target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
f731ee
-	grub_memcpy (target.mac, sender_hardware_address, 6);
f731ee
-	grub_memcpy (target_hardware_address, target.mac, 6);
f731ee
-	grub_memcpy (sender_hardware_address, inf->hwaddress.mac, 6);
f731ee
-
f731ee
-	grub_memcpy (tmp, sender_protocol_address, pln);
f731ee
-	grub_memcpy (sender_protocol_address, target_protocol_address, pln);
f731ee
-	grub_memcpy (target_protocol_address, tmp, pln);
f731ee
+	grub_memcpy (target.mac, arp_packet->sender_mac, 6);
f731ee
+	grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6);
f731ee
+	grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6);
f731ee
 
f731ee
 	/* Change operation to REPLY and send packet */
f731ee
-	arp_header->op = grub_be_to_cpu16 (ARP_REPLY);
f731ee
-	send_ethernet_packet (inf, nb, target, GRUB_NET_ETHERTYPE_ARP);
f731ee
+	send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP);
f731ee
       }
f731ee
   }
f731ee
   return GRUB_ERR_NONE;
f731ee
diff --git a/grub-core/net/icmp.c b/grub-core/net/icmp.c
f731ee
index 28d825ba04c..b1eef114e03 100644
f731ee
--- a/grub-core/net/icmp.c
f731ee
+++ b/grub-core/net/icmp.c
f731ee
@@ -85,22 +85,13 @@ grub_net_recv_icmp_packet (struct grub_net_buff *nb,
f731ee
 	struct icmp_header *icmphr;
f731ee
 	if (icmph->code)
f731ee
 	  break;
f731ee
-	nb_reply = grub_netbuff_alloc (nb->tail - nb->data + 512);
f731ee
+	nb_reply = grub_netbuff_make_pkt (nb->tail - nb->data + sizeof (*icmphr));
f731ee
 	if (!nb_reply)
f731ee
 	  {
f731ee
 	    grub_netbuff_free (nb);
f731ee
 	    return grub_errno;
f731ee
 	  }
f731ee
-	err = grub_netbuff_reserve (nb_reply, nb->tail - nb->data + 512);
f731ee
-	if (err)
f731ee
-	  goto ping_fail;
f731ee
-	err = grub_netbuff_push (nb_reply, nb->tail - nb->data);
f731ee
-	if (err)
f731ee
-	  goto ping_fail;
f731ee
-	grub_memcpy (nb_reply->data, nb->data, nb->tail - nb->data);
f731ee
-	err = grub_netbuff_push (nb_reply, sizeof (*icmphr));
f731ee
-	if (err)
f731ee
-	  goto ping_fail;
f731ee
+	grub_memcpy (nb_reply->data + sizeof (*icmphr), nb->data, nb->tail - nb->data);
f731ee
 	icmphr = (struct icmp_header *) nb_reply->data;
f731ee
 	icmphr->type = ICMP_ECHO_REPLY;
f731ee
 	icmphr->code = 0;
f731ee
@@ -110,7 +101,6 @@ grub_net_recv_icmp_packet (struct grub_net_buff *nb,
f731ee
 	err = grub_net_send_ip_packet (inf, src, ll_src,
f731ee
 				       nb_reply, GRUB_NET_IP_ICMP);
f731ee
 
f731ee
-      ping_fail:
f731ee
 	grub_netbuff_free (nb);
f731ee
 	grub_netbuff_free (nb_reply);
f731ee
 	return err;
f731ee
diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c
f731ee
index e97ecd23e9c..dbeeefe4783 100644
f731ee
--- a/grub-core/net/netbuff.c
f731ee
+++ b/grub-core/net/netbuff.c
f731ee
@@ -97,6 +97,26 @@ grub_netbuff_alloc (grub_size_t len)
f731ee
   return nb;
f731ee
 }
f731ee
 
f731ee
+struct grub_net_buff *
f731ee
+grub_netbuff_make_pkt (grub_size_t len)
f731ee
+{
f731ee
+  struct grub_net_buff *nb;
f731ee
+  grub_err_t err;
f731ee
+  nb = grub_netbuff_alloc (len + 512);
f731ee
+  if (!nb)
f731ee
+    return NULL;
f731ee
+  err = grub_netbuff_reserve (nb, len + 512);
f731ee
+  if (err)
f731ee
+    goto fail;
f731ee
+  err = grub_netbuff_push (nb, len);
f731ee
+  if (err)
f731ee
+    goto fail;
f731ee
+  return nb;
f731ee
+ fail:
f731ee
+  grub_netbuff_free (nb);
f731ee
+  return NULL;
f731ee
+}
f731ee
+
f731ee
 void
f731ee
 grub_netbuff_free (struct grub_net_buff *nb)
f731ee
 {
f731ee
diff --git a/include/grub/net/netbuff.h b/include/grub/net/netbuff.h
f731ee
index 9ac168c897c..1177c122051 100644
f731ee
--- a/include/grub/net/netbuff.h
f731ee
+++ b/include/grub/net/netbuff.h
f731ee
@@ -25,6 +25,7 @@ grub_err_t grub_netbuff_pull (struct grub_net_buff *net_buff, grub_size_t len);
f731ee
 grub_err_t grub_netbuff_reserve (struct grub_net_buff *net_buff, grub_size_t len);
f731ee
 grub_err_t grub_netbuff_clear (struct grub_net_buff *net_buff);
f731ee
 struct grub_net_buff * grub_netbuff_alloc (grub_size_t len);
f731ee
+struct grub_net_buff * grub_netbuff_make_pkt (grub_size_t len);
f731ee
 void grub_netbuff_free (struct grub_net_buff *net_buff);
f731ee
 
f731ee
 #endif