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

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