diff options
author | Alexander Y. Fomichev <git.user@gmail.com> | 2014-08-25 08:26:45 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-08-25 18:17:43 -0400 |
commit | 4c75431ac3520631f1d9e74aa88407e6374dbbc4 (patch) | |
tree | f56e6a2cbb2622fbe24b1325f7800fd9d0b4305a /net | |
parent | a45e92a599e77ee6a850eabdd0141633fde03915 (diff) |
net: prevent of emerging cross-namespace symlinks
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: Alexander Y. Fomichev <git.user@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/dev.c | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index b65a5051361f..66738e9d66e4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -4889,7 +4889,8 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, | |||
4889 | if (adj->master) | 4889 | if (adj->master) |
4890 | sysfs_remove_link(&(dev->dev.kobj), "master"); | 4890 | sysfs_remove_link(&(dev->dev.kobj), "master"); |
4891 | 4891 | ||
4892 | if (netdev_adjacent_is_neigh_list(dev, dev_list)) | 4892 | if (netdev_adjacent_is_neigh_list(dev, dev_list) && |
4893 | net_eq(dev_net(dev),dev_net(adj_dev))) | ||
4893 | netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); | 4894 | netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); |
4894 | 4895 | ||
4895 | list_del_rcu(&adj->list); | 4896 | list_del_rcu(&adj->list); |
@@ -5159,11 +5160,65 @@ void netdev_upper_dev_unlink(struct net_device *dev, | |||
5159 | } | 5160 | } |
5160 | EXPORT_SYMBOL(netdev_upper_dev_unlink); | 5161 | EXPORT_SYMBOL(netdev_upper_dev_unlink); |
5161 | 5162 | ||
5163 | void netdev_adjacent_add_links(struct net_device *dev) | ||
5164 | { | ||
5165 | struct netdev_adjacent *iter; | ||
5166 | |||
5167 | struct net *net = dev_net(dev); | ||
5168 | |||
5169 | list_for_each_entry(iter, &dev->adj_list.upper, list) { | ||
5170 | if (!net_eq(net,dev_net(iter->dev))) | ||
5171 | continue; | ||
5172 | netdev_adjacent_sysfs_add(iter->dev, dev, | ||
5173 | &iter->dev->adj_list.lower); | ||
5174 | netdev_adjacent_sysfs_add(dev, iter->dev, | ||
5175 | &dev->adj_list.upper); | ||
5176 | } | ||
5177 | |||
5178 | list_for_each_entry(iter, &dev->adj_list.lower, list) { | ||
5179 | if (!net_eq(net,dev_net(iter->dev))) | ||
5180 | continue; | ||
5181 | netdev_adjacent_sysfs_add(iter->dev, dev, | ||
5182 | &iter->dev->adj_list.upper); | ||
5183 | netdev_adjacent_sysfs_add(dev, iter->dev, | ||
5184 | &dev->adj_list.lower); | ||
5185 | } | ||
5186 | } | ||
5187 | |||
5188 | void netdev_adjacent_del_links(struct net_device *dev) | ||
5189 | { | ||
5190 | struct netdev_adjacent *iter; | ||
5191 | |||
5192 | struct net *net = dev_net(dev); | ||
5193 | |||
5194 | list_for_each_entry(iter, &dev->adj_list.upper, list) { | ||
5195 | if (!net_eq(net,dev_net(iter->dev))) | ||
5196 | continue; | ||
5197 | netdev_adjacent_sysfs_del(iter->dev, dev->name, | ||
5198 | &iter->dev->adj_list.lower); | ||
5199 | netdev_adjacent_sysfs_del(dev, iter->dev->name, | ||
5200 | &dev->adj_list.upper); | ||
5201 | } | ||
5202 | |||
5203 | list_for_each_entry(iter, &dev->adj_list.lower, list) { | ||
5204 | if (!net_eq(net,dev_net(iter->dev))) | ||
5205 | continue; | ||
5206 | netdev_adjacent_sysfs_del(iter->dev, dev->name, | ||
5207 | &iter->dev->adj_list.upper); | ||
5208 | netdev_adjacent_sysfs_del(dev, iter->dev->name, | ||
5209 | &dev->adj_list.lower); | ||
5210 | } | ||
5211 | } | ||
5212 | |||
5162 | void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) | 5213 | void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) |
5163 | { | 5214 | { |
5164 | struct netdev_adjacent *iter; | 5215 | struct netdev_adjacent *iter; |
5165 | 5216 | ||
5217 | struct net *net = dev_net(dev); | ||
5218 | |||
5166 | list_for_each_entry(iter, &dev->adj_list.upper, list) { | 5219 | list_for_each_entry(iter, &dev->adj_list.upper, list) { |
5220 | if (!net_eq(net,dev_net(iter->dev))) | ||
5221 | continue; | ||
5167 | netdev_adjacent_sysfs_del(iter->dev, oldname, | 5222 | netdev_adjacent_sysfs_del(iter->dev, oldname, |
5168 | &iter->dev->adj_list.lower); | 5223 | &iter->dev->adj_list.lower); |
5169 | netdev_adjacent_sysfs_add(iter->dev, dev, | 5224 | netdev_adjacent_sysfs_add(iter->dev, dev, |
@@ -5171,6 +5226,8 @@ void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) | |||
5171 | } | 5226 | } |
5172 | 5227 | ||
5173 | list_for_each_entry(iter, &dev->adj_list.lower, list) { | 5228 | list_for_each_entry(iter, &dev->adj_list.lower, list) { |
5229 | if (!net_eq(net,dev_net(iter->dev))) | ||
5230 | continue; | ||
5174 | netdev_adjacent_sysfs_del(iter->dev, oldname, | 5231 | netdev_adjacent_sysfs_del(iter->dev, oldname, |
5175 | &iter->dev->adj_list.upper); | 5232 | &iter->dev->adj_list.upper); |
5176 | netdev_adjacent_sysfs_add(iter->dev, dev, | 5233 | netdev_adjacent_sysfs_add(iter->dev, dev, |
@@ -6773,6 +6830,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char | |||
6773 | 6830 | ||
6774 | /* Send a netdev-removed uevent to the old namespace */ | 6831 | /* Send a netdev-removed uevent to the old namespace */ |
6775 | kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE); | 6832 | kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE); |
6833 | netdev_adjacent_del_links(dev); | ||
6776 | 6834 | ||
6777 | /* Actually switch the network namespace */ | 6835 | /* Actually switch the network namespace */ |
6778 | dev_net_set(dev, net); | 6836 | dev_net_set(dev, net); |
@@ -6787,6 +6845,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char | |||
6787 | 6845 | ||
6788 | /* Send a netdev-add uevent to the new namespace */ | 6846 | /* Send a netdev-add uevent to the new namespace */ |
6789 | kobject_uevent(&dev->dev.kobj, KOBJ_ADD); | 6847 | kobject_uevent(&dev->dev.kobj, KOBJ_ADD); |
6848 | netdev_adjacent_add_links(dev); | ||
6790 | 6849 | ||
6791 | /* Fixup kobjects */ | 6850 | /* Fixup kobjects */ |
6792 | err = device_rename(&dev->dev, dev->name); | 6851 | err = device_rename(&dev->dev, dev->name); |