Skip to content

Commit

Permalink
Merge pull request #18817 from miri64/gnrc_sixlowpan/fix/harden
Browse files Browse the repository at this point in the history
gnrc_sixlowpan: Various hardening fixes
  • Loading branch information
miri64 authored Oct 29, 2022
2 parents 2a934c9 + 3c7c9fe commit 5e9d627
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 63 deletions.
2 changes: 1 addition & 1 deletion sys/net/gnrc/netif/ieee802154/gnrc_netif_ieee802154.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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];

Expand All @@ -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];

Expand Down
69 changes: 44 additions & 25 deletions sys/net/gnrc/network_layer/sixlowpan/iphc/gnrc_sixlowpan_iphc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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]);
Expand Down
42 changes: 27 additions & 15 deletions sys/net/link_layer/ieee802154/ieee802154.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
47 changes: 25 additions & 22 deletions tests/unittests/tests-ieee802154/tests-ieee802154.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down

0 comments on commit 5e9d627

Please sign in to comment.