Commit c5d3687f authored by alex.bluesman.smirnov@gmail.com's avatar alex.bluesman.smirnov@gmail.com Committed by David S. Miller

6lowpan: read data from skb safely

Check if skb buffer can pull requested amount of bytes and return
an error in opposite case.
Signed-off-by: default avatarAlexander Smirnov <alex.bluesman.smirnov@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1d5873e9
...@@ -291,25 +291,26 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) ...@@ -291,25 +291,26 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
*hc06_ptr += 2; *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); 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; if (unlikely(!pskb_may_pull(skb, 2)))
return -EINVAL;
BUG_ON(!pskb_may_pull(skb, 2));
ret = skb->data[0] | (skb->data[1] << 8); *val = skb->data[0] | (skb->data[1] << 8);
skb_pull(skb, 2); skb_pull(skb, 2);
return ret;
return 0;
} }
static int static int
...@@ -318,7 +319,8 @@ lowpan_uncompress_udp_header(struct sk_buff *skb) ...@@ -318,7 +319,8 @@ lowpan_uncompress_udp_header(struct sk_buff *skb)
struct udphdr *uh = udp_hdr(skb); struct udphdr *uh = udp_hdr(skb);
u8 tmp; 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) { if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
pr_debug("(%s): UDP header uncompression\n", __func__); pr_debug("(%s): UDP header uncompression\n", __func__);
...@@ -710,7 +712,9 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -710,7 +712,9 @@ lowpan_process_data(struct sk_buff *skb)
/* at least two bytes will be used for the encoding */ /* at least two bytes will be used for the encoding */
if (skb->len < 2) if (skb->len < 2)
goto drop; goto drop;
iphc0 = lowpan_fetch_skb_u8(skb);
if (lowpan_fetch_skb_u8(skb, &iphc0))
goto drop;
/* fragments assembling */ /* fragments assembling */
switch (iphc0 & LOWPAN_DISPATCH_MASK) { switch (iphc0 & LOWPAN_DISPATCH_MASK) {
...@@ -722,8 +726,9 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -722,8 +726,9 @@ lowpan_process_data(struct sk_buff *skb)
u16 tag; u16 tag;
bool found = false; bool found = false;
len = lowpan_fetch_skb_u8(skb); /* frame length */ if (lowpan_fetch_skb_u8(skb, &len) || /* frame length */
tag = lowpan_fetch_skb_u16(skb); lowpan_fetch_skb_u16(skb, &tag)) /* fragment tag */
goto drop;
/* /*
* check if frame assembling with the same tag is * check if frame assembling with the same tag is
...@@ -747,7 +752,8 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -747,7 +752,8 @@ lowpan_process_data(struct sk_buff *skb)
if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1) if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1)
goto unlock_and_drop; 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 payload fits buffer, copy it */
if (likely((offset * 8 + skb->len) <= frame->length)) if (likely((offset * 8 + skb->len) <= frame->length))
...@@ -769,7 +775,10 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -769,7 +775,10 @@ lowpan_process_data(struct sk_buff *skb)
dev_kfree_skb(skb); dev_kfree_skb(skb);
skb = frame->skb; skb = frame->skb;
kfree(frame); kfree(frame);
iphc0 = lowpan_fetch_skb_u8(skb);
if (lowpan_fetch_skb_u8(skb, &iphc0))
goto unlock_and_drop;
break; break;
} }
spin_unlock(&flist_lock); spin_unlock(&flist_lock);
...@@ -780,7 +789,8 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -780,7 +789,8 @@ lowpan_process_data(struct sk_buff *skb)
break; break;
} }
iphc1 = lowpan_fetch_skb_u8(skb); if (lowpan_fetch_skb_u8(skb, &iphc1))
goto drop;
_saddr = mac_cb(skb)->sa.hwaddr; _saddr = mac_cb(skb)->sa.hwaddr;
_daddr = mac_cb(skb)->da.hwaddr; _daddr = mac_cb(skb)->da.hwaddr;
...@@ -791,9 +801,8 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -791,9 +801,8 @@ lowpan_process_data(struct sk_buff *skb)
if (iphc1 & LOWPAN_IPHC_CID) { if (iphc1 & LOWPAN_IPHC_CID) {
pr_debug("(%s): CID flag is set, increase header with one\n", pr_debug("(%s): CID flag is set, increase header with one\n",
__func__); __func__);
if (!skb->len) if (lowpan_fetch_skb_u8(skb, &num_context))
goto drop; goto drop;
num_context = lowpan_fetch_skb_u8(skb);
} }
hdr.version = 6; hdr.version = 6;
...@@ -805,9 +814,9 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -805,9 +814,9 @@ lowpan_process_data(struct sk_buff *skb)
* ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
*/ */
case 0: /* 00b */ case 0: /* 00b */
if (!skb->len) if (lowpan_fetch_skb_u8(skb, &tmp))
goto drop; goto drop;
tmp = lowpan_fetch_skb_u8(skb);
memcpy(&hdr.flow_lbl, &skb->data[0], 3); memcpy(&hdr.flow_lbl, &skb->data[0], 3);
skb_pull(skb, 3); skb_pull(skb, 3);
hdr.priority = ((tmp >> 2) & 0x0f); hdr.priority = ((tmp >> 2) & 0x0f);
...@@ -819,9 +828,9 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -819,9 +828,9 @@ lowpan_process_data(struct sk_buff *skb)
* ECN + DSCP (1 byte), Flow Label is elided * ECN + DSCP (1 byte), Flow Label is elided
*/ */
case 1: /* 10b */ case 1: /* 10b */
if (!skb->len) if (lowpan_fetch_skb_u8(skb, &tmp))
goto drop; goto drop;
tmp = lowpan_fetch_skb_u8(skb);
hdr.priority = ((tmp >> 2) & 0x0f); hdr.priority = ((tmp >> 2) & 0x0f);
hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
hdr.flow_lbl[1] = 0; hdr.flow_lbl[1] = 0;
...@@ -832,9 +841,9 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -832,9 +841,9 @@ lowpan_process_data(struct sk_buff *skb)
* ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
*/ */
case 2: /* 01b */ case 2: /* 01b */
if (!skb->len) if (lowpan_fetch_skb_u8(skb, &tmp))
goto drop; goto drop;
tmp = lowpan_fetch_skb_u8(skb);
hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
skb_pull(skb, 2); skb_pull(skb, 2);
...@@ -853,9 +862,9 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -853,9 +862,9 @@ lowpan_process_data(struct sk_buff *skb)
/* Next Header */ /* Next Header */
if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
/* Next header is carried inline */ /* Next header is carried inline */
if (!skb->len) if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
goto drop; goto drop;
hdr.nexthdr = lowpan_fetch_skb_u8(skb);
pr_debug("(%s): NH flag is set, next header is carried " pr_debug("(%s): NH flag is set, next header is carried "
"inline: %02x\n", __func__, hdr.nexthdr); "inline: %02x\n", __func__, hdr.nexthdr);
} }
...@@ -864,9 +873,8 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -864,9 +873,8 @@ lowpan_process_data(struct sk_buff *skb)
if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
else { else {
if (!skb->len) if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
goto drop; goto drop;
hdr.hop_limit = lowpan_fetch_skb_u8(skb);
} }
/* Extract SAM to the tmp variable */ /* Extract SAM to the tmp variable */
...@@ -894,10 +902,8 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -894,10 +902,8 @@ lowpan_process_data(struct sk_buff *skb)
pr_debug("(%s): destination address non-context-based" pr_debug("(%s): destination address non-context-based"
" multicast compression\n", __func__); " multicast compression\n", __func__);
if (0 < tmp && tmp < 3) { if (0 < tmp && tmp < 3) {
if (!skb->len) if (lowpan_fetch_skb_u8(skb, &prefix[1]))
goto drop; goto drop;
else
prefix[1] = lowpan_fetch_skb_u8(skb);
} }
err = lowpan_uncompress_addr(skb, &hdr.daddr, prefix, err = lowpan_uncompress_addr(skb, &hdr.daddr, prefix,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment