diff options
author | Eric Dumazet <edumazet@google.com> | 2013-05-24 01:49:58 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-05-26 02:26:30 -0400 |
commit | a622260254ee481747cceaaa8609985b29a31565 (patch) | |
tree | f93bf1a22f058b9fb55aed01a346102e57357940 /net/ipv4 | |
parent | 0d8c3e77e7fba8c84c871b43f35029daa92acc17 (diff) |
ip_tunnel: fix kernel panic with icmp_dest_unreach
Daniel Petre reported crashes in icmp_dst_unreach() with following call
graph:
#3 [ffff88003fc03938] __stack_chk_fail at ffffffff81037f77
#4 [ffff88003fc03948] icmp_send at ffffffff814d5fec
#5 [ffff88003fc03ae8] ipv4_link_failure at ffffffff814a1795
#6 [ffff88003fc03af8] ipgre_tunnel_xmit at ffffffff814e7965
#7 [ffff88003fc03b78] dev_hard_start_xmit at ffffffff8146e032
#8 [ffff88003fc03bc8] sch_direct_xmit at ffffffff81487d66
#9 [ffff88003fc03c08] __qdisc_run at ffffffff81487efd
#10 [ffff88003fc03c48] dev_queue_xmit at ffffffff8146e5a7
#11 [ffff88003fc03c88] ip_finish_output at ffffffff814ab596
Daniel found a similar problem mentioned in
http://lkml.indiana.edu/hypermail/linux/kernel/1007.0/00961.html
And indeed this is the root cause : skb->cb[] contains data fooling IP
stack.
We must clear IPCB in ip_tunnel_xmit() sooner in case dst_link_failure()
is called. Or else skb->cb[] might contain garbage from GSO segmentation
layer.
A similar fix was tested on linux-3.9, but gre code was refactored in
linux-3.10. I'll send patches for stable kernels as well.
Many thanks to Daniel for providing reports, patches and testing !
Reported-by: Daniel Petre <daniel.petre@rcs-rds.ro>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/ip_tunnel.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index e4147ec1665a..be2f8da0ae8e 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c | |||
@@ -503,6 +503,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
503 | 503 | ||
504 | inner_iph = (const struct iphdr *)skb_inner_network_header(skb); | 504 | inner_iph = (const struct iphdr *)skb_inner_network_header(skb); |
505 | 505 | ||
506 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | ||
506 | dst = tnl_params->daddr; | 507 | dst = tnl_params->daddr; |
507 | if (dst == 0) { | 508 | if (dst == 0) { |
508 | /* NBMA tunnel */ | 509 | /* NBMA tunnel */ |
@@ -658,7 +659,6 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | |||
658 | 659 | ||
659 | skb_dst_drop(skb); | 660 | skb_dst_drop(skb); |
660 | skb_dst_set(skb, &rt->dst); | 661 | skb_dst_set(skb, &rt->dst); |
661 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | ||
662 | 662 | ||
663 | /* Push down and install the IP header. */ | 663 | /* Push down and install the IP header. */ |
664 | skb_push(skb, sizeof(struct iphdr)); | 664 | skb_push(skb, sizeof(struct iphdr)); |