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: Christian Brauner <christian.brauner@ubuntu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3e3ab9ccca
commit
7c4f63ba82
|
@ -1902,6 +1902,49 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rtnl_link_get_net);
|
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[])
|
static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
|
||||||
{
|
{
|
||||||
if (dev) {
|
if (dev) {
|
||||||
|
@ -2164,17 +2207,14 @@ static int do_setlink(const struct sk_buff *skb,
|
||||||
const struct net_device_ops *ops = dev->netdev_ops;
|
const struct net_device_ops *ops = dev->netdev_ops;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) {
|
if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_IF_NETNSID]) {
|
||||||
struct net *net = rtnl_link_get_net(dev_net(dev), tb);
|
struct net *net = rtnl_link_get_net_capable(skb, dev_net(dev),
|
||||||
|
tb, CAP_NET_ADMIN);
|
||||||
if (IS_ERR(net)) {
|
if (IS_ERR(net)) {
|
||||||
err = PTR_ERR(net);
|
err = PTR_ERR(net);
|
||||||
goto errout;
|
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);
|
err = dev_change_net_namespace(dev, net, ifname);
|
||||||
put_net(net);
|
put_net(net);
|
||||||
if (err)
|
if (err)
|
||||||
|
|
Loading…
Reference in New Issue