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