1 commit 5596732fa8c14139018ecda8356eabbfb599d830
2 Author: Steffen Klassert <steffen.klassert@secunet.com>
3 Date: Mon Apr 7 08:08:52 2014 +0200
5 xfrm: Fix crash with ipv6 IPsec tunnel and NAT.
7 The ipv6 xfrm output path is not aware that packets can be
8 rerouted by NAT to not use IPsec. We crash in this case
9 because we expect to have a xfrm state at the dst_entry.
10 This crash happens if the ipv6 layer does IPsec and NAT
11 or if we have an interfamily IPsec tunnel with ipv4 NAT.
13 We fix this by checking for a NAT rerouted packet in each
14 address family and dst_output() to the new destination
17 Reported-by: Martin Pelikan <martin.pelikan@gmail.com>
18 Tested-by: Martin Pelikan <martin.pelikan@gmail.com>
19 Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
21 --- a/net/ipv4/xfrm4_output.c
22 +++ b/net/ipv4/xfrm4_output.c
23 @@ -62,10 +62,7 @@ int xfrm4_prepare_output(struct xfrm_sta
27 - memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
28 - IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
30 - skb->protocol = htons(ETH_P_IP);
31 + IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
33 return x->outer_mode->output2(x, skb);
35 @@ -73,27 +70,34 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
37 int xfrm4_output_finish(struct sk_buff *skb)
39 + memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
40 + skb->protocol = htons(ETH_P_IP);
42 +#ifdef CONFIG_NETFILTER
43 + IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
46 + return xfrm_output(skb);
49 +static int __xfrm4_output(struct sk_buff *skb)
51 + struct xfrm_state *x = skb_dst(skb)->xfrm;
53 #ifdef CONFIG_NETFILTER
54 - if (!skb_dst(skb)->xfrm) {
56 IPCB(skb)->flags |= IPSKB_REROUTED;
57 return dst_output(skb);
60 - IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
63 - skb->protocol = htons(ETH_P_IP);
64 - return xfrm_output(skb);
65 + return x->outer_mode->afinfo->output_finish(skb);
68 int xfrm4_output(struct sk_buff *skb)
70 - struct dst_entry *dst = skb_dst(skb);
71 - struct xfrm_state *x = dst->xfrm;
73 return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb,
75 - x->outer_mode->afinfo->output_finish,
76 + NULL, skb_dst(skb)->dev, __xfrm4_output,
77 !(IPCB(skb)->flags & IPSKB_REROUTED));
80 --- a/net/ipv6/xfrm6_output.c
81 +++ b/net/ipv6/xfrm6_output.c
82 @@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_sta
86 - memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
87 -#ifdef CONFIG_NETFILTER
88 - IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
91 - skb->protocol = htons(ETH_P_IPV6);
94 return x->outer_mode->output2(x, skb);
95 @@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
97 int xfrm6_output_finish(struct sk_buff *skb)
99 + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
100 + skb->protocol = htons(ETH_P_IPV6);
102 #ifdef CONFIG_NETFILTER
103 IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
106 - skb->protocol = htons(ETH_P_IPV6);
107 return xfrm_output(skb);
110 @@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff
111 struct xfrm_state *x = dst->xfrm;
114 +#ifdef CONFIG_NETFILTER
116 + IP6CB(skb)->flags |= IP6SKB_REROUTED;
117 + return dst_output(skb);
121 if (skb->protocol == htons(ETH_P_IPV6))
122 mtu = ip6_skb_dst_mtu(skb);
124 @@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff
126 int xfrm6_output(struct sk_buff *skb)
128 - return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
129 - skb_dst(skb)->dev, __xfrm6_output);
130 + return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb,
131 + NULL, skb_dst(skb)->dev, __xfrm6_output,
132 + !(IP6CB(skb)->flags & IP6SKB_REROUTED));