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_uint16_t chksum;
|
||||
grub_uint32_t src;
|
||||
grub_uint32_t dest;
|
||||
grub_uint32_t dest;
|
||||
} __attribute__ ((packed)) ;
|
||||
|
||||
enum
|
||||
{
|
||||
DONT_FRAGMENT = 0x4000,
|
||||
MORE_FRAGMENTS = 0x2000,
|
||||
OFFSET_MASK = 0x1fff
|
||||
};
|
||||
|
||||
struct ip6hdr
|
||||
{
|
||||
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;
|
||||
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)
|
||||
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. */
|
||||
{
|
||||
|
@ -136,21 +195,26 @@ grub_net_recv_ip_packets (struct grub_net_buff * nb,
|
|||
return err;
|
||||
grub_net_process_dhcp (nb, inf->card);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
grub_netbuff_free (nb);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
|
|
|
@ -781,6 +781,12 @@ receive_packets (struct grub_net_card *card)
|
|||
break;
|
||||
}
|
||||
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 ();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue