diff options
author | Sabrina Dubroca <sd@queasysnail.net> | 2017-07-19 16:28:55 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-07-20 01:50:14 -0400 |
commit | 6399f1fae4ec29fab5ec76070435555e256ca3a6 (patch) | |
tree | 3bf30f18bbd1c9eb4b37786cba7fe73e70ea014b | |
parent | 1e6c22aef28364dcc5f03c04a05ec463bc2b3431 (diff) |
ipv6: avoid overflow of offset in ip6_find_1stfragopt
In some cases, offset can overflow and can cause an infinite loop in
ip6_find_1stfragopt(). Make it unsigned int to prevent the overflow, and
cap it at IPV6_MAXPLEN, since packets larger than that should be invalid.
This problem has been here since before the beginning of git history.
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv6/output_core.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index e9065b8d3af8..abb2c307fbe8 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c | |||
@@ -78,7 +78,7 @@ EXPORT_SYMBOL(ipv6_select_ident); | |||
78 | 78 | ||
79 | int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | 79 | int 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 | unsigned int packet_len = skb_tail_pointer(skb) - | 82 | unsigned int packet_len = skb_tail_pointer(skb) - |
83 | skb_network_header(skb); | 83 | skb_network_header(skb); |
84 | int found_rhdr = 0; | 84 | int found_rhdr = 0; |
@@ -86,6 +86,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | |||
86 | 86 | ||
87 | while (offset <= packet_len) { | 87 | while (offset <= packet_len) { |
88 | struct ipv6_opt_hdr *exthdr; | 88 | struct ipv6_opt_hdr *exthdr; |
89 | unsigned int len; | ||
89 | 90 | ||
90 | switch (**nexthdr) { | 91 | switch (**nexthdr) { |
91 | 92 | ||
@@ -111,7 +112,10 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | |||
111 | 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); |
114 | offset += ipv6_optlen(exthdr); | 115 | len = ipv6_optlen(exthdr); |
116 | if (len + offset >= IPV6_MAXPLEN) | ||
117 | return -EINVAL; | ||
118 | offset += len; | ||
115 | *nexthdr = &exthdr->nexthdr; | 119 | *nexthdr = &exthdr->nexthdr; |
116 | } | 120 | } |
117 | 121 | ||