mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-10 07:44:23 +08:00
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);
|
||||
|
||||
/* 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)
|
||||
|
Loading…
Reference in New Issue
Block a user