Currently, all relayed packets are broken! At the point when net_key_encrypt() is called from net_rx() for encrypting a relay packet, the packet size must include the NetMIC field. But the length of this field has already been removed during decryption of the incoming packet (by decrypt_net_pkt()), although mesh_crypto_packet_decrypt() has correctly reset the NetMIC field to zeroes. Move stripping of the NetMIC field length from decrypt_net_pkt() to mesh_crypto_packet_parse(), so that the field length is only stripped from the payload message (but keeping the field length for the network PDU). Additionally add extra length checks during parsing. --- mesh/crypto.c | 21 +++++++++++++++++++++ mesh/net-keys.c | 5 +---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/mesh/crypto.c b/mesh/crypto.c index 3dcf226ad8d3..451be81d2fb3 100644 --- a/mesh/crypto.c +++ b/mesh/crypto.c @@ -637,6 +637,9 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len, if (dst) *dst = this_dst; + if (packet_len < 9 + 4) + return false; + hdr = l_get_be32(packet + 9); is_segmented = !!((hdr >> SEG_HDR_SHIFT) & 0x1); @@ -644,6 +647,9 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len, *segmented = is_segmented; if (*ctl) { + /* NetMIC */ + packet_len -= 8; + uint8_t this_opcode = packet[9] & OPCODE_MASK; if (cookie) @@ -660,13 +666,22 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len, *seqZero = (hdr >> SEQ_ZERO_HDR_SHIFT) & SEQ_ZERO_MASK; + if (packet_len < 9) + return false; + *payload = packet + 9; *payload_len = packet_len - 9; } else { + if (packet_len < 10) + return false; + *payload = packet + 10; *payload_len = packet_len - 10; } } else { + /* NetMIC */ + packet_len -= 4; + if (cookie) *cookie = l_get_be32(packet + packet_len - 8); @@ -687,9 +702,15 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len, if (segN) *segN = (hdr >> SEGN_HDR_SHIFT) & SEG_MASK; + if (packet_len < 13) + return false; + *payload = packet + 13; *payload_len = packet_len - 13; } else { + if (packet_len < 10) + return false; + *payload = packet + 10; *payload_len = packet_len - 10; } diff --git a/mesh/net-keys.c b/mesh/net-keys.c index 0daeb9209b86..98e6d23d3f87 100644 --- a/mesh/net-keys.c +++ b/mesh/net-keys.c @@ -238,10 +238,7 @@ static void decrypt_net_pkt(void *a, void *b) if (result) { cache_id = key->id; - if (cache_plain[1] & 0x80) - cache_plainlen = cache_len - 8; - else - cache_plainlen = cache_len - 4; + cache_plainlen = cache_len; } } -- 2.43.0