tunnels: Fix tunnels change rcu protection
After making rcu protection for tunnels (ipip, gre, sit and ip6) a bug was introduced into the SIOCCHGTUNNEL code. The tunnel is first unlinked, then addresses change, then it is linked back probably into another bucket. But while changing the parms, the hash table is unlocked to readers and they can lookup the improper tunnel. Respective commits areb7285b79
(ipip: get rid of ipip_lock),1507850b
(gre: get rid of ipgre_lock),3a43be3c
(sit: get rid of ipip6_lock) and94767632
(ip6tnl: get rid of ip6_tnl_lock). The quick fix is to wait for quiescent state to pass after unlinking, but if it is inappropriate I can invent something better, just let me know. Signed-off-by: Pavel Emelyanov <xemul@openvz.org> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1933f0c094
commit
74b0b85b88
4 changed files with 4 additions and 0 deletions
|
@ -1072,6 +1072,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
break;
|
||||
}
|
||||
ipgre_tunnel_unlink(ign, t);
|
||||
synchronize_net();
|
||||
t->parms.iph.saddr = p.iph.saddr;
|
||||
t->parms.iph.daddr = p.iph.daddr;
|
||||
t->parms.i_key = p.i_key;
|
||||
|
|
|
@ -676,6 +676,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
}
|
||||
t = netdev_priv(dev);
|
||||
ipip_tunnel_unlink(ipn, t);
|
||||
synchronize_net();
|
||||
t->parms.iph.saddr = p.iph.saddr;
|
||||
t->parms.iph.daddr = p.iph.daddr;
|
||||
memcpy(dev->dev_addr, &p.iph.saddr, 4);
|
||||
|
|
|
@ -1284,6 +1284,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
t = netdev_priv(dev);
|
||||
|
||||
ip6_tnl_unlink(ip6n, t);
|
||||
synchronize_net();
|
||||
err = ip6_tnl_change(t, &p);
|
||||
ip6_tnl_link(ip6n, t);
|
||||
netdev_state_change(dev);
|
||||
|
|
|
@ -963,6 +963,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
}
|
||||
t = netdev_priv(dev);
|
||||
ipip6_tunnel_unlink(sitn, t);
|
||||
synchronize_net();
|
||||
t->parms.iph.saddr = p.iph.saddr;
|
||||
t->parms.iph.daddr = p.iph.daddr;
|
||||
memcpy(dev->dev_addr, &p.iph.saddr, 4);
|
||||
|
|
Loading…
Reference in a new issue