Skip to content

Commit

Permalink
tunnel: Clear IPCB(skb)->opt before dst_link_failure called
Browse files Browse the repository at this point in the history
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 11c21a3 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>
  • Loading branch information
Bernie Harris authored and David S. Miller committed Feb 24, 2016
1 parent 9bdfb3b commit 5146d1f
Show file tree
Hide file tree
Showing 4 changed files with 8 additions and 1 deletion.
3 changes: 2 additions & 1 deletion net/ipv4/ip_tunnel.c
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,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 */
Expand Down Expand Up @@ -758,7 +760,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;
Expand Down
2 changes: 2 additions & 0 deletions net/ipv4/udp_tunnel.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ void 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);

iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet);
Expand Down
2 changes: 2 additions & 0 deletions net/ipv6/ip6_gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,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;

Expand Down
2 changes: 2 additions & 0 deletions net/ipv6/ip6_tunnel.c
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,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;
Expand Down

0 comments on commit 5146d1f

Please sign in to comment.