improve robustness of IPv4 receiving code

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-07-08 15:43:34 +02:00
parent 1367c143dd
commit 5438143da6
2 changed files with 81 additions and 11 deletions

View file

@ -38,6 +38,13 @@ struct iphdr {
grub_uint32_t dest; grub_uint32_t dest;
} __attribute__ ((packed)) ; } __attribute__ ((packed)) ;
enum
{
DONT_FRAGMENT = 0x4000,
MORE_FRAGMENTS = 0x2000,
OFFSET_MASK = 0x1fff
};
struct ip6hdr struct ip6hdr
{ {
grub_uint8_t version:4, priority:4; grub_uint8_t version:4, priority:4;
@ -116,9 +123,61 @@ grub_net_recv_ip_packets (struct grub_net_buff * nb,
struct grub_net_network_level_interface *inf = NULL; struct grub_net_network_level_interface *inf = NULL;
grub_net_network_level_address_t source; grub_net_network_level_address_t source;
err = grub_netbuff_pull (nb, sizeof (*iph)); if ((iph->verhdrlen >> 4) != 4)
{
grub_dprintf ("net", "Bad IP version: %d\n", (iph->verhdrlen >> 4));
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}
if ((iph->verhdrlen & 0xf) < 5)
{
grub_dprintf ("net", "IP header too short: %d\n",
(iph->verhdrlen & 0xf));
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}
err = grub_netbuff_pull (nb, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t));
if (err) if (err)
{
grub_netbuff_free (nb);
return err; return err;
}
/* Check size*/
{
grub_size_t expected_size = grub_be_to_cpu16 (iph->len);
grub_size_t actual_size = (nb->tail - nb->data
+ (iph->verhdrlen & 0xf)
* sizeof (grub_uint32_t));
if (actual_size > expected_size)
{
err = grub_netbuff_unput (nb, actual_size - expected_size);
if (err)
{
grub_netbuff_free (nb);
return err;
}
}
if (actual_size < expected_size)
{
grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE
", expected %" PRIuGRUB_SIZE "\n", actual_size,
expected_size);
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}
}
/* Fragmented packet. Bad. */
if (((grub_be_to_cpu16 (iph->frags) & MORE_FRAGMENTS) != 0)
|| (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) != 0)
{
/* FIXME. */
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}
/* DHCP needs special treatment since we don't know IP yet. */ /* DHCP needs special treatment since we don't know IP yet. */
{ {
@ -136,13 +195,13 @@ grub_net_recv_ip_packets (struct grub_net_buff * nb,
return err; return err;
grub_net_process_dhcp (nb, inf->card); grub_net_process_dhcp (nb, inf->card);
grub_netbuff_free (nb); grub_netbuff_free (nb);
return GRUB_ERR_NONE;
} }
grub_netbuff_free (nb);
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
} }
if (!inf)
{
FOR_NET_NETWORK_LEVEL_INTERFACES (inf) FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
{ {
if (inf->card == card if (inf->card == card
@ -151,6 +210,11 @@ grub_net_recv_ip_packets (struct grub_net_buff * nb,
&& grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0) && grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0)
break; break;
} }
if (!inf)
{
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
} }
source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;

View file

@ -781,6 +781,12 @@ receive_packets (struct grub_net_card *card)
break; break;
} }
grub_net_recv_ethernet_packet (nb, card); grub_net_recv_ethernet_packet (nb, card);
if (grub_errno)
{
grub_dprintf ("net", "error receiving: %d: %s\n", grub_errno,
grub_errmsg);
grub_errno = GRUB_ERR_NONE;
}
} }
grub_print_error (); grub_print_error ();
} }