mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-25 14:33:52 +01:00
gnrc_ipv6: validates payload size
This commit is contained in:
parent
a10151d5f0
commit
0de34c91c6
@ -69,6 +69,14 @@ void gnrc_icmpv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt)
|
||||
|
||||
assert(ipv6 != NULL);
|
||||
|
||||
if (icmpv6->size < sizeof(icmpv6_hdr_t)) {
|
||||
DEBUG("icmpv6: packet too short.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note: size will be checked again in gnrc_icmpv6_echo_req_handle,
|
||||
gnrc_ndp_rtr_sol_handle, and others */
|
||||
|
||||
hdr = (icmpv6_hdr_t *)icmpv6->data;
|
||||
|
||||
if (_calc_csum(icmpv6, ipv6, pkt)) {
|
||||
|
||||
@ -138,6 +138,30 @@ static gnrc_pktsnip_t *_mark_extension_header(gnrc_pktsnip_t *current,
|
||||
return next;
|
||||
}
|
||||
|
||||
static inline bool _has_valid_size(gnrc_pktsnip_t *pkt, uint8_t nh)
|
||||
{
|
||||
ipv6_ext_t *ext;
|
||||
|
||||
if (pkt->size < sizeof(ipv6_ext_t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ext = pkt->data;
|
||||
|
||||
switch (nh) {
|
||||
case PROTNUM_IPV6_EXT_RH:
|
||||
case PROTNUM_IPV6_EXT_HOPOPT:
|
||||
case PROTNUM_IPV6_EXT_DST:
|
||||
case PROTNUM_IPV6_EXT_FRAG:
|
||||
case PROTNUM_IPV6_EXT_AH:
|
||||
case PROTNUM_IPV6_EXT_ESP:
|
||||
case PROTNUM_IPV6_EXT_MOB:
|
||||
return ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT) <= pkt->size;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* current pkt
|
||||
@ -158,6 +182,13 @@ void gnrc_ipv6_ext_demux(kernel_pid_t iface,
|
||||
switch (nh) {
|
||||
case PROTNUM_IPV6_EXT_RH:
|
||||
#ifdef MODULE_GNRC_RPL_SRH
|
||||
/* if current != pkt, size is already checked */
|
||||
if (current == pkt && !_has_valid_size(pkt, nh)) {
|
||||
DEBUG("ipv6_ext: invalid size\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (_handle_rh(current, pkt)) {
|
||||
case GNRC_IPV6_EXT_OK:
|
||||
/* We are the final destination. So proceeds like normal packet. */
|
||||
@ -191,6 +222,14 @@ void gnrc_ipv6_ext_demux(kernel_pid_t iface,
|
||||
case PROTNUM_IPV6_EXT_ESP:
|
||||
case PROTNUM_IPV6_EXT_MOB:
|
||||
/* TODO: add handling of types */
|
||||
|
||||
/* if current != pkt, size is already checked */
|
||||
if (current == pkt && !_has_valid_size(pkt, nh)) {
|
||||
DEBUG("ipv6_ext: invalid size\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
nh = ext->nh;
|
||||
DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh);
|
||||
|
||||
|
||||
@ -853,6 +853,7 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
||||
ipv6 = gnrc_pktbuf_mark(pkt, sizeof(ipv6_hdr_t), GNRC_NETTYPE_IPV6);
|
||||
|
||||
first_ext = pkt;
|
||||
pkt->type = GNRC_NETTYPE_UNDEF; /* snip is no longer IPv6 */
|
||||
|
||||
if (ipv6 == NULL) {
|
||||
DEBUG("ipv6: error marking IPv6 header, dropping packet\n");
|
||||
@ -885,6 +886,14 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
||||
if (byteorder_ntohs(hdr->len) < pkt->size) {
|
||||
gnrc_pktbuf_realloc_data(pkt, byteorder_ntohs(hdr->len));
|
||||
}
|
||||
else if (byteorder_ntohs(hdr->len) >
|
||||
(gnrc_pkt_len_upto(pkt, GNRC_NETTYPE_IPV6) - sizeof(ipv6_hdr_t))) {
|
||||
DEBUG("ipv6: invalid payload length: %d, actual: %d, dropping packet\n",
|
||||
(int) byteorder_ntohs(hdr->len),
|
||||
(int) (gnrc_pkt_len_upto(pkt, GNRC_NETTYPE_IPV6) - sizeof(ipv6_hdr_t)));
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("ipv6: Received (src = %s, ",
|
||||
ipv6_addr_to_str(addr_str, &(hdr->src), sizeof(addr_str)));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user