Skip to content
Permalink
Browse files

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>
  • Loading branch information...
qsn authored and davem330 committed Jul 19, 2017
1 parent 1e6c22a commit 6399f1fae4ec29fab5ec76070435555e256ca3a6
Showing with 6 additions and 2 deletions.
  1. +6 −2 net/ipv6/output_core.c
@@ -78,14 +78,15 @@ EXPORT_SYMBOL(ipv6_select_ident);

int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
{
u16 offset = sizeof(struct ipv6hdr);
unsigned int offset = sizeof(struct ipv6hdr);
unsigned int packet_len = skb_tail_pointer(skb) -
skb_network_header(skb);
int found_rhdr = 0;
*nexthdr = &ipv6_hdr(skb)->nexthdr;

while (offset <= packet_len) {
struct ipv6_opt_hdr *exthdr;
unsigned int len;

switch (**nexthdr) {

@@ -111,7 +112,10 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)

exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
offset);
offset += ipv6_optlen(exthdr);
len = ipv6_optlen(exthdr);
if (len + offset >= IPV6_MAXPLEN)
return -EINVAL;
offset += len;
*nexthdr = &exthdr->nexthdr;
}

0 comments on commit 6399f1f

Please sign in to comment.
You can’t perform that action at this time.