dcavalca / rpms / grub2

Forked from rpms/grub2 3 years ago
Clone

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

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