Commit 7c4f63ba authored by Christian Brauner's avatar Christian Brauner Committed by David S. Miller

rtnetlink: enable IFLA_IF_NETNSID in do_setlink()

RTM_{NEW,SET}LINK already allow operations on other network namespaces
by identifying the target network namespace through IFLA_NET_NS_{FD,PID}
properties. This is done by looking for the corresponding properties in
do_setlink(). Extend do_setlink() to also look for the IFLA_IF_NETNSID
property. This introduces no functional changes since all callers of
do_setlink() currently block IFLA_IF_NETNSID by reporting an error before
they reach do_setlink().

This introduces the helpers:

static struct net *rtnl_link_get_net_by_nlattr(struct net *src_net, struct
                                               nlattr *tb[])

static struct net *rtnl_link_get_net_capable(const struct sk_buff *skb,
                                             struct net *src_net,
					     struct nlattr *tb[], int cap)

to simplify permission checks and target network namespace retrieval for
RTM_* requests that already support IFLA_NET_NS_{FD,PID} but get extended
to IFLA_IF_NETNSID. To perserve backwards compatibility the helpers look
for IFLA_NET_NS_{FD,PID} properties first before checking for
IFLA_IF_NETNSID.
Signed-off-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3e3ab9cc
......@@ -1902,6 +1902,49 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
}
EXPORT_SYMBOL(rtnl_link_get_net);
/* Figure out which network namespace we are talking about by
* examining the link attributes in the following order:
*
* 1. IFLA_NET_NS_PID
* 2. IFLA_NET_NS_FD
* 3. IFLA_IF_NETNSID
*/
static struct net *rtnl_link_get_net_by_nlattr(struct net *src_net,
struct nlattr *tb[])
{
struct net *net;
if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD])
return rtnl_link_get_net(src_net, tb);
if (!tb[IFLA_IF_NETNSID])
return get_net(src_net);
net = get_net_ns_by_id(src_net, nla_get_u32(tb[IFLA_IF_NETNSID]));
if (!net)
return ERR_PTR(-EINVAL);
return net;
}
static struct net *rtnl_link_get_net_capable(const struct sk_buff *skb,
struct net *src_net,
struct nlattr *tb[], int cap)
{
struct net *net;
net = rtnl_link_get_net_by_nlattr(src_net, tb);
if (IS_ERR(net))
return net;
if (!netlink_ns_capable(skb, net->user_ns, cap)) {
put_net(net);
return ERR_PTR(-EPERM);
}
return net;
}
static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
{
if (dev) {
......@@ -2164,17 +2207,14 @@ static int do_setlink(const struct sk_buff *skb,
const struct net_device_ops *ops = dev->netdev_ops;
int err;
if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) {
struct net *net = rtnl_link_get_net(dev_net(dev), tb);
if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_IF_NETNSID]) {
struct net *net = rtnl_link_get_net_capable(skb, dev_net(dev),
tb, CAP_NET_ADMIN);
if (IS_ERR(net)) {
err = PTR_ERR(net);
goto errout;
}
if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
put_net(net);
err = -EPERM;
goto errout;
}
err = dev_change_net_namespace(dev, net, ifname);
put_net(net);
if (err)
......
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