]>
Commit | Line | Data |
---|---|---|
a9fba688 SL |
1 | From d70f0c5c48ecf74f6d6a5ef0b786419999d46723 Mon Sep 17 00:00:00 2001 |
2 | From: Junwei Hu <hujunwei4@huawei.com> | |
3 | Date: Tue, 2 Apr 2019 19:38:04 +0800 | |
4 | Subject: ipv6: Fix dangling pointer when ipv6 fragment | |
5 | ||
6 | [ Upstream commit ef0efcd3bd3fd0589732b67fb586ffd3c8705806 ] | |
7 | ||
8 | At the beginning of ip6_fragment func, the prevhdr pointer is | |
9 | obtained in the ip6_find_1stfragopt func. | |
10 | However, all the pointers pointing into skb header may change | |
11 | when calling skb_checksum_help func with | |
12 | skb->ip_summed = CHECKSUM_PARTIAL condition. | |
13 | The prevhdr pointe will be dangling if it is not reloaded after | |
14 | calling __skb_linearize func in skb_checksum_help func. | |
15 | ||
16 | Here, I add a variable, nexthdr_offset, to evaluate the offset, | |
17 | which does not changes even after calling __skb_linearize func. | |
18 | ||
19 | Fixes: 405c92f7a541 ("ipv6: add defensive check for CHECKSUM_PARTIAL skbs in ip_fragment") | |
20 | Signed-off-by: Junwei Hu <hujunwei4@huawei.com> | |
21 | Reported-by: Wenhao Zhang <zhangwenhao8@huawei.com> | |
22 | Reported-by: syzbot+e8ce541d095e486074fc@syzkaller.appspotmail.com | |
23 | Reviewed-by: Zhiqiang Liu <liuzhiqiang26@huawei.com> | |
24 | Acked-by: Martin KaFai Lau <kafai@fb.com> | |
25 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
26 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
27 | --- | |
28 | net/ipv6/ip6_output.c | 4 +++- | |
29 | 1 file changed, 3 insertions(+), 1 deletion(-) | |
30 | ||
31 | diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c | |
32 | index 0bb87f3a10c7..eed9231c90ad 100644 | |
33 | --- a/net/ipv6/ip6_output.c | |
34 | +++ b/net/ipv6/ip6_output.c | |
35 | @@ -587,7 +587,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, | |
36 | inet6_sk(skb->sk) : NULL; | |
37 | struct ipv6hdr *tmp_hdr; | |
38 | struct frag_hdr *fh; | |
39 | - unsigned int mtu, hlen, left, len; | |
40 | + unsigned int mtu, hlen, left, len, nexthdr_offset; | |
41 | int hroom, troom; | |
42 | __be32 frag_id; | |
43 | int ptr, offset = 0, err = 0; | |
44 | @@ -598,6 +598,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, | |
45 | goto fail; | |
46 | hlen = err; | |
47 | nexthdr = *prevhdr; | |
48 | + nexthdr_offset = prevhdr - skb_network_header(skb); | |
49 | ||
50 | mtu = ip6_skb_dst_mtu(skb); | |
51 | ||
52 | @@ -632,6 +633,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, | |
53 | (err = skb_checksum_help(skb))) | |
54 | goto fail; | |
55 | ||
56 | + prevhdr = skb_network_header(skb) + nexthdr_offset; | |
57 | hroom = LL_RESERVED_SPACE(rt->dst.dev); | |
58 | if (skb_has_frag_list(skb)) { | |
59 | unsigned int first_len = skb_pagelen(skb); | |
60 | -- | |
61 | 2.19.1 | |
62 |