Commit 5e1fccc0 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by David S. Miller

net: Allow userns root control of the core of the network stack.

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 ethtool ioctls.

Allow binding to network devices.
Allow setting the socket mark.
Allow setting the socket priority.

Allow setting the network device alias via sysfs.
Allow setting the mtu via sysfs.
Allow changing the network device flags via sysfs.
Allow setting the network device group via sysfs.

Allow the following network device ioctls.
SIOCGMIIPHY
SIOCGMIIREG
SIOCSIFNAME
SIOCSIFFLAGS
SIOCSIFMETRIC
SIOCSIFMTU
SIOCSIFHWADDR
SIOCSIFSLAVE
SIOCADDMULTI
SIOCDELMULTI
SIOCSIFHWBROADCAST
SIOCSMIIREG
SIOCBONDENSLAVE
SIOCBONDRELEASE
SIOCBONDSETHWADDR
SIOCBONDCHANGEACTIVE
SIOCBRADDIF
SIOCBRDELIF
SIOCSHWTSTAMP
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 00f70de0
...@@ -5279,7 +5279,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -5279,7 +5279,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
case SIOCGMIIPHY: case SIOCGMIIPHY:
case SIOCGMIIREG: case SIOCGMIIREG:
case SIOCSIFNAME: case SIOCSIFNAME:
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
dev_load(net, ifr.ifr_name); dev_load(net, ifr.ifr_name);
rtnl_lock(); rtnl_lock();
...@@ -5300,16 +5300,25 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -5300,16 +5300,25 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
* - require strict serialization. * - require strict serialization.
* - do not return a value * - do not return a value
*/ */
case SIOCSIFMAP:
case SIOCSIFTXQLEN:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* fall through */
/*
* These ioctl calls:
* - require local superuser power.
* - require strict serialization.
* - do not return a value
*/
case SIOCSIFFLAGS: case SIOCSIFFLAGS:
case SIOCSIFMETRIC: case SIOCSIFMETRIC:
case SIOCSIFMTU: case SIOCSIFMTU:
case SIOCSIFMAP:
case SIOCSIFHWADDR: case SIOCSIFHWADDR:
case SIOCSIFSLAVE: case SIOCSIFSLAVE:
case SIOCADDMULTI: case SIOCADDMULTI:
case SIOCDELMULTI: case SIOCDELMULTI:
case SIOCSIFHWBROADCAST: case SIOCSIFHWBROADCAST:
case SIOCSIFTXQLEN:
case SIOCSMIIREG: case SIOCSMIIREG:
case SIOCBONDENSLAVE: case SIOCBONDENSLAVE:
case SIOCBONDRELEASE: case SIOCBONDRELEASE:
...@@ -5318,7 +5327,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) ...@@ -5318,7 +5327,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
case SIOCBRADDIF: case SIOCBRADDIF:
case SIOCBRDELIF: case SIOCBRDELIF:
case SIOCSHWTSTAMP: case SIOCSHWTSTAMP:
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
/* fall through */ /* fall through */
case SIOCBONDSLAVEINFOQUERY: case SIOCBONDSLAVEINFOQUERY:
......
...@@ -1460,7 +1460,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) ...@@ -1460,7 +1460,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_GEEE: case ETHTOOL_GEEE:
break; break;
default: default:
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
} }
......
...@@ -73,11 +73,12 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, ...@@ -73,11 +73,12 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t len, const char *buf, size_t len,
int (*set)(struct net_device *, unsigned long)) int (*set)(struct net_device *, unsigned long))
{ {
struct net_device *net = to_net_dev(dev); struct net_device *netdev = to_net_dev(dev);
struct net *net = dev_net(netdev);
unsigned long new; unsigned long new;
int ret = -EINVAL; int ret = -EINVAL;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
ret = kstrtoul(buf, 0, &new); ret = kstrtoul(buf, 0, &new);
...@@ -87,8 +88,8 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, ...@@ -87,8 +88,8 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
if (!rtnl_trylock()) if (!rtnl_trylock())
return restart_syscall(); return restart_syscall();
if (dev_isalive(net)) { if (dev_isalive(netdev)) {
if ((ret = (*set)(net, new)) == 0) if ((ret = (*set)(netdev, new)) == 0)
ret = len; ret = len;
} }
rtnl_unlock(); rtnl_unlock();
...@@ -264,6 +265,9 @@ static ssize_t store_tx_queue_len(struct device *dev, ...@@ -264,6 +265,9 @@ static ssize_t store_tx_queue_len(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t len) const char *buf, size_t len)
{ {
if (!capable(CAP_NET_ADMIN))
return -EPERM;
return netdev_store(dev, attr, buf, len, change_tx_queue_len); return netdev_store(dev, attr, buf, len, change_tx_queue_len);
} }
...@@ -271,10 +275,11 @@ static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr, ...@@ -271,10 +275,11 @@ static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr,
const char *buf, size_t len) const char *buf, size_t len)
{ {
struct net_device *netdev = to_net_dev(dev); struct net_device *netdev = to_net_dev(dev);
struct net *net = dev_net(netdev);
size_t count = len; size_t count = len;
ssize_t ret; ssize_t ret;
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
/* ignore trailing newline */ /* ignore trailing newline */
......
...@@ -515,7 +515,7 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) ...@@ -515,7 +515,7 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen)
/* Sorry... */ /* Sorry... */
ret = -EPERM; ret = -EPERM;
if (!capable(CAP_NET_RAW)) if (!ns_capable(net->user_ns, CAP_NET_RAW))
goto out; goto out;
ret = -EINVAL; ret = -EINVAL;
...@@ -696,7 +696,8 @@ int sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -696,7 +696,8 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
break; break;
case SO_PRIORITY: case SO_PRIORITY:
if ((val >= 0 && val <= 6) || capable(CAP_NET_ADMIN)) if ((val >= 0 && val <= 6) ||
ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
sk->sk_priority = val; sk->sk_priority = val;
else else
ret = -EPERM; ret = -EPERM;
...@@ -813,7 +814,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -813,7 +814,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
clear_bit(SOCK_PASSSEC, &sock->flags); clear_bit(SOCK_PASSSEC, &sock->flags);
break; break;
case SO_MARK: case SO_MARK:
if (!capable(CAP_NET_ADMIN)) if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
ret = -EPERM; ret = -EPERM;
else else
sk->sk_mark = val; sk->sk_mark = val;
......
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