Skip to content

Commit d303dab

Browse files
author
Tomasz Bursztyka
committed
net/ieee802154: Each fragment should be at least of its header's length
Not validating this length could lead to integer underflow and memory corruption. Signed-off-by: Tomasz Bursztyka <[email protected]>
1 parent 14aba71 commit d303dab

File tree

1 file changed

+23
-13
lines changed

1 file changed

+23
-13
lines changed

subsys/net/l2/ieee802154/ieee802154_fragment.c

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ void ieee802154_fragment(struct ieee802154_fragment_ctx *ctx,
215215
ctx->offset = ctx->processed >> 3;
216216
}
217217

218+
static inline uint8_t get_datagram_type(uint8_t *ptr)
219+
{
220+
return ptr[0] & NET_FRAG_DISPATCH_MASK;
221+
}
222+
218223
static inline uint16_t get_datagram_size(uint8_t *ptr)
219224
{
220225
return ((ptr[0] & 0x1F) << 8) | ptr[1];
@@ -344,8 +349,7 @@ static inline struct frag_cache *get_reass_cache(uint16_t size, uint16_t tag)
344349

345350
static inline void fragment_append(struct net_pkt *pkt, struct net_buf *frag)
346351
{
347-
if ((frag->data[0] & NET_FRAG_DISPATCH_MASK) ==
348-
NET_6LO_DISPATCH_FRAG1) {
352+
if (get_datagram_type(frag->data) == NET_6LO_DISPATCH_FRAG1) {
349353
/* Always make sure first fragment is inserted first
350354
* This will be useful for fragment_cached_pkt_len()
351355
*/
@@ -367,8 +371,7 @@ static inline size_t fragment_cached_pkt_len(struct net_pkt *pkt)
367371
while (frag) {
368372
uint16_t hdr_len = NET_6LO_FRAGN_HDR_LEN;
369373

370-
if ((frag->data[0] & NET_FRAG_DISPATCH_MASK) ==
371-
NET_6LO_DISPATCH_FRAG1) {
374+
if (get_datagram_type(frag->data) == NET_6LO_DISPATCH_FRAG1) {
372375
hdr_len = NET_6LO_FRAG1_HDR_LEN;
373376
}
374377

@@ -396,8 +399,7 @@ static inline size_t fragment_cached_pkt_len(struct net_pkt *pkt)
396399

397400
static inline uint16_t fragment_offset(struct net_buf *frag)
398401
{
399-
if ((frag->data[0] & NET_FRAG_DISPATCH_MASK) ==
400-
NET_6LO_DISPATCH_FRAG1) {
402+
if (get_datagram_type(frag->data) == NET_6LO_DISPATCH_FRAG1) {
401403
return 0;
402404
}
403405

@@ -435,8 +437,7 @@ static inline void fragment_remove_headers(struct net_pkt *pkt)
435437
while (frag) {
436438
uint16_t hdr_len = NET_6LO_FRAGN_HDR_LEN;
437439

438-
if ((frag->data[0] & NET_FRAG_DISPATCH_MASK) ==
439-
NET_6LO_DISPATCH_FRAG1) {
440+
if (get_datagram_type(frag->data) == NET_6LO_DISPATCH_FRAG1) {
440441
hdr_len = NET_6LO_FRAG1_HDR_LEN;
441442
}
442443

@@ -486,18 +487,28 @@ static inline enum net_verdict fragment_add_to_cache(struct net_pkt *pkt)
486487
struct net_buf *frag;
487488
uint16_t size;
488489
uint16_t tag;
490+
uint8_t type;
491+
492+
frag = pkt->buffer;
493+
type = get_datagram_type(frag->data);
494+
495+
if ((type == NET_6LO_DISPATCH_FRAG1 &&
496+
frag->len < NET_6LO_FRAG1_HDR_LEN) ||
497+
(type == NET_6LO_DISPATCH_FRAGN &&
498+
frag->len < NET_6LO_FRAGN_HDR_LEN)) {
499+
return NET_DROP;
500+
}
489501

490502
/* Parse total size of packet */
491-
size = get_datagram_size(pkt->buffer->data);
503+
size = get_datagram_size(frag->data);
492504

493505
/* Parse the datagram tag */
494-
tag = get_datagram_tag(pkt->buffer->data +
506+
tag = get_datagram_tag(frag->data +
495507
NET_6LO_FRAG_DATAGRAM_SIZE_LEN);
496508

497509
/* If there are no fragments in the cache means this frag
498510
* is the first one. So cache Rx pkt otherwise not.
499511
*/
500-
frag = pkt->buffer;
501512
pkt->buffer = NULL;
502513

503514
cache = get_reass_cache(size, tag);
@@ -556,8 +567,7 @@ enum net_verdict ieee802154_reassemble(struct net_pkt *pkt)
556567
return NET_DROP;
557568
}
558569

559-
if ((pkt->buffer->data[0] & NET_FRAG_DISPATCH_MASK) >=
560-
NET_6LO_DISPATCH_FRAG1) {
570+
if (get_datagram_type(pkt->buffer->data) >= NET_6LO_DISPATCH_FRAG1) {
561571
return fragment_add_to_cache(pkt);
562572
} else {
563573
NET_DBG("No frag dispatch (%02x)", pkt->buffer->data[0]);

0 commit comments

Comments
 (0)