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

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