]>
Commit | Line | Data |
---|---|---|
a9fba688 SL |
1 | From bd9983ed1e753eb3a30935c032446aa6c5a2d913 Mon Sep 17 00:00:00 2001 |
2 | From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com> | |
3 | Date: Sat, 6 Apr 2019 17:16:52 +0200 | |
4 | Subject: net: ip_gre: fix possible use-after-free in erspan_rcv | |
5 | ||
6 | [ Upstream commit 492b67e28ee5f2a2522fb72e3d3bcb990e461514 ] | |
7 | ||
8 | erspan tunnels run __iptunnel_pull_header on received skbs to remove | |
9 | gre and erspan headers. This can determine a possible use-after-free | |
10 | accessing pkt_md pointer in erspan_rcv since the packet will be 'uncloned' | |
11 | running pskb_expand_head if it is a cloned gso skb (e.g if the packet has | |
12 | been sent though a veth device). Fix it resetting pkt_md pointer after | |
13 | __iptunnel_pull_header | |
14 | ||
15 | Fixes: 1d7e2ed22f8d ("net: erspan: refactor existing erspan code") | |
16 | Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com> | |
17 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
18 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
19 | --- | |
20 | net/ipv4/ip_gre.c | 15 ++++++++++----- | |
21 | 1 file changed, 10 insertions(+), 5 deletions(-) | |
22 | ||
23 | diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c | |
24 | index f199945f6e4a..3c734832bb7c 100644 | |
25 | --- a/net/ipv4/ip_gre.c | |
26 | +++ b/net/ipv4/ip_gre.c | |
27 | @@ -260,7 +260,6 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, | |
28 | struct net *net = dev_net(skb->dev); | |
29 | struct metadata_dst *tun_dst = NULL; | |
30 | struct erspan_base_hdr *ershdr; | |
31 | - struct erspan_metadata *pkt_md; | |
32 | struct ip_tunnel_net *itn; | |
33 | struct ip_tunnel *tunnel; | |
34 | const struct iphdr *iph; | |
35 | @@ -283,9 +282,6 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, | |
36 | if (unlikely(!pskb_may_pull(skb, len))) | |
37 | return PACKET_REJECT; | |
38 | ||
39 | - ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); | |
40 | - pkt_md = (struct erspan_metadata *)(ershdr + 1); | |
41 | - | |
42 | if (__iptunnel_pull_header(skb, | |
43 | len, | |
44 | htons(ETH_P_TEB), | |
45 | @@ -293,8 +289,9 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, | |
46 | goto drop; | |
47 | ||
48 | if (tunnel->collect_md) { | |
49 | + struct erspan_metadata *pkt_md, *md; | |
50 | struct ip_tunnel_info *info; | |
51 | - struct erspan_metadata *md; | |
52 | + unsigned char *gh; | |
53 | __be64 tun_id; | |
54 | __be16 flags; | |
55 | ||
56 | @@ -307,6 +304,14 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, | |
57 | if (!tun_dst) | |
58 | return PACKET_REJECT; | |
59 | ||
60 | + /* skb can be uncloned in __iptunnel_pull_header, so | |
61 | + * old pkt_md is no longer valid and we need to reset | |
62 | + * it | |
63 | + */ | |
64 | + gh = skb_network_header(skb) + | |
65 | + skb_network_header_len(skb); | |
66 | + pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len + | |
67 | + sizeof(*ershdr)); | |
68 | md = ip_tunnel_info_opts(&tun_dst->u.tun_info); | |
69 | md->version = ver; | |
70 | md2 = &md->u.md2; | |
71 | -- | |
72 | 2.19.1 | |
73 |