aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Thery <benjamin.thery@bull.net>2007-08-25 02:12:08 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-08-26 21:35:43 -0400
commitaaa53c4aba14f14de06419a20e552fe2d8823a33 (patch)
treef026db39803fa265b588dac40f014cdfd69cbc56
parentf424bb9efaee90b752aabcb4e5e95920ee9580bb (diff)
[NET]: Fix crash in dev_mc_sync()/dev_mc_unsync()
This patch fixes a crash that may occur when the routine dev_mc_sync() deletes an address from the list it is currently going through. It saves the pointer to the next element before deleting the current one. The problem may also exist in dev_mc_unsync(). Signed-off-by: Benjamin Thery <benjamin.thery@bull.net> Acked-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/core/dev_mcast.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index 99aece1aeccf..20330c572610 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -116,11 +116,13 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
116 */ 116 */
117int dev_mc_sync(struct net_device *to, struct net_device *from) 117int dev_mc_sync(struct net_device *to, struct net_device *from)
118{ 118{
119 struct dev_addr_list *da; 119 struct dev_addr_list *da, *next;
120 int err = 0; 120 int err = 0;
121 121
122 netif_tx_lock_bh(to); 122 netif_tx_lock_bh(to);
123 for (da = from->mc_list; da != NULL; da = da->next) { 123 da = from->mc_list;
124 while (da != NULL) {
125 next = da->next;
124 if (!da->da_synced) { 126 if (!da->da_synced) {
125 err = __dev_addr_add(&to->mc_list, &to->mc_count, 127 err = __dev_addr_add(&to->mc_list, &to->mc_count,
126 da->da_addr, da->da_addrlen, 0); 128 da->da_addr, da->da_addrlen, 0);
@@ -134,6 +136,7 @@ int dev_mc_sync(struct net_device *to, struct net_device *from)
134 __dev_addr_delete(&from->mc_list, &from->mc_count, 136 __dev_addr_delete(&from->mc_list, &from->mc_count,
135 da->da_addr, da->da_addrlen, 0); 137 da->da_addr, da->da_addrlen, 0);
136 } 138 }
139 da = next;
137 } 140 }
138 if (!err) 141 if (!err)
139 __dev_set_rx_mode(to); 142 __dev_set_rx_mode(to);
@@ -156,12 +159,14 @@ EXPORT_SYMBOL(dev_mc_sync);
156 */ 159 */
157void dev_mc_unsync(struct net_device *to, struct net_device *from) 160void dev_mc_unsync(struct net_device *to, struct net_device *from)
158{ 161{
159 struct dev_addr_list *da; 162 struct dev_addr_list *da, *next;
160 163
161 netif_tx_lock_bh(from); 164 netif_tx_lock_bh(from);
162 netif_tx_lock_bh(to); 165 netif_tx_lock_bh(to);
163 166
164 for (da = from->mc_list; da != NULL; da = da->next) { 167 da = from->mc_list;
168 while (da != NULL) {
169 next = da->next;
165 if (!da->da_synced) 170 if (!da->da_synced)
166 continue; 171 continue;
167 __dev_addr_delete(&to->mc_list, &to->mc_count, 172 __dev_addr_delete(&to->mc_list, &to->mc_count,
@@ -169,6 +174,7 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from)
169 da->da_synced = 0; 174 da->da_synced = 0;
170 __dev_addr_delete(&from->mc_list, &from->mc_count, 175 __dev_addr_delete(&from->mc_list, &from->mc_count,
171 da->da_addr, da->da_addrlen, 0); 176 da->da_addr, da->da_addrlen, 0);
177 da = next;
172 } 178 }
173 __dev_set_rx_mode(to); 179 __dev_set_rx_mode(to);
174 180