aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154
diff options
context:
space:
mode:
authoralex.bluesman.smirnov@gmail.com <alex.bluesman.smirnov@gmail.com>2012-06-24 23:49:01 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-25 19:40:31 -0400
commitc5d3687f6cfed185c2c0b29a5b33273ebd2c0781 (patch)
treec5443136aa55edfbd19ba7b41b9aced35338c140 /net/ieee802154
parent1d5873e9d75bb72012a6c1327a368d0d2b13581f (diff)
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>
Diffstat (limited to 'net/ieee802154')
-rw-r--r--net/ieee802154/6lowpan.c70
1 files changed, 38 insertions, 32 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 32eb4179e8fa..5c7bcf9663d3 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -291,25 +291,26 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
291 *hc06_ptr += 2; 291 *hc06_ptr += 2;
292} 292}
293 293
294static u8 lowpan_fetch_skb_u8(struct sk_buff *skb) 294static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
295{ 295{
296 u8 ret; 296 if (unlikely(!pskb_may_pull(skb, 1)))
297 return -EINVAL;
297 298
298 ret = skb->data[0]; 299 *val = skb->data[0];
299 skb_pull(skb, 1); 300 skb_pull(skb, 1);
300 301
301 return ret; 302 return 0;
302} 303}
303 304
304static u16 lowpan_fetch_skb_u16(struct sk_buff *skb) 305static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
305{ 306{
306 u16 ret; 307 if (unlikely(!pskb_may_pull(skb, 2)))
307 308 return -EINVAL;
308 BUG_ON(!pskb_may_pull(skb, 2));
309 309
310 ret = skb->data[0] | (skb->data[1] << 8); 310 *val = skb->data[0] | (skb->data[1] << 8);
311 skb_pull(skb, 2); 311 skb_pull(skb, 2);
312 return ret; 312
313 return 0;
313} 314}
314 315
315static int 316static int
@@ -318,7 +319,8 @@ lowpan_uncompress_udp_header(struct sk_buff *skb)
318 struct udphdr *uh = udp_hdr(skb); 319 struct udphdr *uh = udp_hdr(skb);
319 u8 tmp; 320 u8 tmp;
320 321
321 tmp = lowpan_fetch_skb_u8(skb); 322 if (lowpan_fetch_skb_u8(skb, &tmp))
323 goto err;
322 324
323 if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { 325 if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
324 pr_debug("(%s): UDP header uncompression\n", __func__); 326 pr_debug("(%s): UDP header uncompression\n", __func__);
@@ -710,7 +712,9 @@ lowpan_process_data(struct sk_buff *skb)
710 /* at least two bytes will be used for the encoding */ 712 /* at least two bytes will be used for the encoding */
711 if (skb->len < 2) 713 if (skb->len < 2)
712 goto drop; 714 goto drop;
713 iphc0 = lowpan_fetch_skb_u8(skb); 715
716 if (lowpan_fetch_skb_u8(skb, &iphc0))
717 goto drop;
714 718
715 /* fragments assembling */ 719 /* fragments assembling */
716 switch (iphc0 & LOWPAN_DISPATCH_MASK) { 720 switch (iphc0 & LOWPAN_DISPATCH_MASK) {
@@ -722,8 +726,9 @@ lowpan_process_data(struct sk_buff *skb)
722 u16 tag; 726 u16 tag;
723 bool found = false; 727 bool found = false;
724 728
725 len = lowpan_fetch_skb_u8(skb); /* frame length */ 729 if (lowpan_fetch_skb_u8(skb, &len) || /* frame length */
726 tag = lowpan_fetch_skb_u16(skb); 730 lowpan_fetch_skb_u16(skb, &tag)) /* fragment tag */
731 goto drop;
727 732
728 /* 733 /*
729 * check if frame assembling with the same tag is 734 * check if frame assembling with the same tag is
@@ -747,7 +752,8 @@ lowpan_process_data(struct sk_buff *skb)
747 if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1) 752 if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1)
748 goto unlock_and_drop; 753 goto unlock_and_drop;
749 754
750 offset = lowpan_fetch_skb_u8(skb); /* fetch offset */ 755 if (lowpan_fetch_skb_u8(skb, &offset)) /* fetch offset */
756 goto unlock_and_drop;
751 757
752 /* if payload fits buffer, copy it */ 758 /* if payload fits buffer, copy it */
753 if (likely((offset * 8 + skb->len) <= frame->length)) 759 if (likely((offset * 8 + skb->len) <= frame->length))
@@ -769,7 +775,10 @@ lowpan_process_data(struct sk_buff *skb)
769 dev_kfree_skb(skb); 775 dev_kfree_skb(skb);
770 skb = frame->skb; 776 skb = frame->skb;
771 kfree(frame); 777 kfree(frame);
772 iphc0 = lowpan_fetch_skb_u8(skb); 778
779 if (lowpan_fetch_skb_u8(skb, &iphc0))
780 goto unlock_and_drop;
781
773 break; 782 break;
774 } 783 }
775 spin_unlock(&flist_lock); 784 spin_unlock(&flist_lock);
@@ -780,7 +789,8 @@ lowpan_process_data(struct sk_buff *skb)
780 break; 789 break;
781 } 790 }
782 791
783 iphc1 = lowpan_fetch_skb_u8(skb); 792 if (lowpan_fetch_skb_u8(skb, &iphc1))
793 goto drop;
784 794
785 _saddr = mac_cb(skb)->sa.hwaddr; 795 _saddr = mac_cb(skb)->sa.hwaddr;
786 _daddr = mac_cb(skb)->da.hwaddr; 796 _daddr = mac_cb(skb)->da.hwaddr;
@@ -791,9 +801,8 @@ lowpan_process_data(struct sk_buff *skb)
791 if (iphc1 & LOWPAN_IPHC_CID) { 801 if (iphc1 & LOWPAN_IPHC_CID) {
792 pr_debug("(%s): CID flag is set, increase header with one\n", 802 pr_debug("(%s): CID flag is set, increase header with one\n",
793 __func__); 803 __func__);
794 if (!skb->len) 804 if (lowpan_fetch_skb_u8(skb, &num_context))
795 goto drop; 805 goto drop;
796 num_context = lowpan_fetch_skb_u8(skb);
797 } 806 }
798 807
799 hdr.version = 6; 808 hdr.version = 6;
@@ -805,9 +814,9 @@ lowpan_process_data(struct sk_buff *skb)
805 * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) 814 * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
806 */ 815 */
807 case 0: /* 00b */ 816 case 0: /* 00b */
808 if (!skb->len) 817 if (lowpan_fetch_skb_u8(skb, &tmp))
809 goto drop; 818 goto drop;
810 tmp = lowpan_fetch_skb_u8(skb); 819
811 memcpy(&hdr.flow_lbl, &skb->data[0], 3); 820 memcpy(&hdr.flow_lbl, &skb->data[0], 3);
812 skb_pull(skb, 3); 821 skb_pull(skb, 3);
813 hdr.priority = ((tmp >> 2) & 0x0f); 822 hdr.priority = ((tmp >> 2) & 0x0f);
@@ -819,9 +828,9 @@ lowpan_process_data(struct sk_buff *skb)
819 * ECN + DSCP (1 byte), Flow Label is elided 828 * ECN + DSCP (1 byte), Flow Label is elided
820 */ 829 */
821 case 1: /* 10b */ 830 case 1: /* 10b */
822 if (!skb->len) 831 if (lowpan_fetch_skb_u8(skb, &tmp))
823 goto drop; 832 goto drop;
824 tmp = lowpan_fetch_skb_u8(skb); 833
825 hdr.priority = ((tmp >> 2) & 0x0f); 834 hdr.priority = ((tmp >> 2) & 0x0f);
826 hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); 835 hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
827 hdr.flow_lbl[1] = 0; 836 hdr.flow_lbl[1] = 0;
@@ -832,9 +841,9 @@ lowpan_process_data(struct sk_buff *skb)
832 * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided 841 * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
833 */ 842 */
834 case 2: /* 01b */ 843 case 2: /* 01b */
835 if (!skb->len) 844 if (lowpan_fetch_skb_u8(skb, &tmp))
836 goto drop; 845 goto drop;
837 tmp = lowpan_fetch_skb_u8(skb); 846
838 hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); 847 hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
839 memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); 848 memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
840 skb_pull(skb, 2); 849 skb_pull(skb, 2);
@@ -853,9 +862,9 @@ lowpan_process_data(struct sk_buff *skb)
853 /* Next Header */ 862 /* Next Header */
854 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { 863 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
855 /* Next header is carried inline */ 864 /* Next header is carried inline */
856 if (!skb->len) 865 if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
857 goto drop; 866 goto drop;
858 hdr.nexthdr = lowpan_fetch_skb_u8(skb); 867
859 pr_debug("(%s): NH flag is set, next header is carried " 868 pr_debug("(%s): NH flag is set, next header is carried "
860 "inline: %02x\n", __func__, hdr.nexthdr); 869 "inline: %02x\n", __func__, hdr.nexthdr);
861 } 870 }
@@ -864,9 +873,8 @@ lowpan_process_data(struct sk_buff *skb)
864 if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) 873 if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
865 hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; 874 hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
866 else { 875 else {
867 if (!skb->len) 876 if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
868 goto drop; 877 goto drop;
869 hdr.hop_limit = lowpan_fetch_skb_u8(skb);
870 } 878 }
871 879
872 /* Extract SAM to the tmp variable */ 880 /* Extract SAM to the tmp variable */
@@ -894,10 +902,8 @@ lowpan_process_data(struct sk_buff *skb)
894 pr_debug("(%s): destination address non-context-based" 902 pr_debug("(%s): destination address non-context-based"
895 " multicast compression\n", __func__); 903 " multicast compression\n", __func__);
896 if (0 < tmp && tmp < 3) { 904 if (0 < tmp && tmp < 3) {
897 if (!skb->len) 905 if (lowpan_fetch_skb_u8(skb, &prefix[1]))
898 goto drop; 906 goto drop;
899 else
900 prefix[1] = lowpan_fetch_skb_u8(skb);
901 } 907 }
902 908
903 err = lowpan_uncompress_addr(skb, &hdr.daddr, prefix, 909 err = lowpan_uncompress_addr(skb, &hdr.daddr, prefix,