Commit 52e804c6 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by David S. Miller

net: Allow userns root to control ipv4

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: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5e1fccc0
...@@ -346,7 +346,8 @@ static int inet_create(struct net *net, struct socket *sock, int protocol, ...@@ -346,7 +346,8 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
} }
err = -EPERM; 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; goto out_rcu_unlock;
err = -EAFNOSUPPORT; err = -EAFNOSUPPORT;
......
...@@ -1161,7 +1161,7 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -1161,7 +1161,7 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
switch (cmd) { switch (cmd) {
case SIOCDARP: case SIOCDARP:
case SIOCSARP: case SIOCSARP:
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
case SIOCGARP: case SIOCGARP:
err = copy_from_user(&r, arg, sizeof(struct arpreq)); err = copy_from_user(&r, arg, sizeof(struct arpreq));
......
...@@ -730,7 +730,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -730,7 +730,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
case SIOCSIFFLAGS: case SIOCSIFFLAGS:
ret = -EPERM; ret = -EPERM;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
goto out; goto out;
break; break;
case SIOCSIFADDR: /* Set interface address (and family) */ case SIOCSIFADDR: /* Set interface address (and family) */
...@@ -738,7 +738,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -738,7 +738,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
case SIOCSIFDSTADDR: /* Set the destination address */ case SIOCSIFDSTADDR: /* Set the destination address */
case SIOCSIFNETMASK: /* Set the netmask for the interface */ case SIOCSIFNETMASK: /* Set the netmask for the interface */
ret = -EPERM; ret = -EPERM;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
goto out; goto out;
ret = -EINVAL; ret = -EINVAL;
if (sin->sin_family != AF_INET) if (sin->sin_family != AF_INET)
......
...@@ -488,7 +488,7 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -488,7 +488,7 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
switch (cmd) { switch (cmd) {
case SIOCADDRT: /* Add a route */ case SIOCADDRT: /* Add a route */
case SIOCDELRT: /* Delete a route */ case SIOCDELRT: /* Delete a route */
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
if (copy_from_user(&rt, arg, sizeof(rt))) if (copy_from_user(&rt, arg, sizeof(rt)))
......
...@@ -1064,7 +1064,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1064,7 +1064,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCADDTUNNEL: case SIOCADDTUNNEL:
case SIOCCHGTUNNEL: case SIOCCHGTUNNEL:
err = -EPERM; err = -EPERM;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
goto done; goto done;
err = -EFAULT; err = -EFAULT;
...@@ -1139,7 +1139,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1139,7 +1139,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCDELTUNNEL: case SIOCDELTUNNEL:
err = -EPERM; err = -EPERM;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
goto done; goto done;
if (dev == ign->fb_tunnel_dev) { if (dev == ign->fb_tunnel_dev) {
......
...@@ -409,7 +409,7 @@ int ip_options_compile(struct net *net, ...@@ -409,7 +409,7 @@ int ip_options_compile(struct net *net,
optptr[2] += 8; optptr[2] += 8;
break; break;
default: default:
if (!skb && !capable(CAP_NET_RAW)) { if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) {
pp_ptr = optptr + 3; pp_ptr = optptr + 3;
goto error; goto error;
} }
...@@ -445,7 +445,7 @@ int ip_options_compile(struct net *net, ...@@ -445,7 +445,7 @@ int ip_options_compile(struct net *net,
opt->router_alert = optptr - iph; opt->router_alert = optptr - iph;
break; break;
case IPOPT_CIPSO: 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; pp_ptr = optptr;
goto error; goto error;
} }
...@@ -458,7 +458,7 @@ int ip_options_compile(struct net *net, ...@@ -458,7 +458,7 @@ int ip_options_compile(struct net *net,
case IPOPT_SEC: case IPOPT_SEC:
case IPOPT_SID: case IPOPT_SID:
default: default:
if (!skb && !capable(CAP_NET_RAW)) { if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) {
pp_ptr = optptr; pp_ptr = optptr;
goto error; goto error;
} }
......
...@@ -989,13 +989,14 @@ static int do_ip_setsockopt(struct sock *sk, int level, ...@@ -989,13 +989,14 @@ static int do_ip_setsockopt(struct sock *sk, int level,
case IP_IPSEC_POLICY: case IP_IPSEC_POLICY:
case IP_XFRM_POLICY: case IP_XFRM_POLICY:
err = -EPERM; err = -EPERM;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
break; break;
err = xfrm_user_policy(sk, optname, optval, optlen); err = xfrm_user_policy(sk, optname, optval, optlen);
break; break;
case IP_TRANSPARENT: 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; err = -EPERM;
break; break;
} }
......
...@@ -488,7 +488,7 @@ vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -488,7 +488,7 @@ vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCADDTUNNEL: case SIOCADDTUNNEL:
case SIOCCHGTUNNEL: case SIOCCHGTUNNEL:
err = -EPERM; err = -EPERM;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
goto done; goto done;
err = -EFAULT; err = -EFAULT;
...@@ -553,7 +553,7 @@ vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -553,7 +553,7 @@ vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCDELTUNNEL: case SIOCDELTUNNEL:
err = -EPERM; err = -EPERM;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
goto done; goto done;
if (dev == ipn->fb_tunnel_dev) { if (dev == ipn->fb_tunnel_dev) {
......
...@@ -691,7 +691,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -691,7 +691,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCADDTUNNEL: case SIOCADDTUNNEL:
case SIOCCHGTUNNEL: case SIOCCHGTUNNEL:
err = -EPERM; err = -EPERM;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
goto done; goto done;
err = -EFAULT; err = -EFAULT;
...@@ -735,7 +735,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -735,7 +735,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCDELTUNNEL: case SIOCDELTUNNEL:
err = -EPERM; err = -EPERM;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
goto done; goto done;
if (dev == ipn->fb_tunnel_dev) { if (dev == ipn->fb_tunnel_dev) {
......
...@@ -1213,7 +1213,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi ...@@ -1213,7 +1213,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
if (optname != MRT_INIT) { if (optname != MRT_INIT) {
if (sk != rcu_access_pointer(mrt->mroute_sk) && if (sk != rcu_access_pointer(mrt->mroute_sk) &&
!capable(CAP_NET_ADMIN)) !ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EACCES; return -EACCES;
} }
......
...@@ -1533,7 +1533,7 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, ...@@ -1533,7 +1533,7 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user,
{ {
int ret; int ret;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
switch (cmd) { switch (cmd) {
...@@ -1677,7 +1677,7 @@ static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, ...@@ -1677,7 +1677,7 @@ static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user,
{ {
int ret; int ret;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
switch (cmd) { switch (cmd) {
...@@ -1698,7 +1698,7 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned ...@@ -1698,7 +1698,7 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned
{ {
int ret; int ret;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
switch (cmd) { switch (cmd) {
...@@ -1722,7 +1722,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len ...@@ -1722,7 +1722,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
{ {
int ret; int ret;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
switch (cmd) { switch (cmd) {
......
...@@ -1846,7 +1846,7 @@ compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, ...@@ -1846,7 +1846,7 @@ compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
{ {
int ret; int ret;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
switch (cmd) { switch (cmd) {
...@@ -1961,7 +1961,7 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -1961,7 +1961,7 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
{ {
int ret; int ret;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
switch (cmd) { switch (cmd) {
...@@ -1983,7 +1983,7 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ...@@ -1983,7 +1983,7 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
{ {
int ret; int ret;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
switch (cmd) { switch (cmd) {
...@@ -2008,7 +2008,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -2008,7 +2008,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
{ {
int ret; int ret;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
switch (cmd) { switch (cmd) {
......
...@@ -2304,7 +2304,7 @@ void tcp_sock_destruct(struct sock *sk) ...@@ -2304,7 +2304,7 @@ void tcp_sock_destruct(struct sock *sk)
static inline bool tcp_can_repair_sock(const 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)); ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED));
} }
......
...@@ -259,7 +259,8 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) ...@@ -259,7 +259,8 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
if (!ca) if (!ca)
err = -ENOENT; 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; err = -EPERM;
else if (!try_module_get(ca->owner)) else if (!try_module_get(ca->owner))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment