aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/output_core.c')
-rw-r--r--net/ipv6/output_core.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
index 1d184322a7b1..f9f02581c4ca 100644
--- a/net/ipv6/output_core.c
+++ b/net/ipv6/output_core.c
@@ -78,15 +78,15 @@ EXPORT_SYMBOL(ipv6_select_ident);
78 78
79int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) 79int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
80{ 80{
81 u16 offset = sizeof(struct ipv6hdr); 81 unsigned int offset = sizeof(struct ipv6hdr);
82 struct ipv6_opt_hdr *exthdr =
83 (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
84 unsigned int packet_len = skb_tail_pointer(skb) - 82 unsigned int packet_len = skb_tail_pointer(skb) -
85 skb_network_header(skb); 83 skb_network_header(skb);
86 int found_rhdr = 0; 84 int found_rhdr = 0;
87 *nexthdr = &ipv6_hdr(skb)->nexthdr; 85 *nexthdr = &ipv6_hdr(skb)->nexthdr;
88 86
89 while (offset + 1 <= packet_len) { 87 while (offset <= packet_len) {
88 struct ipv6_opt_hdr *exthdr;
89 unsigned int len;
90 90
91 switch (**nexthdr) { 91 switch (**nexthdr) {
92 92
@@ -107,13 +107,19 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
107 return offset; 107 return offset;
108 } 108 }
109 109
110 offset += ipv6_optlen(exthdr); 110 if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
111 *nexthdr = &exthdr->nexthdr; 111 return -EINVAL;
112
112 exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) + 113 exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
113 offset); 114 offset);
115 len = ipv6_optlen(exthdr);
116 if (len + offset >= IPV6_MAXPLEN)
117 return -EINVAL;
118 offset += len;
119 *nexthdr = &exthdr->nexthdr;
114 } 120 }
115 121
116 return offset; 122 return -EINVAL;
117} 123}
118EXPORT_SYMBOL(ip6_find_1stfragopt); 124EXPORT_SYMBOL(ip6_find_1stfragopt);
119 125