Commit 99d65e7e authored by Alexander Y. Fomichev's avatar Alexander Y. Fomichev Committed by Luis Henriques

net: prevent of emerging cross-namespace symlinks

commit 4c75431a upstream.

Code manipulating sysfs symlinks on adjacent net_devices(s)
currently doesn't take into account that devices potentially
belong to different namespaces.

This patch trying to fix an issue as follows:
- check for net_ns before creating / deleting symlink.
  for now only netdev_adjacent_rename_links and
  __netdev_adjacent_dev_remove are affected, afaics
  __netdev_adjacent_dev_insert implies both net_devs
  belong to the same namespace.
- Drop all existing symlinks to / from all adj_devs before
  switching namespace and recreate them just after.
Signed-off-by: default avatarAlexander Y. 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 576e0cda
...@@ -4885,7 +4885,8 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, ...@@ -4885,7 +4885,8 @@ 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, 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);
...@@ -5155,11 +5156,65 @@ void netdev_upper_dev_unlink(struct net_device *dev, ...@@ -5155,11 +5156,65 @@ void netdev_upper_dev_unlink(struct net_device *dev,
} }
EXPORT_SYMBOL(netdev_upper_dev_unlink); EXPORT_SYMBOL(netdev_upper_dev_unlink);
void netdev_adjacent_add_links(struct net_device *dev)
{
struct netdev_adjacent *iter;
struct net *net = dev_net(dev);
list_for_each_entry(iter, &dev->adj_list.upper, list) {
if (!net_eq(net,dev_net(iter->dev)))
continue;
netdev_adjacent_sysfs_add(iter->dev, dev,
&iter->dev->adj_list.lower);
netdev_adjacent_sysfs_add(dev, iter->dev,
&dev->adj_list.upper);
}
list_for_each_entry(iter, &dev->adj_list.lower, list) {
if (!net_eq(net,dev_net(iter->dev)))
continue;
netdev_adjacent_sysfs_add(iter->dev, dev,
&iter->dev->adj_list.upper);
netdev_adjacent_sysfs_add(dev, iter->dev,
&dev->adj_list.lower);
}
}
void netdev_adjacent_del_links(struct net_device *dev)
{
struct netdev_adjacent *iter;
struct net *net = dev_net(dev);
list_for_each_entry(iter, &dev->adj_list.upper, list) {
if (!net_eq(net,dev_net(iter->dev)))
continue;
netdev_adjacent_sysfs_del(iter->dev, dev->name,
&iter->dev->adj_list.lower);
netdev_adjacent_sysfs_del(dev, iter->dev->name,
&dev->adj_list.upper);
}
list_for_each_entry(iter, &dev->adj_list.lower, list) {
if (!net_eq(net,dev_net(iter->dev)))
continue;
netdev_adjacent_sysfs_del(iter->dev, dev->name,
&iter->dev->adj_list.upper);
netdev_adjacent_sysfs_del(dev, iter->dev->name,
&dev->adj_list.lower);
}
}
void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) void netdev_adjacent_rename_links(struct net_device *dev, char *oldname)
{ {
struct netdev_adjacent *iter; struct netdev_adjacent *iter;
struct net *net = dev_net(dev);
list_for_each_entry(iter, &dev->adj_list.upper, list) { list_for_each_entry(iter, &dev->adj_list.upper, list) {
if (!net_eq(net,dev_net(iter->dev)))
continue;
netdev_adjacent_sysfs_del(iter->dev, oldname, netdev_adjacent_sysfs_del(iter->dev, oldname,
&iter->dev->adj_list.lower); &iter->dev->adj_list.lower);
netdev_adjacent_sysfs_add(iter->dev, dev, netdev_adjacent_sysfs_add(iter->dev, dev,
...@@ -5167,6 +5222,8 @@ void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) ...@@ -5167,6 +5222,8 @@ void netdev_adjacent_rename_links(struct net_device *dev, char *oldname)
} }
list_for_each_entry(iter, &dev->adj_list.lower, list) { list_for_each_entry(iter, &dev->adj_list.lower, list) {
if (!net_eq(net,dev_net(iter->dev)))
continue;
netdev_adjacent_sysfs_del(iter->dev, oldname, netdev_adjacent_sysfs_del(iter->dev, oldname,
&iter->dev->adj_list.upper); &iter->dev->adj_list.upper);
netdev_adjacent_sysfs_add(iter->dev, dev, netdev_adjacent_sysfs_add(iter->dev, dev,
...@@ -6770,6 +6827,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char ...@@ -6770,6 +6827,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
/* Send a netdev-removed uevent to the old namespace */ /* Send a netdev-removed uevent to the old namespace */
kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE); kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE);
netdev_adjacent_del_links(dev);
/* Actually switch the network namespace */ /* Actually switch the network namespace */
dev_net_set(dev, net); dev_net_set(dev, net);
...@@ -6784,6 +6842,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char ...@@ -6784,6 +6842,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
/* Send a netdev-add uevent to the new namespace */ /* Send a netdev-add uevent to the new namespace */
kobject_uevent(&dev->dev.kobj, KOBJ_ADD); kobject_uevent(&dev->dev.kobj, KOBJ_ADD);
netdev_adjacent_add_links(dev);
/* Fixup kobjects */ /* Fixup kobjects */
err = device_rename(&dev->dev, dev->name); err = device_rename(&dev->dev, dev->name);
......
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