diff options
author | Benjamin Thery <benjamin.thery@bull.net> | 2007-08-25 02:12:08 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-08-26 21:35:43 -0400 |
commit | aaa53c4aba14f14de06419a20e552fe2d8823a33 (patch) | |
tree | f026db39803fa265b588dac40f014cdfd69cbc56 /net/core | |
parent | f424bb9efaee90b752aabcb4e5e95920ee9580bb (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>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev_mcast.c | 14 |
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 | */ |
117 | int dev_mc_sync(struct net_device *to, struct net_device *from) | 117 | int 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 | */ |
157 | void dev_mc_unsync(struct net_device *to, struct net_device *from) | 160 | void 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 | ||