improve robustness of IPv4 receiving code
This commit is contained in:
parent
1367c143dd
commit
5438143da6
2 changed files with 81 additions and 11 deletions
|
@ -35,9 +35,16 @@ struct iphdr {
|
||||||
grub_uint8_t protocol;
|
grub_uint8_t protocol;
|
||||||
grub_uint16_t chksum;
|
grub_uint16_t chksum;
|
||||||
grub_uint32_t src;
|
grub_uint32_t src;
|
||||||
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)
|
||||||
return err;
|
{
|
||||||
|
grub_netbuff_free (nb);
|
||||||
|
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,21 +195,26 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
|
||||||
|
{
|
||||||
|
if (inf->card == card
|
||||||
|
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
|
||||||
|
&& inf->address.ipv4 == iph->dest
|
||||||
|
&& grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!inf)
|
if (!inf)
|
||||||
{
|
{
|
||||||
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
|
grub_netbuff_free (nb);
|
||||||
{
|
return GRUB_ERR_NONE;
|
||||||
if (inf->card == card
|
|
||||||
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
|
|
||||||
&& inf->address.ipv4 == iph->dest
|
|
||||||
&& grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||||
|
|
|
@ -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 ();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue