diff --git a/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c b/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c index f8f9754910..9b2a0c4f66 100644 --- a/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c +++ b/sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c @@ -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)) { diff --git a/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c b/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c index b86d035e7d..349b673afb 100644 --- a/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c +++ b/sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c @@ -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); diff --git a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c index 397429c0dd..3ebe2cc7fd 100644 --- a/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c +++ b/sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c @@ -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)));