1 |
commit 4c75431ac3520631f1d9e74aa88407e6374dbbc4 |
2 |
Author: Alexander Y. Fomichev <git.user@gmail.com> |
3 |
Date: Mon Aug 25 16:26:20 2014 +0400 |
4 |
|
5 |
net: prevent of emerging cross-namespace symlinks |
6 |
|
7 |
Code manipulating sysfs symlinks on adjacent net_devices(s) |
8 |
currently doesn't take into account that devices potentially |
9 |
belong to different namespaces. |
10 |
|
11 |
This patch trying to fix an issue as follows: |
12 |
- check for net_ns before creating / deleting symlink. |
13 |
for now only netdev_adjacent_rename_links and |
14 |
__netdev_adjacent_dev_remove are affected, afaics |
15 |
__netdev_adjacent_dev_insert implies both net_devs |
16 |
belong to the same namespace. |
17 |
- Drop all existing symlinks to / from all adj_devs before |
18 |
switching namespace and recreate them just after. |
19 |
|
20 |
Signed-off-by: Alexander Y. Fomichev <git.user@gmail.com> |
21 |
Signed-off-by: David S. Miller <davem@davemloft.net> |
22 |
--- |
23 |
net/core/dev.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
24 |
1 file changed, 60 insertions(+), 1 deletion(-) |
25 |
|
26 |
diff --git a/net/core/dev.c b/net/core/dev.c |
27 |
index b65a505..66738e9 100644 |
28 |
--- a/net/core/dev.c |
29 |
+++ b/net/core/dev.c |
30 |
@@ -4889,7 +4889,8 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, |
31 |
if (adj->master) |
32 |
sysfs_remove_link(&(dev->dev.kobj), "master"); |
33 |
|
34 |
- if (netdev_adjacent_is_neigh_list(dev, dev_list)) |
35 |
+ if (netdev_adjacent_is_neigh_list(dev, dev_list) && |
36 |
+ net_eq(dev_net(dev),dev_net(adj_dev))) |
37 |
netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); |
38 |
|
39 |
list_del_rcu(&adj->list); |
40 |
@@ -5159,11 +5160,65 @@ void netdev_upper_dev_unlink(struct net_device *dev, |
41 |
} |
42 |
EXPORT_SYMBOL(netdev_upper_dev_unlink); |
43 |
|
44 |
+void netdev_adjacent_add_links(struct net_device *dev) |
45 |
+{ |
46 |
+ struct netdev_adjacent *iter; |
47 |
+ |
48 |
+ struct net *net = dev_net(dev); |
49 |
+ |
50 |
+ list_for_each_entry(iter, &dev->adj_list.upper, list) { |
51 |
+ if (!net_eq(net,dev_net(iter->dev))) |
52 |
+ continue; |
53 |
+ netdev_adjacent_sysfs_add(iter->dev, dev, |
54 |
+ &iter->dev->adj_list.lower); |
55 |
+ netdev_adjacent_sysfs_add(dev, iter->dev, |
56 |
+ &dev->adj_list.upper); |
57 |
+ } |
58 |
+ |
59 |
+ list_for_each_entry(iter, &dev->adj_list.lower, list) { |
60 |
+ if (!net_eq(net,dev_net(iter->dev))) |
61 |
+ continue; |
62 |
+ netdev_adjacent_sysfs_add(iter->dev, dev, |
63 |
+ &iter->dev->adj_list.upper); |
64 |
+ netdev_adjacent_sysfs_add(dev, iter->dev, |
65 |
+ &dev->adj_list.lower); |
66 |
+ } |
67 |
+} |
68 |
+ |
69 |
+void netdev_adjacent_del_links(struct net_device *dev) |
70 |
+{ |
71 |
+ struct netdev_adjacent *iter; |
72 |
+ |
73 |
+ struct net *net = dev_net(dev); |
74 |
+ |
75 |
+ list_for_each_entry(iter, &dev->adj_list.upper, list) { |
76 |
+ if (!net_eq(net,dev_net(iter->dev))) |
77 |
+ continue; |
78 |
+ netdev_adjacent_sysfs_del(iter->dev, dev->name, |
79 |
+ &iter->dev->adj_list.lower); |
80 |
+ netdev_adjacent_sysfs_del(dev, iter->dev->name, |
81 |
+ &dev->adj_list.upper); |
82 |
+ } |
83 |
+ |
84 |
+ list_for_each_entry(iter, &dev->adj_list.lower, list) { |
85 |
+ if (!net_eq(net,dev_net(iter->dev))) |
86 |
+ continue; |
87 |
+ netdev_adjacent_sysfs_del(iter->dev, dev->name, |
88 |
+ &iter->dev->adj_list.upper); |
89 |
+ netdev_adjacent_sysfs_del(dev, iter->dev->name, |
90 |
+ &dev->adj_list.lower); |
91 |
+ } |
92 |
+} |
93 |
+ |
94 |
void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) |
95 |
{ |
96 |
struct netdev_adjacent *iter; |
97 |
|
98 |
+ struct net *net = dev_net(dev); |
99 |
+ |
100 |
list_for_each_entry(iter, &dev->adj_list.upper, list) { |
101 |
+ if (!net_eq(net,dev_net(iter->dev))) |
102 |
+ continue; |
103 |
netdev_adjacent_sysfs_del(iter->dev, oldname, |
104 |
&iter->dev->adj_list.lower); |
105 |
netdev_adjacent_sysfs_add(iter->dev, dev, |
106 |
@@ -5171,6 +5226,8 @@ void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) |
107 |
} |
108 |
|
109 |
list_for_each_entry(iter, &dev->adj_list.lower, list) { |
110 |
+ if (!net_eq(net,dev_net(iter->dev))) |
111 |
+ continue; |
112 |
netdev_adjacent_sysfs_del(iter->dev, oldname, |
113 |
&iter->dev->adj_list.upper); |
114 |
netdev_adjacent_sysfs_add(iter->dev, dev, |
115 |
@@ -6773,6 +6830,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char |
116 |
|
117 |
/* Send a netdev-removed uevent to the old namespace */ |
118 |
kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE); |
119 |
+ netdev_adjacent_del_links(dev); |
120 |
|
121 |
/* Actually switch the network namespace */ |
122 |
dev_net_set(dev, net); |
123 |
@@ -6787,6 +6845,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char |
124 |
|
125 |
/* Send a netdev-add uevent to the new namespace */ |
126 |
kobject_uevent(&dev->dev.kobj, KOBJ_ADD); |
127 |
+ netdev_adjacent_add_links(dev); |
128 |
|
129 |
/* Fixup kobjects */ |
130 |
err = device_rename(&dev->dev, dev->name); |