]> Pileus Git - ~andy/linux/commitdiff
net: Allow userns root to control ipv4
authorEric W. Biederman <ebiederm@xmission.com>
Fri, 16 Nov 2012 03:03:05 +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 creating raw sockets.
Allow the SIOCSARP ioctl to control the arp cache.
Allow the SIOCSIFFLAG ioctl to allow setting network device flags.
Allow the SIOCSIFADDR ioctl to allow setting a netdevice ipv4 address.
Allow the SIOCSIFBRDADDR ioctl to allow setting a netdevice ipv4 broadcast address.
Allow the SIOCSIFDSTADDR ioctl to allow setting a netdevice ipv4 destination address.
Allow the SIOCSIFNETMASK ioctl to allow setting a netdevice ipv4 netmask.
Allow the SIOCADDRT and SIOCDELRT ioctls to allow adding and deleting ipv4 routes.

Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting gre tunnels.

Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting ipip tunnels.

Allow the SIOCADDTUNNEL, SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls for
adding, changing and deleting ipsec virtual tunnel interfaces.

Allow setting the MRT_INIT, MRT_DONE, MRT_ADD_VIF, MRT_DEL_VIF, MRT_ADD_MFC,
MRT_DEL_MFC, MRT_ASSERT, MRT_PIM, MRT_TABLE socket options on multicast routing
sockets.

Allow setting and receiving IPOPT_CIPSO, IP_OPT_SEC, IP_OPT_SID and
arbitrary ip options.

Allow setting IP_SEC_POLICY/IP_XFRM_POLICY ipv4 socket option.
Allow setting the IP_TRANSPARENT ipv4 socket option.
Allow setting the TCP_REPAIR socket option.
Allow setting the TCP_CONGESTION socket option.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
14 files changed:
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/fib_frontend.c
net/ipv4/ip_gre.c
net/ipv4/ip_options.c
net/ipv4/ip_sockglue.c
net/ipv4/ip_vti.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c

index d5e5a054123c199f05f5d4d4a356406412b88928..4f5f22061e1c54c8c671d5875dcf00c16b73dfa7 100644 (file)
@@ -346,7 +346,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;
 
        err = -EAFNOSUPPORT;
index 47800459e4cb341c395f54f2d161c300a112c1cf..ce6fbdfd40b893edc29aa090052663024039eadc 100644 (file)
@@ -1161,7 +1161,7 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        switch (cmd) {
        case SIOCDARP:
        case SIOCSARP:
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        return -EPERM;
        case SIOCGARP:
                err = copy_from_user(&r, arg, sizeof(struct arpreq));
index 41709353891699c7e370490b8b97dad63718b2ab..259622a5e690a1012443a3739ae4a457f6a1368b 100644 (file)
@@ -730,7 +730,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
 
        case SIOCSIFFLAGS:
                ret = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        goto out;
                break;
        case SIOCSIFADDR:       /* Set interface address (and family) */
@@ -738,7 +738,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        case SIOCSIFDSTADDR:    /* Set the destination address */
        case SIOCSIFNETMASK:    /* Set the netmask for the interface */
                ret = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        goto out;
                ret = -EINVAL;
                if (sin->sin_family != AF_INET)
index bce4541c67844be50387c5a3f731f8392051d634..784716a677ce32c453f1263fdb4d2d776123c526 100644 (file)
@@ -488,7 +488,7 @@ int ip_rt_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;
 
                if (copy_from_user(&rt, arg, sizeof(rt)))
index 127f2a1e67f58fabfa5bf31eb51d9dd3a4845e6c..a85ae2f7a21cb15502bd69e9c63a1ec29020fa40 100644 (file)
@@ -1064,7 +1064,7 @@ ipgre_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;
@@ -1139,7 +1139,7 @@ ipgre_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 == ign->fb_tunnel_dev) {
index 1dc01f9793d59120a713213e7e65cc855bfb37b9..f6289bf6f3325edc2c78541eca88e546e5ec97c9 100644 (file)
@@ -409,7 +409,7 @@ int ip_options_compile(struct net *net,
                                        optptr[2] += 8;
                                        break;
                                      default:
-                                       if (!skb && !capable(CAP_NET_RAW)) {
+                                       if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) {
                                                pp_ptr = optptr + 3;
                                                goto error;
                                        }
@@ -445,7 +445,7 @@ int ip_options_compile(struct net *net,
                                opt->router_alert = optptr - iph;
                        break;
                      case IPOPT_CIPSO:
-                       if ((!skb && !capable(CAP_NET_RAW)) || opt->cipso) {
+                       if ((!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) || opt->cipso) {
                                pp_ptr = optptr;
                                goto error;
                        }
@@ -458,7 +458,7 @@ int ip_options_compile(struct net *net,
                      case IPOPT_SEC:
                      case IPOPT_SID:
                      default:
-                       if (!skb && !capable(CAP_NET_RAW)) {
+                       if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) {
                                pp_ptr = optptr;
                                goto error;
                        }
index 14bbfcf717acb9d02df641231cdf30a611a43810..3c9d20880283de0f9b5244eae8184e76d9a20dcd 100644 (file)
@@ -989,13 +989,14 @@ mc_msf_out:
        case IP_IPSEC_POLICY:
        case IP_XFRM_POLICY:
                err = -EPERM;
-               if (!capable(CAP_NET_ADMIN))
+               if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
                        break;
                err = xfrm_user_policy(sk, optname, optval, optlen);
                break;
 
        case IP_TRANSPARENT:
-               if (!!val && !capable(CAP_NET_RAW) && !capable(CAP_NET_ADMIN)) {
+               if (!!val && !ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
+                   !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
                        err = -EPERM;
                        break;
                }
index f4a825d3bd7ffea56b08022fb8c528055c8281ea..c3a4233c0ac290394c819882aeff5ba3800378f4 100644 (file)
@@ -488,7 +488,7 @@ vti_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;
@@ -553,7 +553,7 @@ vti_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 == ipn->fb_tunnel_dev) {
index c26c1717c1dbdb04f011dc40e451296080dc46f9..191fc24a745a9668332f74106fd39831d9f01c53 100644 (file)
@@ -691,7 +691,7 @@ ipip_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;
@@ -735,7 +735,7 @@ ipip_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 == ipn->fb_tunnel_dev) {
index 6168c4dc58b1db546c567ef0c55842ab42edee16..adf3d349566f0d12c506104f4bbeed3b9babdc12 100644 (file)
@@ -1213,7 +1213,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
 
        if (optname != MRT_INIT) {
                if (sk != rcu_access_pointer(mrt->mroute_sk) &&
-                   !capable(CAP_NET_ADMIN))
+                   !ns_capable(net->user_ns, CAP_NET_ADMIN))
                        return -EACCES;
        }
 
index 97e61eadf5800f8df1054da565beb227e0479568..3ea4127404d662f6756155128054d4a4c9b4ba0a 100644 (file)
@@ -1533,7 +1533,7 @@ static int compat_do_arpt_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) {
@@ -1677,7 +1677,7 @@ static int compat_do_arpt_get_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) {
@@ -1698,7 +1698,7 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned
 {
        int ret;
 
-       if (!capable(CAP_NET_ADMIN))
+       if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
        switch (cmd) {
@@ -1722,7 +1722,7 @@ static int do_arpt_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 170b1fdd6b72e26060edb584812be07493fb2f04..17c5e06da6628b7ec12495471d3bfcc943acf969 100644 (file)
@@ -1846,7 +1846,7 @@ compat_do_ipt_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) {
@@ -1961,7 +1961,7 @@ compat_do_ipt_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) {
@@ -1983,7 +1983,7 @@ do_ipt_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) {
@@ -2008,7 +2008,7 @@ do_ipt_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 4aefa0b42c2e1bd0ff2284346ebaba9de27184d4..e6eace1c2bdbe8a8c40678b8a004b8776c1dc596 100644 (file)
@@ -2304,7 +2304,7 @@ void tcp_sock_destruct(struct sock *sk)
 
 static inline bool tcp_can_repair_sock(const struct sock *sk)
 {
-       return capable(CAP_NET_ADMIN) &&
+       return ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN) &&
                ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED));
 }
 
index 1432cdb0644c2b16f893de842bcd3b9fdd3c5538..baf28611b3345030d42ea73d40a14284648717bb 100644 (file)
@@ -259,7 +259,8 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
        if (!ca)
                err = -ENOENT;
 
-       else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) || capable(CAP_NET_ADMIN)))
+       else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) ||
+                  ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)))
                err = -EPERM;
 
        else if (!try_module_get(ca->owner))