Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gnrc_sixlowpan: Various hardening fixes [backport 2022.10] #18820

Merged
Merged
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