netfilter: ipv6: fix crash caused by ipv6_find_hdr()
When calling:
ipv6_find_hdr(skb, &thoff, -1, NULL)
on a fragmented packet, thoff would be left with a random
value causing callers to read random memory offsets with:
skb_header_pointer(skb, thoff, ...)
Now we force ipv6_find_hdr() to return a failure in this case.
Calling:
ipv6_find_hdr(skb, &thoff, -1, &fragoff)
will set fragoff as expected, and not return a failure.
Change-Id: Ib474e8a4267dd2b300feca325811330329684a88
Signed-off-by: JP Abgrall <jpa@google.com>
This commit is contained in:
@@ -2292,16 +2292,15 @@ static void __exit ip6_tables_fini(void)
|
||||
* "No next header".
|
||||
*
|
||||
* If target header is found, its offset is set in *offset and return protocol
|
||||
* number. Otherwise, return -1.
|
||||
* number. Otherwise, return -ENOENT or -EBADMSG.
|
||||
*
|
||||
* If the first fragment doesn't contain the final protocol header or
|
||||
* NEXTHDR_NONE it is considered invalid.
|
||||
*
|
||||
* Note that non-1st fragment is special case that "the protocol number
|
||||
* of last header" is "next header" field in Fragment header. In this case,
|
||||
* *offset is meaningless and fragment offset is stored in *fragoff if fragoff
|
||||
* isn't NULL.
|
||||
*
|
||||
* *offset is meaningless. If fragoff is not NULL, the fragment offset is
|
||||
* stored in *fragoff; if it is NULL, return -EINVAL.
|
||||
*/
|
||||
int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
|
||||
int target, unsigned short *fragoff)
|
||||
@@ -2342,9 +2341,12 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
|
||||
if (target < 0 &&
|
||||
((!ipv6_ext_hdr(hp->nexthdr)) ||
|
||||
hp->nexthdr == NEXTHDR_NONE)) {
|
||||
if (fragoff)
|
||||
if (fragoff) {
|
||||
*fragoff = _frag_off;
|
||||
return hp->nexthdr;
|
||||
return hp->nexthdr;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user