From: Denis V. Lunev <[email protected]>

vti6_init_net() frees the vti6_net of every container netns. vti6
tunnels cannot be created in a container, but the host can move one in
with "ip link set v6 netns <CT>". vti6_dellink() and
vti6_siocdevprivate() look ip6n up in dev_net(dev) and read
ip6n->fb_tnl_dev, so the node panics on a NULL pointer dereference when
container root deletes the tunnel or issues a tunnel ioctl on it, when
the container stops and cleanup_net() deletes it, or when ip6_vti is
unloaded. SIOCADDTUNNEL on such a device also walks the NULL hash in
vti6_locate().

Take the netns from t->net in both, as ip6_tunnel and sit do. For a
tunnel that was not moved t->net is dev_net(dev), so the host sees no
change. For a moved one the CAP_NET_ADMIN checks of the ioctls now run
against the creation netns and container root gets EPERM, as it does
for ip6tnl and sit; "ip link del" keeps working.

This relies on the backports of mainline 11b326fb0a37 ("ip6: vti: Use
ip6_tnl.net in vti6_changelink()."), which moves vti6_changelink() and
vti6_update() to t->net, and d289d5307762 ("ip6_vti: set
netns_immutable on the fallback device."), which keeps ip6_vti0 in its
netns so the fb_tnl_dev comparisons keep their meaning.

Fixes: b03d021d2fd6 ("ve/net: ip6_vti: skip per net init in ve")

https://virtuozzo.atlassian.net/browse/VSTOR-154348
Feature: net: whitelist allowed Container network devices
Signed-off-by: Denis V. Lunev <[email protected]>
---
 net/ipv6/ip6_vti.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index 420830c5e064..40c6298c8b13 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -805,8 +805,9 @@ vti6_siocdevprivate(struct net_device *dev, struct ifreq 
*ifr, void __user *data
        int err = 0;
        struct ip6_tnl_parm2 p;
        struct __ip6_tnl_parm p1;
+       struct ip6_tnl *self = netdev_priv(dev);
        struct ip6_tnl *t = NULL;
-       struct net *net = dev_net(dev);
+       struct net *net = self->net;
        struct vti6_net *ip6n = net_generic(net, vti6_net_id);
 
        memset(&p1, 0, sizeof(p1));
@@ -842,8 +843,6 @@ vti6_siocdevprivate(struct net_device *dev, struct ifreq 
*ifr, void __user *data
                        break;
                vti6_parm_from_user(&p1, &p);
                if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
-                       struct ip6_tnl *self = netdev_priv(dev);
-
                        err = -EPERM;
                        if (!ns_capable(self->net->user_ns, CAP_NET_ADMIN))
                                break;
@@ -1034,8 +1033,8 @@ static int vti6_newlink(struct net *src_net, struct 
net_device *dev,
 
 static void vti6_dellink(struct net_device *dev, struct list_head *head)
 {
-       struct net *net = dev_net(dev);
-       struct vti6_net *ip6n = net_generic(net, vti6_net_id);
+       struct ip6_tnl *t = netdev_priv(dev);
+       struct vti6_net *ip6n = net_generic(t->net, vti6_net_id);
 
        if (dev != ip6n->fb_tnl_dev)
                unregister_netdevice_queue(dev, head);
-- 
2.53.0

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to