diff --git a/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c b/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c index 806f94fb6dbe..5b50bfa3d24c 100644 --- a/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c +++ b/sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c @@ -54,7 +54,7 @@ static gnrc_pktsnip_t *_make_netif_hdr(uint8_t *mhr) dst_len = ieee802154_get_dst(mhr, dst, &_pan_tmp); src_len = ieee802154_get_src(mhr, src, &_pan_tmp); - if ((dst_len < 0) || (src_len < 0)) { + if ((dst_len < 0) || (src_len <= 0)) { DEBUG("_make_netif_hdr: unable to get addresses\n"); return NULL; } diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/rb/gnrc_sixlowpan_frag_rb.c b/sys/net/gnrc/network_layer/sixlowpan/frag/rb/gnrc_sixlowpan_frag_rb.c index 97fa3cd2fdc1..d406f6057660 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/frag/rb/gnrc_sixlowpan_frag_rb.c +++ b/sys/net/gnrc/network_layer/sixlowpan/frag/rb/gnrc_sixlowpan_frag_rb.c @@ -236,6 +236,9 @@ static size_t _6lo_frag_size(gnrc_pktsnip_t *pkt, size_t offset, uint8_t *data) size_t frag_size; if (offset == 0) { + if (pkt->size < sizeof(sixlowpan_frag_t)) { + return 0; + } frag_size = pkt->size - sizeof(sixlowpan_frag_t); if (data[0] == SIXLOWPAN_UNCOMP) { /* subtract SIXLOWPAN_UNCOMP byte from fragment size, @@ -244,6 +247,9 @@ static size_t _6lo_frag_size(gnrc_pktsnip_t *pkt, size_t offset, uint8_t *data) } } else { + if (pkt->size < sizeof(sixlowpan_frag_n_t)) { + return 0; + } frag_size = pkt->size - sizeof(sixlowpan_frag_n_t); } return frag_size; @@ -306,6 +312,11 @@ static int _rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG) && sixlowpan_frag_is(pkt->data)) { data = _6lo_frag_payload(pkt); frag_size = _6lo_frag_size(pkt, offset, data); + if (frag_size == 0) { + DEBUG("6lo rbuf: integer underflow detected.\n"); + gnrc_pktbuf_release(pkt); + return RBUF_ADD_ERROR; + } datagram_size = sixlowpan_frag_datagram_size(pkt->data); datagram_tag = sixlowpan_frag_datagram_tag(pkt->data); } diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/vrb/gnrc_sixlowpan_frag_vrb.c b/sys/net/gnrc/network_layer/sixlowpan/frag/vrb/gnrc_sixlowpan_frag_vrb.c index 1ceacbdac6b1..e4a858f78d83 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/frag/vrb/gnrc_sixlowpan_frag_vrb.c +++ b/sys/net/gnrc/network_layer/sixlowpan/frag/vrb/gnrc_sixlowpan_frag_vrb.c @@ -53,6 +53,7 @@ gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_add( gnrc_sixlowpan_frag_vrb_t *vrbe = NULL; assert(base != NULL); + assert(base->src_len != 0); assert(out_netif != NULL); assert(out_dst != NULL); assert(out_dst_len > 0); @@ -168,6 +169,7 @@ gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_get( { DEBUG("6lo vrb: trying to get entry for (%s, %u)\n", gnrc_netif_addr_to_str(src, src_len, addr_str), src_tag); + assert(src_len != 0); for (unsigned i = 0; i < CONFIG_GNRC_SIXLOWPAN_FRAG_VRB_SIZE; i++) { gnrc_sixlowpan_frag_vrb_t *vrbe = &_vrb[i]; @@ -189,6 +191,7 @@ gnrc_sixlowpan_frag_vrb_t *gnrc_sixlowpan_frag_vrb_reverse( { DEBUG("6lo vrb: trying to get entry for reverse label switching (%s, %u)\n", gnrc_netif_addr_to_str(src, src_len, addr_str), tag); + assert(src_len != 0); for (unsigned i = 0; i < CONFIG_GNRC_SIXLOWPAN_FRAG_VRB_SIZE; i++) { gnrc_sixlowpan_frag_vrb_t *vrbe = &_vrb[i]; diff --git a/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c b/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c index 6545217ab5e9..430a694ed861 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c +++ b/sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c @@ -737,6 +737,12 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr, if (rbuf != NULL) { ipv6 = rbuf->pkt; assert(ipv6 != NULL); + if ((ipv6->size < sizeof(ipv6_hdr_t)) && + (gnrc_pktbuf_realloc_data(ipv6, sizeof(ipv6_hdr_t)) != 0)) { + DEBUG("6lo iphc: no space to decompress IPHC\n"); + _recv_error_release(sixlo, ipv6, rbuf); + return; + } } else { ipv6 = gnrc_pktbuf_add(NULL, NULL, sizeof(ipv6_hdr_t), @@ -754,8 +760,9 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr, iface = gnrc_netif_hdr_get_netif(netif->data); payload_offset = _iphc_ipv6_decode(iphc_hdr, netif->data, iface, ipv6->data); - if (payload_offset == 0) { - /* unable to parse IPHC header */ + if ((payload_offset == 0) || (payload_offset > sixlo->size)) { + /* unable to parse IPHC header or malicious packet */ + DEBUG("6lo iphc: malformed IPHC header\n"); _recv_error_release(sixlo, ipv6, rbuf); return; } @@ -775,7 +782,9 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr, &prev_nh_offset, ipv6, &uncomp_hdr_len); - if (payload_offset == 0) { + if ((payload_offset == 0) || (payload_offset > sixlo->size)) { + /* unable to parse IPHC header or malicious packet */ + DEBUG("6lo iphc: malformed IPHC NHC IPv6 header\n"); _recv_error_release(sixlo, ipv6, rbuf); return; } @@ -790,7 +799,9 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr, prev_nh_offset, ipv6, &uncomp_hdr_len); - if (payload_offset == 0) { + if ((payload_offset == 0) || (payload_offset > sixlo->size)) { + /* unable to parse IPHC header or malicious packet */ + DEBUG("6lo iphc: malformed IPHC NHC IPv6 header\n"); _recv_error_release(sixlo, ipv6, rbuf); return; } @@ -828,14 +839,14 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr, #endif /* MODULE_GNRC_SIXLOWPAN_FRAG_VRB */ } else { - /* for a fragmented datagram we know the overall length already */ + /* for a fragmented datagram we know the overall length already */ payload_len = (uint16_t)(rbuf->super.datagram_size - sizeof(ipv6_hdr_t)); } #ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB - DEBUG("6lo iphc: VRB present, trying to create entry for dst %s\n", - ipv6_addr_to_str(addr_str, &ipv6_hdr->dst, sizeof(addr_str))); /* re-assign IPv6 header in case realloc changed the address */ ipv6_hdr = ipv6->data; + DEBUG("6lo iphc: VRB present, trying to create entry for dst %s\n", + ipv6_addr_to_str(addr_str, &ipv6_hdr->dst, sizeof(addr_str))); /* only create virtual reassembly buffer entry from IPv6 destination if * the current first fragment is the only received fragment in the * reassembly buffer so far and the hop-limit is larger than 1 @@ -872,19 +883,31 @@ void gnrc_sixlowpan_iphc_recv(gnrc_pktsnip_t *sixlo, void *rbuf_ptr, payload_len = (sixlo->size + uncomp_hdr_len - payload_offset - sizeof(ipv6_hdr_t)); } - if ((rbuf == NULL) && + if (rbuf == NULL) { /* (rbuf == NULL) => forwarding is not affected by this */ - (gnrc_pktbuf_realloc_data(ipv6, uncomp_hdr_len + payload_len) != 0)) { - DEBUG("6lo iphc: no space left to copy payload\n"); - _recv_error_release(sixlo, ipv6, rbuf); - return; + if (gnrc_pktbuf_realloc_data(ipv6, uncomp_hdr_len + payload_len) != 0) { + DEBUG("6lo iphc: no space left to copy payload\n"); + _recv_error_release(sixlo, ipv6, rbuf); + return; + } } + else { + if (ipv6->size < (uncomp_hdr_len + (sixlo->size - payload_offset))) { + DEBUG("6lo iphc: not enough space to copy payload.\n"); + DEBUG("6lo iphc: potentially malicious datagram size received.\n"); + _recv_error_release(sixlo, ipv6, rbuf); + return; + } + } + /* re-assign IPv6 header in case realloc changed the address */ ipv6_hdr = ipv6->data; ipv6_hdr->len = byteorder_htons(payload_len); - memcpy(((uint8_t *)ipv6->data) + uncomp_hdr_len, - ((uint8_t *)sixlo->data) + payload_offset, - sixlo->size - payload_offset); + if (sixlo->size > payload_offset) { + memcpy(((uint8_t *)ipv6->data) + uncomp_hdr_len, + ((uint8_t *)sixlo->data) + payload_offset, + sixlo->size - payload_offset); + } if (rbuf != NULL) { rbuf->super.current_size += (uncomp_hdr_len - payload_offset); #ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB @@ -1590,16 +1613,7 @@ static gnrc_pktsnip_t *_iphc_encode(gnrc_pktsnip_t *pkt, else { dispatch->next = ptr; } - if (ptr->type == GNRC_NETTYPE_UNDEF) { - /* most likely UDP for now so use that (XXX: extend if extension - * headers make problems) */ - dispatch_size += sizeof(udp_hdr_t); - break; /* nothing special after UDP so quit even if more UNDEF - * come */ - } - else { - dispatch_size += ptr->size; - } + dispatch_size += ptr->size; dispatch = ptr; /* use dispatch as temporary point for prev */ ptr = ptr->next; } @@ -1627,6 +1641,11 @@ static gnrc_pktsnip_t *_iphc_encode(gnrc_pktsnip_t *pkt, #ifdef MODULE_GNRC_SIXLOWPAN_IPHC_NHC while (_compressible_nh(nh)) { ssize_t local_pos = 0; + if (pkt->next->next == NULL) { + DEBUG("6lo iphc: packet next header missing data"); + gnrc_pktbuf_release(dispatch); + return NULL; + } switch (nh) { case PROTNUM_UDP: local_pos = _nhc_udp_encode_snip(pkt, &iphc_hdr[inline_pos]); diff --git a/sys/net/link_layer/ieee802154/ieee802154.c b/sys/net/link_layer/ieee802154/ieee802154.c index 7b7227270fd1..9d51bc815843 100644 --- a/sys/net/link_layer/ieee802154/ieee802154.c +++ b/sys/net/link_layer/ieee802154/ieee802154.c @@ -115,27 +115,39 @@ size_t ieee802154_set_frame_hdr(uint8_t *buf, const uint8_t *src, size_t src_len size_t ieee802154_get_frame_hdr_len(const uint8_t *mhr) { /* TODO: include security header implications */ - uint8_t tmp; + uint8_t tmp, has_dst = 0; size_t len = 3; /* 2 byte FCF, 1 byte sequence number */ - /* figure out address sizes */ - tmp = (mhr[1] & IEEE802154_FCF_DST_ADDR_MASK); - if (tmp == IEEE802154_FCF_DST_ADDR_SHORT) { - len += 4; /* 2 byte dst PAN + 2 byte dst short address */ - } - else if (tmp == IEEE802154_FCF_DST_ADDR_LONG) { - len += 10; /* 2 byte dst PAN + 2 byte dst long address */ - } - else if (tmp != IEEE802154_FCF_DST_ADDR_VOID) { - return 0; - } - else if (mhr[0] & IEEE802154_FCF_PAN_COMP) { - /* PAN compression, but no destination address => illegal state */ + tmp = (mhr[0] & IEEE802154_FCF_TYPE_MASK); + if (tmp == IEEE802154_FCF_TYPE_ACK) { + /* ACK contains no other fields */ + return len; + } else if (tmp != IEEE802154_FCF_TYPE_BEACON) { + /* Beacon contains no dst address */ + tmp = (mhr[1] & IEEE802154_FCF_DST_ADDR_MASK); + if (tmp == IEEE802154_FCF_DST_ADDR_SHORT) { + len += 4; /* 2 byte dst PAN + 2 byte dst short address */ + has_dst = 1; + } + else if (tmp == IEEE802154_FCF_DST_ADDR_LONG) { + len += 10; /* 2 byte dst PAN + 8 byte dst long address */ + has_dst = 1; + } + else if (tmp != IEEE802154_FCF_DST_ADDR_VOID) { + return 0; + } + else if (mhr[0] & IEEE802154_FCF_PAN_COMP) { + /* PAN compression, but no destination address => illegal state */ + return 0; + } + } else if (mhr[0] & IEEE802154_FCF_PAN_COMP) { + /* Beacon can't use PAN compression */ return 0; } tmp = (mhr[1] & IEEE802154_FCF_SRC_ADDR_MASK); if (tmp == IEEE802154_FCF_SRC_ADDR_VOID) { - return len; + /* One of dst or src address must be present */ + return has_dst ? len : 0; } else { if (!(mhr[0] & IEEE802154_FCF_PAN_COMP)) { diff --git a/tests/unittests/tests-ieee802154/tests-ieee802154.c b/tests/unittests/tests-ieee802154/tests-ieee802154.c index 6573f14c8550..e7a48757cfbd 100644 --- a/tests/unittests/tests-ieee802154/tests-ieee802154.c +++ b/tests/unittests/tests-ieee802154/tests-ieee802154.c @@ -406,105 +406,108 @@ static void test_ieee802154_set_frame_hdr_dst8_src8_pancomp(void) static void test_ieee802154_get_frame_hdr_len_dst0_src0(void) { - const uint8_t mhr[] = { 0x00, IEEE802154_FCF_DST_ADDR_VOID | - IEEE802154_FCF_SRC_ADDR_VOID }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA, IEEE802154_FCF_DST_ADDR_VOID | + IEEE802154_FCF_SRC_ADDR_VOID }; - TEST_ASSERT_EQUAL_INT(3, ieee802154_get_frame_hdr_len(mhr)); + /* either source or destination are required, so expect an error */ + TEST_ASSERT_EQUAL_INT(0, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dstr(void) { - const uint8_t mhr[] = { 0x00, IEEE802154_FCF_DST_ADDR_RESV }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA, IEEE802154_FCF_DST_ADDR_RESV }; TEST_ASSERT_EQUAL_INT(0, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_srcr(void) { - const uint8_t mhr[] = { 0x00, IEEE802154_FCF_DST_ADDR_RESV }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA, IEEE802154_FCF_DST_ADDR_RESV }; TEST_ASSERT_EQUAL_INT(0, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst2_src0(void) { - const uint8_t mhr[] = { 0x00, IEEE802154_FCF_DST_ADDR_SHORT | - IEEE802154_FCF_SRC_ADDR_VOID }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA, IEEE802154_FCF_DST_ADDR_SHORT | + IEEE802154_FCF_SRC_ADDR_VOID }; TEST_ASSERT_EQUAL_INT(7, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst8_src0(void) { - const uint8_t mhr[] = { 0x00, IEEE802154_FCF_DST_ADDR_LONG }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA, IEEE802154_FCF_DST_ADDR_LONG }; TEST_ASSERT_EQUAL_INT(13, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst0_src2(void) { - const uint8_t mhr[] = { 0x00, IEEE802154_FCF_SRC_ADDR_SHORT }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA, IEEE802154_FCF_SRC_ADDR_SHORT }; TEST_ASSERT_EQUAL_INT(7, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst0_src2_pancomp(void) { - const uint8_t mhr[] = { IEEE802154_FCF_PAN_COMP, IEEE802154_FCF_SRC_ADDR_SHORT }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA | IEEE802154_FCF_PAN_COMP, + IEEE802154_FCF_SRC_ADDR_SHORT }; TEST_ASSERT_EQUAL_INT(0, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst0_src8(void) { - const uint8_t mhr[] = { 0x00, IEEE802154_FCF_SRC_ADDR_LONG }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA, IEEE802154_FCF_SRC_ADDR_LONG }; TEST_ASSERT_EQUAL_INT(13, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst0_src8_pancomp(void) { - const uint8_t mhr[] = { IEEE802154_FCF_PAN_COMP, IEEE802154_FCF_SRC_ADDR_LONG }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA | IEEE802154_FCF_PAN_COMP, + IEEE802154_FCF_SRC_ADDR_LONG }; TEST_ASSERT_EQUAL_INT(0, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst2_src2(void) { - const uint8_t mhr[] = { 0x00, IEEE802154_FCF_DST_ADDR_SHORT | - IEEE802154_FCF_SRC_ADDR_SHORT }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA, + IEEE802154_FCF_DST_ADDR_SHORT | IEEE802154_FCF_SRC_ADDR_SHORT }; TEST_ASSERT_EQUAL_INT(11, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst8_src2(void) { - const uint8_t mhr[] = { 0x00, IEEE802154_FCF_DST_ADDR_LONG | - IEEE802154_FCF_SRC_ADDR_SHORT }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA, + IEEE802154_FCF_DST_ADDR_LONG | IEEE802154_FCF_SRC_ADDR_SHORT }; TEST_ASSERT_EQUAL_INT(17, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst8_src8(void) { - const uint8_t mhr[] = { 0x00, IEEE802154_FCF_DST_ADDR_LONG | - IEEE802154_FCF_SRC_ADDR_LONG }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA, + IEEE802154_FCF_DST_ADDR_LONG | IEEE802154_FCF_SRC_ADDR_LONG }; TEST_ASSERT_EQUAL_INT(23, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst2_src2_pancomp(void) { - const uint8_t mhr[] = { IEEE802154_FCF_PAN_COMP, IEEE802154_FCF_DST_ADDR_SHORT | - IEEE802154_FCF_SRC_ADDR_SHORT }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA | IEEE802154_FCF_PAN_COMP, + IEEE802154_FCF_DST_ADDR_SHORT | IEEE802154_FCF_SRC_ADDR_SHORT }; TEST_ASSERT_EQUAL_INT(9, ieee802154_get_frame_hdr_len(mhr)); } static void test_ieee802154_get_frame_hdr_len_dst8_src8_pancomp(void) { - const uint8_t mhr[] = { IEEE802154_FCF_PAN_COMP, IEEE802154_FCF_DST_ADDR_LONG | - IEEE802154_FCF_SRC_ADDR_LONG }; + const uint8_t mhr[] = { IEEE802154_FCF_TYPE_DATA | IEEE802154_FCF_PAN_COMP, + IEEE802154_FCF_DST_ADDR_LONG | IEEE802154_FCF_SRC_ADDR_LONG }; TEST_ASSERT_EQUAL_INT(21, ieee802154_get_frame_hdr_len(mhr)); }