ip_tunnel: fix kernel panic with icmp_dest_unreach
authorEric Dumazet <edumazet@google.com>
Fri, 24 May 2013 05:49:58 +0000 (05:49 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jun 2013 18:27:32 +0000 (11:27 -0700)
[ Upstream commit a622260254ee481747cceaaa8609985b29a31565 ]

Daniel Petre reported crashes in icmp_dst_unreach() with following call
graph:

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/ipv4/ip_gre.c
net/ipv4/ipip.c

index b57532d4742c7cccc95a05dd641bfc47875b4717..a16509cba75d8f79fda41b54f5bee0002dd002a4 100644 (file)
@@ -722,6 +722,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
                tiph = &tunnel->parms.iph;
        }
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        if ((dst = tiph->daddr) == 0) {
                /* NBMA tunnel */
 
@@ -865,7 +866,6 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
        skb_reset_transport_header(skb);
        skb_push(skb, gre_hlen);
        skb_reset_network_header(skb);
-       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
                              IPSKB_REROUTED);
        skb_dst_drop(skb);
index ae1413e3f2f8bd7a16ed73bdd327f908a6012a28..d2f634880bdd30b13d19e16710462e7f72f79e61 100644 (file)
@@ -448,6 +448,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (tos & 1)
                tos = old_iph->tos;
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        if (!dst) {
                /* NBMA tunnel */
                if ((rt = skb_rtable(skb)) == NULL) {
@@ -530,7 +531,6 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        skb->transport_header = skb->network_header;
        skb_push(skb, sizeof(struct iphdr));
        skb_reset_network_header(skb);
-       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
                              IPSKB_REROUTED);
        skb_dst_drop(skb);