Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+38 −32
Original line number Diff line number Diff line
@@ -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,