]> Pileus Git - ~andy/linux/commitdiff
net: Allow userns root to control ipv6
authorEric W. Biederman <ebiederm@xmission.com>
Fri, 16 Nov 2012 03:03:06 +0000 (03:03 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 19 Nov 2012 01:32:45 +0000 (20:32 -0500)
Allow an unpriviled user who has created a user namespace, and then
created a network namespace to effectively use the new network
namespace, by reducing capable(CAP_NET_ADMIN) and
capable(CAP_NET_RAW) calls to be ns_capable(net->user_ns,
CAP_NET_ADMIN), or capable(net->user_ns, CAP_NET_RAW) calls.

Settings that merely control a single network device are allowed.
Either the network device is a logical network device where
restrictions make no difference or the network device is hardware NIC
that has been explicity moved from the initial network namespace.

In general policy and network stack state changes are allowed while
resource control is left unchanged.

Allow the SIOCSIFADDR ioctl to add ipv6 addresses.
Allow the SIOCDIFADDR ioctl to delete ipv6 addresses.
Allow the SIOCADDRT ioctl to add ipv6 routes.
Allow the SIOCDELRT ioctl to delete ipv6 routes.

Allow creation of ipv6 raw sockets.

Allow setting the IPV6_JOIN_ANYCAST socket option.
Allow setting the IPV6_FL_A_RENEW parameter of the IPV6_FLOWLABEL_MGR
socket option.

Allow setting the IPV6_TRANSPARENT socket option.
Allow setting the IPV6_HOPOPTS socket option.
Allow setting the IPV6_RTHDRDSTOPTS socket option.
Allow setting the IPV6_DSTOPTS socket option.
Allow setting the IPV6_IPSEC_POLICY socket option.
Allow setting the IPV6_XFRM_POLICY socket option.

Allow sending packets with the IPV6_2292HOPOPTS control message.
Allow sending packets with the IPV6_2292DSTOPTS control message.
Allow sending packets with the IPV6_RTHDRDSTOPTS control message.

Allow setting the multicast routing socket options on non multicast
routing sockets.

Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL, and SIOCDELTUNNEL ioctls for
setting up, changing and deleting tunnels over ipv6.

Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL, SIOCDELTUNNEL ioctls for
setting up, changing and deleting ipv6 over ipv4 tunnels.

Allow the SIOCADDPRL, SIOCDELPRL, SIOCCHGPRL ioctls for adding,
deleting, and changing the potential router list for ISATAP tunnels.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
12 files changed:
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/anycast.c
net/ipv6/datagram.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/ipv6_sockglue.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/route.c
net/ipv6/sit.c

index e21bdb92565d771315f24700e1d858496edda1e2..67ac9f8d19767cda8414a22a716adbeef5254cae 100644 (file)
@@ -2413,7 +2413,7 @@ int addrconf_add_ifaddr(struct net *net, void __user *arg)
        struct in6_ifreq ireq;
        int err;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
        if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
@@ -2432,7 +2432,7 @@ int addrconf_del_ifaddr(struct net *net, void __user *arg)
        struct in6_ifreq ireq;
        int err;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
        if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
index 7bafc51cda117c1d58270773a0b42818e3addfa9..4b29f6b52c114861dcecb4ea52a4f2600bafca71 100644 (file)
@@ -160,7 +160,8 @@ lookup_protocol:
        }
 
        err = -EPERM;
-       if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
+       if (sock->type == SOCK_RAW && !kern &&
+           !ns_capable(net->user_ns, CAP_NET_RAW))
                goto out_rcu_unlock;
 
        sock->ops = answer->ops;
index 4963c769a13f0a1a4e1b19fa51a3f9a891d50afd..2f4f584d796dd3f27a7c580621bea4035ea1728f 100644 (file)
@@ -64,7 +64,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
        int     ishost = !net->ipv6.devconf_all->forwarding;
        int     err = 0;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                return -EPERM;
        if (ipv6_addr_is_multicast(addr))
                return -EINVAL;
index 93cbad2c0aa724b47c1049e851d55755d7859285..8edf2601065af07790500809b8dee9fad0fc8eaa 100644 (file)
@@ -701,7 +701,7 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
                                err = -EINVAL;
                                goto exit_f;
                        }
-                       if (!capable(CAP_NET_RAW)) {
+                       if (!ns_capable(net->user_ns, CAP_NET_RAW)) {
                                err = -EPERM;
                                goto exit_f;
                        }
@@ -721,7 +721,7 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
                                err = -EINVAL;
                                goto exit_f;
                        }
-                       if (!capable(CAP_NET_RAW)) {
+                       if (!ns_capable(net->user_ns, CAP_NET_RAW)) {
                                err = -EPERM;
                                goto exit_f;
                        }
@@ -746,7 +746,7 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
                                err = -EINVAL;
                                goto exit_f;
                        }
-                       if (!capable(CAP_NET_RAW)) {
+                       if (!ns_capable(net->user_ns, CAP_NET_RAW)) {
                                err = -EPERM;
                                goto exit_f;
                        }
index 90bbefb579435d3f3c4117f738d38366d0421b33..29124b7a04c8dfb335df69014b5348e22b3fb6ab 100644 (file)
@@ -519,7 +519,8 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
                }
                read_unlock_bh(&ip6_sk_fl_lock);
 
-               if (freq.flr_share == IPV6_FL_S_NONE && capable(CAP_NET_ADMIN)) {
+               if (freq.flr_share == IPV6_FL_S_NONE &&
+                   ns_capable(net->user_ns, CAP_NET_ADMIN)) {
                        fl = fl_lookup(net, freq.flr_label);
                        if (fl) {
                                err = fl6_renew(fl, freq.flr_linger, freq.flr_expires);
index 823fd64d01360802146be2ab6d0efa07df511c64..867466c96aac053c6bf39c956160171a099ff304 100644 (file)
@@ -1146,7 +1146,7 @@ static int ip6gre_tunnel_ioctl(struct net_device *dev,
        case SIOCADDTUNNEL:
        case SIOCCHGTUNNEL:
                err = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        goto done;
 
                err = -EFAULT;
@@ -1194,7 +1194,7 @@ static int ip6gre_tunnel_ioctl(struct net_device *dev,
 
        case SIOCDELTUNNEL:
                err = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        goto done;
 
                if (dev == ign->fb_tunnel_dev) {
index bf3a549267d322fde1ef1c35a671174f9b14d62d..fb828e9fe8e0c8c8dbf04e99d0fe0bfc9dcdd8ff 100644 (file)
@@ -1350,7 +1350,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCADDTUNNEL:
        case SIOCCHGTUNNEL:
                err = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        break;
                err = -EFAULT;
                if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
@@ -1383,7 +1383,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                break;
        case SIOCDELTUNNEL:
                err = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        break;
 
                if (dev == ip6n->fb_tnl_dev) {
index f7c7c6319720246f67f3cdbf09daea76634df0ba..d7330f8ea6d449633a4dc6213e9fa3ca0ad84017 100644 (file)
@@ -1583,7 +1583,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
                return -ENOENT;
 
        if (optname != MRT6_INIT) {
-               if (sk != mrt->mroute6_sk && !capable(CAP_NET_ADMIN))
+               if (sk != mrt->mroute6_sk && !ns_capable(net->user_ns, CAP_NET_ADMIN))
                        return -EACCES;
        }
 
index 4b4172dbbe6449fbcbf63109b39b863b14c08ac7..ee94d31c9d4d494cdfe2dce1ac812e4e094fe65f 100644 (file)
@@ -343,7 +343,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                break;
 
        case IPV6_TRANSPARENT:
-               if (valbool && !capable(CAP_NET_ADMIN) && !capable(CAP_NET_RAW)) {
+               if (valbool && !ns_capable(net->user_ns, CAP_NET_ADMIN) &&
+                   !ns_capable(net->user_ns, CAP_NET_RAW)) {
                        retv = -EPERM;
                        break;
                }
@@ -381,7 +382,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 
                /* hop-by-hop / destination options are privileged option */
                retv = -EPERM;
-               if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
+               if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
                        break;
 
                opt = ipv6_renew_options(sk, np->opt, optname,
@@ -754,7 +755,7 @@ done:
        case IPV6_IPSEC_POLICY:
        case IPV6_XFRM_POLICY:
                retv = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        break;
                retv = xfrm_user_policy(sk, optname, optval, optlen);
                break;
index 10ce76a2cb94b8431583b7a59b730028eb59d6be..74cadd0719a585525e4c0505d7b1a92a54c1dd83 100644 (file)
@@ -1854,7 +1854,7 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
 {
        int ret;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
        switch (cmd) {
@@ -1969,7 +1969,7 @@ compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 {
        int ret;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
        switch (cmd) {
@@ -1991,7 +1991,7 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 {
        int ret;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
        switch (cmd) {
@@ -2016,7 +2016,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 {
        int ret;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
        switch (cmd) {
index c6215e2b9d7f97cca35ee511b00410ea36225444..a86b65599328aa9d47e47136442f1a2f614df074 100644 (file)
@@ -2036,7 +2036,7 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        switch(cmd) {
        case SIOCADDRT:         /* Add a route */
        case SIOCDELRT:         /* Delete a route */
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        return -EPERM;
                err = copy_from_user(&rtmsg, arg,
                                     sizeof(struct in6_rtmsg));
index ca6c2c8e71d24e0c41ebd9f90211f906d8b2a368..fee21c6c3ebff01c5ab43c065e010d421cdf1268 100644 (file)
@@ -988,7 +988,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCADDTUNNEL:
        case SIOCCHGTUNNEL:
                err = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        goto done;
 
                err = -EFAULT;
@@ -1032,7 +1032,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 
        case SIOCDELTUNNEL:
                err = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        goto done;
 
                if (dev == sitn->fb_tunnel_dev) {
@@ -1065,7 +1065,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCDELPRL:
        case SIOCCHGPRL:
                err = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        goto done;
                err = -EINVAL;
                if (dev == sitn->fb_tunnel_dev)
@@ -1094,7 +1094,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
        case SIOCCHG6RD:
        case SIOCDEL6RD:
                err = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        goto done;
 
                err = -EFAULT;