diff options
author | alex.bluesman.smirnov@gmail.com <alex.bluesman.smirnov@gmail.com> | 2012-06-24 23:49:01 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-06-25 19:40:31 -0400 |
commit | c5d3687f6cfed185c2c0b29a5b33273ebd2c0781 (patch) | |
tree | c5443136aa55edfbd19ba7b41b9aced35338c140 /net/ieee802154 | |
parent | 1d5873e9d75bb72012a6c1327a368d0d2b13581f (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.c | 70 |
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 | ||
294 | static u8 lowpan_fetch_skb_u8(struct sk_buff *skb) | 294 | static 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 | ||
304 | static u16 lowpan_fetch_skb_u16(struct sk_buff *skb) | 305 | static 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 | ||
315 | static int | 316 | static 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, |