tunnel: Clear IPCB(skb)->opt before dst_link_failure called
authorBernie Harris <bernie.harris@alliedtelesis.co.nz>
Sun, 21 Feb 2016 23:58:05 +0000 (12:58 +1300)
committerSasha Levin <sasha.levin@oracle.com>
Mon, 11 Jul 2016 03:06:58 +0000 (23:06 -0400)
[ Upstream commit 5146d1f151122e868e594c7b45115d64825aee5f ]

IPCB may contain data from previous layers (in the observed case the
qdisc layer). In the observed scenario, the data was misinterpreted as
ip header options, which later caused the ihl to be set to an invalid
value (<5). This resulted in an infinite loop in the mips implementation
of ip_fast_csum.

This patch clears IPCB(skb)->opt before dst_link_failure can be called for
various types of tunnels. This change only applies to encapsulated ipv4
packets.

The code introduced in 11c21a30 which clears all of IPCB has been removed
to be consistent with these changes, and instead the opt field is cleared
unconditionally in ip_tunnel_xmit. The change in ip_tunnel_xmit applies to
SIT, GRE, and IPIP tunnels.

The relevant vti, l2tp, and pptp functions already contain similar code for
clearing the IPCB.

Signed-off-by: Bernie Harris <bernie.harris@alliedtelesis.co.nz>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
net/ipv4/ip_tunnel.c
net/ipv4/udp_tunnel.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_tunnel.c

index 626d9e56a6bd2671611f3dde4f8090b76645301c..35080a708b5956100369c7ac8576f6b62c7d19b5 100644 (file)
@@ -652,6 +652,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
        connected = (tunnel->parms.iph.daddr != 0);
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        dst = tnl_params->daddr;
        if (dst == 0) {
                /* NBMA tunnel */
@@ -749,7 +751,6 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                                tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
                        tunnel->err_count--;
 
-                       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
                        dst_link_failure(skb);
                } else
                        tunnel->err_count = 0;
index 6bb98cc193c9a1b532b668b34e9b401357ad96e1..7b534ac040560d6a608851019c5f62c1f560e2c2 100644 (file)
@@ -90,6 +90,8 @@ int udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
        uh->source = src_port;
        uh->len = htons(skb->len);
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        udp_set_csum(nocheck, skb, src, dst, skb->len);
 
        return iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP,
index 76be7d311cc4e1d40af8c23d6a3028db06beda16..b1311da5d7b8f41a3085eb41337f32addb6fc0cd 100644 (file)
@@ -783,6 +783,8 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
        __u32 mtu;
        int err;
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
                encap_limit = t->parms.encap_limit;
 
index 5cafd92c231270703af5bf948d131d99c5e9c193..6fd0f96fdac1e945779612777c187cb6f185b4d8 100644 (file)
@@ -1124,6 +1124,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        u8 tproto;
        int err;
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        tproto = ACCESS_ONCE(t->parms.proto);
        if (tproto != IPPROTO_IPIP && tproto != 0)
                return -1;