* (patch needs review) NULL dereference in xfrm_output with NAT
@ 2014-04-02 10:37 Martin Pelikan
2014-04-04 9:02 ` Steffen Klassert
0 siblings, 1 reply; 5+ messages in thread
From: Martin Pelikan @ 2014-04-02 10:37 UTC (permalink / raw)
To: netdev
Hi!
There was a protection fault caused by nf_xfrm_me_harder. The xfrm layer
shouldn't have been drinking during its packets' preNATal period, because
the packets can MASQUERADE and give the layer complications during output.
BUG: unable to handle kernel NULL pointer dereference at 00000000000002d0
IP: [<ffffffff81945458>] xfrm_output_resume+0x1c8/0x3a0
PGD 22dafe067 PUD 2306ac067 PMD 0
Oops: 0000 [#1] SMP
CPU: 7 PID: 3087 Comm: ping Not tainted 3.14.0-gentoo #1
Hardware name: Gigabyte Technology Co., Ltd. To be filled by O.E.M./970A-DS3P, BIOS F1 04/08/2013
task: ffff8802341333c0 ti: ffff88022d8ca000 task.ti: ffff88022d8ca000
RIP: 0010:[<ffffffff81945458>] [<ffffffff81945458>] xfrm_output_resume+0x1c8/0x3a0
RSP: 0018:ffff88022d8cba68 EFLAGS: 00010286
RAX: 0000000000000000 RBX: ffff880230702600 RCX: 0000000000000000
RDX: 00000000fffffde4 RSI: 0000000000000000 RDI: ffff880230702600
RBP: ffff88022d8cba90 R08: 0000000000000286 R09: 000000009744b544
R10: ffff88022f32fb60 R11: 0000000000000002 R12: 0000000000000001
R13: 0000000000000000 R14: ffff88023043b800 R15: 0000000000000000
FS: 00007f53a4573700(0000) GS:ffff88023edc0000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00000000000002d0 CR3: 000000022dafd000 CR4: 00000000000407e0
Stack:
ffff88022d8cbad0 ffff880230702600 ffff880230702600 ffff88022d8cbf18
ffff88023043b800 ffff88022d8cbac0 ffffffff8194567d ffffffff81ee64c0
ffff880230702600 ffffffff8197eba0 ffff88022d8cbf18 ffff88022d8cbad0
Call Trace:
[<ffffffff8194567d>] xfrm_output+0x3d/0x100
[<ffffffff8197eba0>] ? xfrm6_prepare_output+0x60/0x60
[<ffffffff8197ebb7>] xfrm6_output_finish+0x17/0x20
[<ffffffff8193c006>] xfrm4_output+0x46/0x80
[<ffffffff818e7bb0>] ip_local_out+0x20/0x30
[<ffffffff818e9cc0>] ip_send_skb+0x10/0x40
[<ffffffff818e9d1d>] ip_push_pending_frames+0x2d/0x30
[<ffffffff8190d071>] raw_sendmsg+0x7b1/0x900
[<ffffffff8195fd09>] ? ip6_route_output+0x69/0xb0
[<ffffffff81919eed>] inet_sendmsg+0x5d/0xa0
[<ffffffff81851208>] sock_sendmsg+0x88/0xc0
[<ffffffff8113ea64>] ? ttwu_do_wakeup+0x14/0xc0
[<ffffffff811c2100>] ? find_get_page+0x80/0xc0
[<ffffffff81850cf4>] ? move_addr_to_kernel+0x24/0x40
[<ffffffff81851798>] ___sys_sendmsg+0x3d8/0x3e0
[<ffffffff811d00f9>] ? lru_cache_add+0x9/0x10
[<ffffffff811eb7d3>] ? handle_mm_fault+0x6d3/0xa60
[<ffffffff8108b344>] ? __do_page_fault+0x234/0x4d0
[<ffffffff818525cd>] __sys_sendmsg+0x3d/0x80
[<ffffffff8185261d>] SyS_sendmsg+0xd/0x20
[<ffffffff819ddbb9>] system_call_fastpath+0x16/0x1b
Code: 00 00 00 4c 89 e0 48 83 e0 fe e9 88 fe ff ff 0f 1f 40 00 85 f6 0f 8f d7 fe ff ff 31 f6 85 d2 0f 8f cd fe ff ff 66 0f 1f 44 00 00 <49> 8b 85 d0 02 00 00 48 89 de 4c 89 ef ff 50 18 85 c0 41 89 c4
RIP [<ffffffff81945458>] xfrm_output_resume+0x1c8/0x3a0
RSP <ffff88022d8cba68>
CR2: 00000000000002d0
---[ end trace 2deb078a5e49b29c ]---
Obviously, this was caused by a packet being sent into an IPv4 flow in an
IPv6 tunnel, on which a postrouting nftables SNAT rule was applied. That
rule changed the packet's mind about going through the tunnel, but it was
too late. xfrm_output_one() does indeed check the validity of xfrm_state
in the chain of dst_entry's, but not the first one (Assuming if something
got into xfrm layer means it actually wants at least one transform?)
Comments? Fix below, but people need to re-check if it's the right spot.
If you agree and can put your name on it, send me and e-mail and I'll try
to send a patch from git.
--
Martin Pelikan
--- ./net/xfrm/xfrm_output.c 2014-04-02 11:27:04.597375669 +0200
+++ ./net/xfrm/xfrm_output.c 2014-04-02 11:26:33.399378335 +0200
@@ -46,6 +46,10 @@
if (err <= 0)
goto resume;
+
+ /* Netfilter NAT can make us not to do even the first transform. */
+ if (x == NULL)
+ return 0;
do {
err = xfrm_skb_check_space(skb);
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: (patch needs review) NULL dereference in xfrm_output with NAT
2014-04-02 10:37 (patch needs review) NULL dereference in xfrm_output with NAT Martin Pelikan
@ 2014-04-04 9:02 ` Steffen Klassert
2014-04-04 12:29 ` Martin Pelikan
0 siblings, 1 reply; 5+ messages in thread
From: Steffen Klassert @ 2014-04-04 9:02 UTC (permalink / raw)
To: Martin Pelikan; +Cc: netdev
On Wed, Apr 02, 2014 at 12:37:11PM +0200, Martin Pelikan wrote:
> Hi!
>
> There was a protection fault caused by nf_xfrm_me_harder. The xfrm layer
> shouldn't have been drinking during its packets' preNATal period, because
> the packets can MASQUERADE and give the layer complications during output.
>
Thanks for the report! Looks like IPv6 does not handle NAT rerouted
IPsec interfamily packets correctly. We also have this problem with
the new IPv6 NAT support.
>
> Obviously, this was caused by a packet being sent into an IPv4 flow in an
> IPv6 tunnel, on which a postrouting nftables SNAT rule was applied. That
> rule changed the packet's mind about going through the tunnel, but it was
> too late. xfrm_output_one() does indeed check the validity of xfrm_state
> in the chain of dst_entry's, but not the first one (Assuming if something
> got into xfrm layer means it actually wants at least one transform?)
>
> Comments? Fix below, but people need to re-check if it's the right spot.
> If you agree and can put your name on it, send me and e-mail and I'll try
> to send a patch from git.
> --
> Martin Pelikan
>
>
> --- ./net/xfrm/xfrm_output.c 2014-04-02 11:27:04.597375669 +0200
> +++ ./net/xfrm/xfrm_output.c 2014-04-02 11:26:33.399378335 +0200
> @@ -46,6 +46,10 @@
>
> if (err <= 0)
> goto resume;
> +
> + /* Netfilter NAT can make us not to do even the first transform. */
> + if (x == NULL)
> + return 0;
>
Just returning 0 here is not sufficient, we need to dst_output() the
packet to its new destination. Does the patch below fix your problem?
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index baa0f63..52df0e6 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -62,10 +62,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
if (err)
return err;
- memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
- IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
-
- skb->protocol = htons(ETH_P_IP);
+ IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
return x->outer_mode->output2(x, skb);
}
@@ -73,27 +70,36 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
int xfrm4_output_finish(struct sk_buff *skb)
{
+ memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+ skb->protocol = htons(ETH_P_IP);
+
#ifdef CONFIG_NETFILTER
- if (!skb_dst(skb)->xfrm) {
+ IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+#endif
+
+ return xfrm_output(skb);
+}
+
+static int __xfrm4_output(struct sk_buff *skb)
+{
+ struct xfrm_state *x = skb_dst(skb)->xfrm;
+
+#ifdef CONFIG_NETFILTER
+ if (!x) {
IPCB(skb)->flags |= IPSKB_REROUTED;
return dst_output(skb);
}
-
- IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
#endif
- skb->protocol = htons(ETH_P_IP);
- return xfrm_output(skb);
+ return x->outer_mode->afinfo->output_finish(skb);
}
int xfrm4_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
- struct xfrm_state *x = dst->xfrm;
return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb,
- NULL, dst->dev,
- x->outer_mode->afinfo->output_finish,
+ NULL, dst->dev, __xfrm4_output,
!(IPCB(skb)->flags & IPSKB_REROUTED));
}
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 6cd625e..ba62433 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
if (err)
return err;
- memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
-#ifdef CONFIG_NETFILTER
- IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
-#endif
-
- skb->protocol = htons(ETH_P_IPV6);
skb->local_df = 1;
return x->outer_mode->output2(x, skb);
@@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
int xfrm6_output_finish(struct sk_buff *skb)
{
+ memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+ skb->protocol = htons(ETH_P_IPV6);
+
#ifdef CONFIG_NETFILTER
IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
#endif
- skb->protocol = htons(ETH_P_IPV6);
return xfrm_output(skb);
}
@@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff *skb)
struct xfrm_state *x = dst->xfrm;
int mtu;
+#ifdef CONFIG_NETFILTER
+ if (!x) {
+ IP6CB(skb)->flags |= IP6SKB_REROUTED;
+ return dst_output(skb);
+ }
+#endif
+
if (skb->protocol == htons(ETH_P_IPV6))
mtu = ip6_skb_dst_mtu(skb);
else
@@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff *skb)
int xfrm6_output(struct sk_buff *skb)
{
- return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
- skb_dst(skb)->dev, __xfrm6_output);
+ return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb,
+ NULL, skb_dst(skb)->dev, __xfrm6_output,
+ !(IP6CB(skb)->flags & IP6SKB_REROUTED));
}
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: (patch needs review) NULL dereference in xfrm_output with NAT
2014-04-04 9:02 ` Steffen Klassert
@ 2014-04-04 12:29 ` Martin Pelikan
2014-04-07 10:55 ` Steffen Klassert
2014-04-08 7:31 ` Steffen Klassert
0 siblings, 2 replies; 5+ messages in thread
From: Martin Pelikan @ 2014-04-04 12:29 UTC (permalink / raw)
To: Steffen Klassert; +Cc: netdev
> Just returning 0 here is not sufficient, we need to dst_output() the
> packet to its new destination. Does the patch below fix your problem?
Your patch avoids the crash the same way as mine, but doesn't fix my related
problem: I have two flows through that IPv6 endpoint: IPv6 default gw tunnel
+ IPv4 tunnel between two private networks. But only one of them works at a
time, and it is the one which was set up first.
The other endpoint is OpenBSD with iked(8) and I can see the replies going
into enc0 there, ESP packets arriving into this Linux box at enp4s6, but the
traffic isn't being decapsulated and sent further away on br0.
If I disable the working tunnel (v6 for example), the other one (v4) starts
working immediately, so it's probably not caused by bad strongSwan config.
Do you think these bugs might be related? Any ideas how to proceed without
spending days on it? This doesn't work with either diff, but as a crash
fix, I'm fine with yours.
Thanks!
--
Martin Pelikan
> diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
> index baa0f63..52df0e6 100644
> --- a/net/ipv4/xfrm4_output.c
> +++ b/net/ipv4/xfrm4_output.c
> @@ -62,10 +62,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
> if (err)
> return err;
>
> - memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
> - IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
> -
> - skb->protocol = htons(ETH_P_IP);
> + IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
>
> return x->outer_mode->output2(x, skb);
> }
> @@ -73,27 +70,36 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
>
> int xfrm4_output_finish(struct sk_buff *skb)
> {
> + memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
> + skb->protocol = htons(ETH_P_IP);
> +
> #ifdef CONFIG_NETFILTER
> - if (!skb_dst(skb)->xfrm) {
> + IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
> +#endif
> +
> + return xfrm_output(skb);
> +}
> +
> +static int __xfrm4_output(struct sk_buff *skb)
> +{
> + struct xfrm_state *x = skb_dst(skb)->xfrm;
> +
> +#ifdef CONFIG_NETFILTER
> + if (!x) {
> IPCB(skb)->flags |= IPSKB_REROUTED;
> return dst_output(skb);
> }
> -
> - IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
> #endif
>
> - skb->protocol = htons(ETH_P_IP);
> - return xfrm_output(skb);
> + return x->outer_mode->afinfo->output_finish(skb);
> }
>
> int xfrm4_output(struct sk_buff *skb)
> {
> struct dst_entry *dst = skb_dst(skb);
> - struct xfrm_state *x = dst->xfrm;
>
> return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb,
> - NULL, dst->dev,
> - x->outer_mode->afinfo->output_finish,
> + NULL, dst->dev, __xfrm4_output,
> !(IPCB(skb)->flags & IPSKB_REROUTED));
> }
>
> diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
> index 6cd625e..ba62433 100644
> --- a/net/ipv6/xfrm6_output.c
> +++ b/net/ipv6/xfrm6_output.c
> @@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
> if (err)
> return err;
>
> - memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
> -#ifdef CONFIG_NETFILTER
> - IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
> -#endif
> -
> - skb->protocol = htons(ETH_P_IPV6);
> skb->local_df = 1;
>
> return x->outer_mode->output2(x, skb);
> @@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
>
> int xfrm6_output_finish(struct sk_buff *skb)
> {
> + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
> + skb->protocol = htons(ETH_P_IPV6);
> +
> #ifdef CONFIG_NETFILTER
> IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
> #endif
>
> - skb->protocol = htons(ETH_P_IPV6);
> return xfrm_output(skb);
> }
>
> @@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff *skb)
> struct xfrm_state *x = dst->xfrm;
> int mtu;
>
> +#ifdef CONFIG_NETFILTER
> + if (!x) {
> + IP6CB(skb)->flags |= IP6SKB_REROUTED;
> + return dst_output(skb);
> + }
> +#endif
> +
> if (skb->protocol == htons(ETH_P_IPV6))
> mtu = ip6_skb_dst_mtu(skb);
> else
> @@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff *skb)
>
> int xfrm6_output(struct sk_buff *skb)
> {
> - return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
> - skb_dst(skb)->dev, __xfrm6_output);
> + return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb,
> + NULL, skb_dst(skb)->dev, __xfrm6_output,
> + !(IP6CB(skb)->flags & IP6SKB_REROUTED));
> }
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: (patch needs review) NULL dereference in xfrm_output with NAT
2014-04-04 12:29 ` Martin Pelikan
@ 2014-04-07 10:55 ` Steffen Klassert
2014-04-08 7:31 ` Steffen Klassert
1 sibling, 0 replies; 5+ messages in thread
From: Steffen Klassert @ 2014-04-07 10:55 UTC (permalink / raw)
To: Martin Pelikan; +Cc: netdev
On Fri, Apr 04, 2014 at 02:29:17PM +0200, Martin Pelikan wrote:
>
> Your patch avoids the crash the same way as mine, but doesn't fix my related
> problem: I have two flows through that IPv6 endpoint: IPv6 default gw tunnel
> + IPv4 tunnel between two private networks. But only one of them works at a
> time, and it is the one which was set up first.
> The other endpoint is OpenBSD with iked(8) and I can see the replies going
> into enc0 there, ESP packets arriving into this Linux box at enp4s6, but the
> traffic isn't being decapsulated and sent further away on br0.
> If I disable the working tunnel (v6 for example), the other one (v4) starts
> working immediately, so it's probably not caused by bad strongSwan config.
>
> Do you think these bugs might be related? Any ideas how to proceed without
> spending days on it?
A good starting point for further debugging would be to find out
where the packets are dropped. xfrm increases a counter whenever
a packet is dropped in the xfrm layer. You can find these counters
in /proc/net/xfrm_stat.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: (patch needs review) NULL dereference in xfrm_output with NAT
2014-04-04 12:29 ` Martin Pelikan
2014-04-07 10:55 ` Steffen Klassert
@ 2014-04-08 7:31 ` Steffen Klassert
1 sibling, 0 replies; 5+ messages in thread
From: Steffen Klassert @ 2014-04-08 7:31 UTC (permalink / raw)
To: Martin Pelikan; +Cc: netdev
On Fri, Apr 04, 2014 at 02:29:17PM +0200, Martin Pelikan wrote:
>
> Your patch avoids the crash the same way as mine
I've applied the following fix to the ipsec tree.
Subject: [PATCH] xfrm: Fix crash with ipv6 IPsec tunnel and NAT.
The ipv6 xfrm output path is not aware that packets can be
rerouted by NAT to not use IPsec. We crash in this case
because we expect to have a xfrm state at the dst_entry.
This crash happens if the ipv6 layer does IPsec and NAT
or if we have an interfamily IPsec tunnel with ipv4 NAT.
We fix this by checking for a NAT rerouted packet in each
address family and dst_output() to the new destination
in this case.
Reported-by: Martin Pelikan <martin.pelikan@gmail.com>
Tested-by: Martin Pelikan <martin.pelikan@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/ipv4/xfrm4_output.c | 32 ++++++++++++++++++--------------
net/ipv6/xfrm6_output.c | 22 +++++++++++++---------
2 files changed, 31 insertions(+), 23 deletions(-)
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index baa0f63..f3800bf 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -62,10 +62,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
if (err)
return err;
- memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
- IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
-
- skb->protocol = htons(ETH_P_IP);
+ IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
return x->outer_mode->output2(x, skb);
}
@@ -73,27 +70,34 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
int xfrm4_output_finish(struct sk_buff *skb)
{
+ memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+ skb->protocol = htons(ETH_P_IP);
+
+#ifdef CONFIG_NETFILTER
+ IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+#endif
+
+ return xfrm_output(skb);
+}
+
+static int __xfrm4_output(struct sk_buff *skb)
+{
+ struct xfrm_state *x = skb_dst(skb)->xfrm;
+
#ifdef CONFIG_NETFILTER
- if (!skb_dst(skb)->xfrm) {
+ if (!x) {
IPCB(skb)->flags |= IPSKB_REROUTED;
return dst_output(skb);
}
-
- IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
#endif
- skb->protocol = htons(ETH_P_IP);
- return xfrm_output(skb);
+ return x->outer_mode->afinfo->output_finish(skb);
}
int xfrm4_output(struct sk_buff *skb)
{
- struct dst_entry *dst = skb_dst(skb);
- struct xfrm_state *x = dst->xfrm;
-
return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb,
- NULL, dst->dev,
- x->outer_mode->afinfo->output_finish,
+ NULL, skb_dst(skb)->dev, __xfrm4_output,
!(IPCB(skb)->flags & IPSKB_REROUTED));
}
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 6cd625e..ba62433 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -114,12 +114,6 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
if (err)
return err;
- memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
-#ifdef CONFIG_NETFILTER
- IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
-#endif
-
- skb->protocol = htons(ETH_P_IPV6);
skb->local_df = 1;
return x->outer_mode->output2(x, skb);
@@ -128,11 +122,13 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
int xfrm6_output_finish(struct sk_buff *skb)
{
+ memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+ skb->protocol = htons(ETH_P_IPV6);
+
#ifdef CONFIG_NETFILTER
IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
#endif
- skb->protocol = htons(ETH_P_IPV6);
return xfrm_output(skb);
}
@@ -142,6 +138,13 @@ static int __xfrm6_output(struct sk_buff *skb)
struct xfrm_state *x = dst->xfrm;
int mtu;
+#ifdef CONFIG_NETFILTER
+ if (!x) {
+ IP6CB(skb)->flags |= IP6SKB_REROUTED;
+ return dst_output(skb);
+ }
+#endif
+
if (skb->protocol == htons(ETH_P_IPV6))
mtu = ip6_skb_dst_mtu(skb);
else
@@ -165,6 +168,7 @@ static int __xfrm6_output(struct sk_buff *skb)
int xfrm6_output(struct sk_buff *skb)
{
- return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
- skb_dst(skb)->dev, __xfrm6_output);
+ return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb,
+ NULL, skb_dst(skb)->dev, __xfrm6_output,
+ !(IP6CB(skb)->flags & IP6SKB_REROUTED));
}
--
1.7.9.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2014-04-08 7:32 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-02 10:37 (patch needs review) NULL dereference in xfrm_output with NAT Martin Pelikan
2014-04-04 9:02 ` Steffen Klassert
2014-04-04 12:29 ` Martin Pelikan
2014-04-07 10:55 ` Steffen Klassert
2014-04-08 7:31 ` Steffen Klassert
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).