aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Brauner <christianvanbrauner@gmail.com>2018-01-24 09:26:32 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-29 11:31:06 -0500
commit7c4f63ba824302492985553018881455982241d6 (patch)
tree94d7a309a8829fda7650cae81983a87dd9a5ad7c
parent3e3ab9ccca5b50b11bd4d16c2048b667343354bd (diff)
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>
-rw-r--r--net/core/rtnetlink.c54
1 files changed, 47 insertions, 7 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 97874daa1336..f7e99c25dfe4 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1902,6 +1902,49 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
1902} 1902}
1903EXPORT_SYMBOL(rtnl_link_get_net); 1903EXPORT_SYMBOL(rtnl_link_get_net);
1904 1904
1905/* Figure out which network namespace we are talking about by
1906 * examining the link attributes in the following order:
1907 *
1908 * 1. IFLA_NET_NS_PID
1909 * 2. IFLA_NET_NS_FD
1910 * 3. IFLA_IF_NETNSID
1911 */
1912static struct net *rtnl_link_get_net_by_nlattr(struct net *src_net,
1913 struct nlattr *tb[])
1914{
1915 struct net *net;
1916
1917 if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD])
1918 return rtnl_link_get_net(src_net, tb);
1919
1920 if (!tb[IFLA_IF_NETNSID])
1921 return get_net(src_net);
1922
1923 net = get_net_ns_by_id(src_net, nla_get_u32(tb[IFLA_IF_NETNSID]));
1924 if (!net)
1925 return ERR_PTR(-EINVAL);
1926
1927 return net;
1928}
1929
1930static struct net *rtnl_link_get_net_capable(const struct sk_buff *skb,
1931 struct net *src_net,
1932 struct nlattr *tb[], int cap)
1933{
1934 struct net *net;
1935
1936 net = rtnl_link_get_net_by_nlattr(src_net, tb);
1937 if (IS_ERR(net))
1938 return net;
1939
1940 if (!netlink_ns_capable(skb, net->user_ns, cap)) {
1941 put_net(net);
1942 return ERR_PTR(-EPERM);
1943 }
1944
1945 return net;
1946}
1947
1905static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) 1948static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
1906{ 1949{
1907 if (dev) { 1950 if (dev) {
@@ -2164,17 +2207,14 @@ static int do_setlink(const struct sk_buff *skb,
2164 const struct net_device_ops *ops = dev->netdev_ops; 2207 const struct net_device_ops *ops = dev->netdev_ops;
2165 int err; 2208 int err;
2166 2209
2167 if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { 2210 if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_IF_NETNSID]) {
2168 struct net *net = rtnl_link_get_net(dev_net(dev), tb); 2211 struct net *net = rtnl_link_get_net_capable(skb, dev_net(dev),
2212 tb, CAP_NET_ADMIN);
2169 if (IS_ERR(net)) { 2213 if (IS_ERR(net)) {
2170 err = PTR_ERR(net); 2214 err = PTR_ERR(net);
2171 goto errout; 2215 goto errout;
2172 } 2216 }
2173 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { 2217
2174 put_net(net);
2175 err = -EPERM;
2176 goto errout;
2177 }
2178 err = dev_change_net_namespace(dev, net, ifname); 2218 err = dev_change_net_namespace(dev, net, ifname);
2179 put_net(net); 2219 put_net(net);
2180 if (err) 2220 if (err)