Skip to content

Commit

Permalink
6lowpan: read data from skb safely
Browse files Browse the repository at this point in the history
Check if skb buffer can pull requested amount of bytes and return
an error in opposite case.

Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
alex.bluesman.smirnov@gmail.com authored and David S. Miller committed Jun 25, 2012
1 parent 1d5873e commit c5d3687
Showing 1 changed file with 38 additions and 32 deletions.
70 changes: 38 additions & 32 deletions net/ieee802154/6lowpan.c
Original file line number Diff line number Diff line change
@@ -291,25 +291,26 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
*hc06_ptr += 2;
}

static u8 lowpan_fetch_skb_u8(struct sk_buff *skb)
static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
{
u8 ret;
if (unlikely(!pskb_may_pull(skb, 1)))
return -EINVAL;

ret = skb->data[0];
*val = skb->data[0];
skb_pull(skb, 1);

return ret;
return 0;
}

static u16 lowpan_fetch_skb_u16(struct sk_buff *skb)
static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
{
u16 ret;

BUG_ON(!pskb_may_pull(skb, 2));
if (unlikely(!pskb_may_pull(skb, 2)))
return -EINVAL;

ret = skb->data[0] | (skb->data[1] << 8);
*val = skb->data[0] | (skb->data[1] << 8);
skb_pull(skb, 2);
return ret;

return 0;
}

static int
@@ -318,7 +319,8 @@ lowpan_uncompress_udp_header(struct sk_buff *skb)
struct udphdr *uh = udp_hdr(skb);
u8 tmp;

tmp = lowpan_fetch_skb_u8(skb);
if (lowpan_fetch_skb_u8(skb, &tmp))
goto err;

if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
pr_debug("(%s): UDP header uncompression\n", __func__);
@@ -710,7 +712,9 @@ lowpan_process_data(struct sk_buff *skb)
/* at least two bytes will be used for the encoding */
if (skb->len < 2)
goto drop;
iphc0 = lowpan_fetch_skb_u8(skb);

if (lowpan_fetch_skb_u8(skb, &iphc0))
goto drop;

/* fragments assembling */
switch (iphc0 & LOWPAN_DISPATCH_MASK) {
@@ -722,8 +726,9 @@ lowpan_process_data(struct sk_buff *skb)
u16 tag;
bool found = false;

len = lowpan_fetch_skb_u8(skb); /* frame length */
tag = lowpan_fetch_skb_u16(skb);
if (lowpan_fetch_skb_u8(skb, &len) || /* frame length */
lowpan_fetch_skb_u16(skb, &tag)) /* fragment tag */
goto drop;

/*
* check if frame assembling with the same tag is
@@ -747,7 +752,8 @@ lowpan_process_data(struct sk_buff *skb)
if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1)
goto unlock_and_drop;

offset = lowpan_fetch_skb_u8(skb); /* fetch offset */
if (lowpan_fetch_skb_u8(skb, &offset)) /* fetch offset */
goto unlock_and_drop;

/* if payload fits buffer, copy it */
if (likely((offset * 8 + skb->len) <= frame->length))
@@ -769,7 +775,10 @@ lowpan_process_data(struct sk_buff *skb)
dev_kfree_skb(skb);
skb = frame->skb;
kfree(frame);
iphc0 = lowpan_fetch_skb_u8(skb);

if (lowpan_fetch_skb_u8(skb, &iphc0))
goto unlock_and_drop;

break;
}
spin_unlock(&flist_lock);
@@ -780,7 +789,8 @@ lowpan_process_data(struct sk_buff *skb)
break;
}

iphc1 = lowpan_fetch_skb_u8(skb);
if (lowpan_fetch_skb_u8(skb, &iphc1))
goto drop;

_saddr = mac_cb(skb)->sa.hwaddr;
_daddr = mac_cb(skb)->da.hwaddr;
@@ -791,9 +801,8 @@ lowpan_process_data(struct sk_buff *skb)
if (iphc1 & LOWPAN_IPHC_CID) {
pr_debug("(%s): CID flag is set, increase header with one\n",
__func__);
if (!skb->len)
if (lowpan_fetch_skb_u8(skb, &num_context))
goto drop;
num_context = lowpan_fetch_skb_u8(skb);
}

hdr.version = 6;
@@ -805,9 +814,9 @@ lowpan_process_data(struct sk_buff *skb)
* ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
*/
case 0: /* 00b */
if (!skb->len)
if (lowpan_fetch_skb_u8(skb, &tmp))
goto drop;
tmp = lowpan_fetch_skb_u8(skb);

memcpy(&hdr.flow_lbl, &skb->data[0], 3);
skb_pull(skb, 3);
hdr.priority = ((tmp >> 2) & 0x0f);
@@ -819,9 +828,9 @@ lowpan_process_data(struct sk_buff *skb)
* ECN + DSCP (1 byte), Flow Label is elided
*/
case 1: /* 10b */
if (!skb->len)
if (lowpan_fetch_skb_u8(skb, &tmp))
goto drop;
tmp = lowpan_fetch_skb_u8(skb);

hdr.priority = ((tmp >> 2) & 0x0f);
hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
hdr.flow_lbl[1] = 0;
@@ -832,9 +841,9 @@ lowpan_process_data(struct sk_buff *skb)
* ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
*/
case 2: /* 01b */
if (!skb->len)
if (lowpan_fetch_skb_u8(skb, &tmp))
goto drop;
tmp = lowpan_fetch_skb_u8(skb);

hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
skb_pull(skb, 2);
@@ -853,9 +862,9 @@ lowpan_process_data(struct sk_buff *skb)
/* Next Header */
if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
/* Next header is carried inline */
if (!skb->len)
if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
goto drop;
hdr.nexthdr = lowpan_fetch_skb_u8(skb);

pr_debug("(%s): NH flag is set, next header is carried "
"inline: %02x\n", __func__, hdr.nexthdr);
}
@@ -864,9 +873,8 @@ lowpan_process_data(struct sk_buff *skb)
if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
else {
if (!skb->len)
if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
goto drop;
hdr.hop_limit = lowpan_fetch_skb_u8(skb);
}

/* Extract SAM to the tmp variable */
@@ -894,10 +902,8 @@ lowpan_process_data(struct sk_buff *skb)
pr_debug("(%s): destination address non-context-based"
" multicast compression\n", __func__);
if (0 < tmp && tmp < 3) {
if (!skb->len)
if (lowpan_fetch_skb_u8(skb, &prefix[1]))
goto drop;
else
prefix[1] = lowpan_fetch_skb_u8(skb);
}

err = lowpan_uncompress_addr(skb, &hdr.daddr, prefix,

0 comments on commit c5d3687

Please sign in to comment.