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: Alexander Smirnov <alex.bluesman.smirnov@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1d5873e9d7
commit
c5d3687f6c
@ -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;
|
||||
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);
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user