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 | ||
