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

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