Commit 0e1ae67c authored by Alexander Y. Fomichev's avatar Alexander Y. Fomichev Committed by Luis Henriques

net: fix creation adjacent device symlinks

commit 7ce64c79 upstream.

__netdev_adjacent_dev_insert may add adjust device of different net
namespace, without proper check it leads to emergence of broken
sysfs links from/to devices in another namespace.
Fix: rewrite netdev_adjacent_is_neigh_list macro as a function,
     move net_eq check into netdev_adjacent_is_neigh_list.
     (thanks David)
     related to: 4c75431aSigned-off-by: default avatarAlexander Fomichev <git.user@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Cc: Miquel van Smoorenburg <mikevs@xs4all.net>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 99d65e7e
...@@ -4799,9 +4799,14 @@ static void netdev_adjacent_sysfs_del(struct net_device *dev, ...@@ -4799,9 +4799,14 @@ static void netdev_adjacent_sysfs_del(struct net_device *dev,
sysfs_remove_link(&(dev->dev.kobj), linkname); sysfs_remove_link(&(dev->dev.kobj), linkname);
} }
#define netdev_adjacent_is_neigh_list(dev, dev_list) \ static inline bool netdev_adjacent_is_neigh_list(struct net_device *dev,
(dev_list == &dev->adj_list.upper || \ struct net_device *adj_dev,
dev_list == &dev->adj_list.lower) struct list_head *dev_list)
{
return (dev_list == &dev->adj_list.upper ||
dev_list == &dev->adj_list.lower) &&
net_eq(dev_net(dev), dev_net(adj_dev));
}
static int __netdev_adjacent_dev_insert(struct net_device *dev, static int __netdev_adjacent_dev_insert(struct net_device *dev,
struct net_device *adj_dev, struct net_device *adj_dev,
...@@ -4831,7 +4836,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, ...@@ -4831,7 +4836,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
pr_debug("dev_hold for %s, because of link added from %s to %s\n", pr_debug("dev_hold for %s, because of link added from %s to %s\n",
adj_dev->name, dev->name, adj_dev->name); adj_dev->name, dev->name, adj_dev->name);
if (netdev_adjacent_is_neigh_list(dev, dev_list)) { if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) {
ret = netdev_adjacent_sysfs_add(dev, adj_dev, dev_list); ret = netdev_adjacent_sysfs_add(dev, adj_dev, dev_list);
if (ret) if (ret)
goto free_adj; goto free_adj;
...@@ -4852,7 +4857,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, ...@@ -4852,7 +4857,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
return 0; return 0;
remove_symlinks: remove_symlinks:
if (netdev_adjacent_is_neigh_list(dev, dev_list)) if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list))
netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list);
free_adj: free_adj:
kfree(adj); kfree(adj);
...@@ -4885,8 +4890,7 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, ...@@ -4885,8 +4890,7 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
if (adj->master) if (adj->master)
sysfs_remove_link(&(dev->dev.kobj), "master"); sysfs_remove_link(&(dev->dev.kobj), "master");
if (netdev_adjacent_is_neigh_list(dev, dev_list) && if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list))
net_eq(dev_net(dev),dev_net(adj_dev)))
netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list);
list_del_rcu(&adj->list); list_del_rcu(&adj->list);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment