diff options
author | Christian Brauner <christianvanbrauner@gmail.com> | 2018-01-24 09:26:32 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-29 11:31:06 -0500 |
commit | 7c4f63ba824302492985553018881455982241d6 (patch) | |
tree | 94d7a309a8829fda7650cae81983a87dd9a5ad7c | |
parent | 3e3ab9ccca5b50b11bd4d16c2048b667343354bd (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.c | 54 |
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 | } |
1903 | EXPORT_SYMBOL(rtnl_link_get_net); | 1903 | EXPORT_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 | */ | ||
1912 | static 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 | |||
1930 | static 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 | |||
1905 | static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) | 1948 | static 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) |