diff options
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index ab293a3066b3..7ebed55b5f7d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -1300,7 +1300,6 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
1300 | s_h = cb->args[0]; | 1300 | s_h = cb->args[0]; |
1301 | s_idx = cb->args[1]; | 1301 | s_idx = cb->args[1]; |
1302 | 1302 | ||
1303 | rcu_read_lock(); | ||
1304 | cb->seq = net->dev_base_seq; | 1303 | cb->seq = net->dev_base_seq; |
1305 | 1304 | ||
1306 | /* A hack to preserve kernel<->userspace interface. | 1305 | /* A hack to preserve kernel<->userspace interface. |
@@ -1322,7 +1321,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
1322 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | 1321 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
1323 | idx = 0; | 1322 | idx = 0; |
1324 | head = &net->dev_index_head[h]; | 1323 | head = &net->dev_index_head[h]; |
1325 | hlist_for_each_entry_rcu(dev, head, index_hlist) { | 1324 | hlist_for_each_entry(dev, head, index_hlist) { |
1326 | if (idx < s_idx) | 1325 | if (idx < s_idx) |
1327 | goto cont; | 1326 | goto cont; |
1328 | err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, | 1327 | err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, |
@@ -1344,7 +1343,6 @@ cont: | |||
1344 | } | 1343 | } |
1345 | } | 1344 | } |
1346 | out: | 1345 | out: |
1347 | rcu_read_unlock(); | ||
1348 | cb->args[1] = idx; | 1346 | cb->args[1] = idx; |
1349 | cb->args[0] = h; | 1347 | cb->args[0] = h; |
1350 | 1348 | ||
@@ -1934,10 +1932,10 @@ static int rtnl_group_changelink(const struct sk_buff *skb, | |||
1934 | struct ifinfomsg *ifm, | 1932 | struct ifinfomsg *ifm, |
1935 | struct nlattr **tb) | 1933 | struct nlattr **tb) |
1936 | { | 1934 | { |
1937 | struct net_device *dev; | 1935 | struct net_device *dev, *aux; |
1938 | int err; | 1936 | int err; |
1939 | 1937 | ||
1940 | for_each_netdev(net, dev) { | 1938 | for_each_netdev_safe(net, dev, aux) { |
1941 | if (dev->group == group) { | 1939 | if (dev->group == group) { |
1942 | err = do_setlink(skb, dev, ifm, tb, NULL, 0); | 1940 | err = do_setlink(skb, dev, ifm, tb, NULL, 0); |
1943 | if (err < 0) | 1941 | if (err < 0) |
@@ -2012,8 +2010,8 @@ replay: | |||
2012 | } | 2010 | } |
2013 | 2011 | ||
2014 | if (1) { | 2012 | if (1) { |
2015 | struct nlattr *attr[ops ? ops->maxtype + 1 : 0]; | 2013 | struct nlattr *attr[ops ? ops->maxtype + 1 : 1]; |
2016 | struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 0]; | 2014 | struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 1]; |
2017 | struct nlattr **data = NULL; | 2015 | struct nlattr **data = NULL; |
2018 | struct nlattr **slave_data = NULL; | 2016 | struct nlattr **slave_data = NULL; |
2019 | struct net *dest_net, *link_net = NULL; | 2017 | struct net *dest_net, *link_net = NULL; |
@@ -2122,6 +2120,10 @@ replay: | |||
2122 | if (IS_ERR(dest_net)) | 2120 | if (IS_ERR(dest_net)) |
2123 | return PTR_ERR(dest_net); | 2121 | return PTR_ERR(dest_net); |
2124 | 2122 | ||
2123 | err = -EPERM; | ||
2124 | if (!netlink_ns_capable(skb, dest_net->user_ns, CAP_NET_ADMIN)) | ||
2125 | goto out; | ||
2126 | |||
2125 | if (tb[IFLA_LINK_NETNSID]) { | 2127 | if (tb[IFLA_LINK_NETNSID]) { |
2126 | int id = nla_get_s32(tb[IFLA_LINK_NETNSID]); | 2128 | int id = nla_get_s32(tb[IFLA_LINK_NETNSID]); |
2127 | 2129 | ||
@@ -2130,6 +2132,9 @@ replay: | |||
2130 | err = -EINVAL; | 2132 | err = -EINVAL; |
2131 | goto out; | 2133 | goto out; |
2132 | } | 2134 | } |
2135 | err = -EPERM; | ||
2136 | if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN)) | ||
2137 | goto out; | ||
2133 | } | 2138 | } |
2134 | 2139 | ||
2135 | dev = rtnl_create_link(link_net ? : dest_net, ifname, | 2140 | dev = rtnl_create_link(link_net ? : dest_net, ifname, |
@@ -2161,28 +2166,28 @@ replay: | |||
2161 | } | 2166 | } |
2162 | } | 2167 | } |
2163 | err = rtnl_configure_link(dev, ifm); | 2168 | err = rtnl_configure_link(dev, ifm); |
2164 | if (err < 0) { | 2169 | if (err < 0) |
2165 | if (ops->newlink) { | 2170 | goto out_unregister; |
2166 | LIST_HEAD(list_kill); | ||
2167 | |||
2168 | ops->dellink(dev, &list_kill); | ||
2169 | unregister_netdevice_many(&list_kill); | ||
2170 | } else { | ||
2171 | unregister_netdevice(dev); | ||
2172 | } | ||
2173 | goto out; | ||
2174 | } | ||
2175 | |||
2176 | if (link_net) { | 2171 | if (link_net) { |
2177 | err = dev_change_net_namespace(dev, dest_net, ifname); | 2172 | err = dev_change_net_namespace(dev, dest_net, ifname); |
2178 | if (err < 0) | 2173 | if (err < 0) |
2179 | unregister_netdevice(dev); | 2174 | goto out_unregister; |
2180 | } | 2175 | } |
2181 | out: | 2176 | out: |
2182 | if (link_net) | 2177 | if (link_net) |
2183 | put_net(link_net); | 2178 | put_net(link_net); |
2184 | put_net(dest_net); | 2179 | put_net(dest_net); |
2185 | return err; | 2180 | return err; |
2181 | out_unregister: | ||
2182 | if (ops->newlink) { | ||
2183 | LIST_HEAD(list_kill); | ||
2184 | |||
2185 | ops->dellink(dev, &list_kill); | ||
2186 | unregister_netdevice_many(&list_kill); | ||
2187 | } else { | ||
2188 | unregister_netdevice(dev); | ||
2189 | } | ||
2190 | goto out; | ||
2186 | } | 2191 | } |
2187 | } | 2192 | } |
2188 | 2193 | ||