[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>

authored by Benjamin Thery and committed by David S. Miller aaa53c4a f424bb9e

+10 -4
+10 -4
net/core/dev_mcast.c
··· 116 */ 117 int dev_mc_sync(struct net_device *to, struct net_device *from) 118 { 119 - struct dev_addr_list *da; 120 int err = 0; 121 122 netif_tx_lock_bh(to); 123 - for (da = from->mc_list; da != NULL; da = da->next) { 124 if (!da->da_synced) { 125 err = __dev_addr_add(&to->mc_list, &to->mc_count, 126 da->da_addr, da->da_addrlen, 0); ··· 136 __dev_addr_delete(&from->mc_list, &from->mc_count, 137 da->da_addr, da->da_addrlen, 0); 138 } 139 } 140 if (!err) 141 __dev_set_rx_mode(to); ··· 159 */ 160 void dev_mc_unsync(struct net_device *to, struct net_device *from) 161 { 162 - struct dev_addr_list *da; 163 164 netif_tx_lock_bh(from); 165 netif_tx_lock_bh(to); 166 167 - for (da = from->mc_list; da != NULL; da = da->next) { 168 if (!da->da_synced) 169 continue; 170 __dev_addr_delete(&to->mc_list, &to->mc_count, ··· 174 da->da_synced = 0; 175 __dev_addr_delete(&from->mc_list, &from->mc_count, 176 da->da_addr, da->da_addrlen, 0); 177 } 178 __dev_set_rx_mode(to); 179
··· 116 */ 117 int dev_mc_sync(struct net_device *to, struct net_device *from) 118 { 119 + struct dev_addr_list *da, *next; 120 int err = 0; 121 122 netif_tx_lock_bh(to); 123 + da = from->mc_list; 124 + while (da != NULL) { 125 + next = da->next; 126 if (!da->da_synced) { 127 err = __dev_addr_add(&to->mc_list, &to->mc_count, 128 da->da_addr, da->da_addrlen, 0); ··· 134 __dev_addr_delete(&from->mc_list, &from->mc_count, 135 da->da_addr, da->da_addrlen, 0); 136 } 137 + da = next; 138 } 139 if (!err) 140 __dev_set_rx_mode(to); ··· 156 */ 157 void dev_mc_unsync(struct net_device *to, struct net_device *from) 158 { 159 + struct dev_addr_list *da, *next; 160 161 netif_tx_lock_bh(from); 162 netif_tx_lock_bh(to); 163 164 + da = from->mc_list; 165 + while (da != NULL) { 166 + next = da->next; 167 if (!da->da_synced) 168 continue; 169 __dev_addr_delete(&to->mc_list, &to->mc_count, ··· 169 da->da_synced = 0; 170 __dev_addr_delete(&from->mc_list, &from->mc_count, 171 da->da_addr, da->da_addrlen, 0); 172 + da = next; 173 } 174 __dev_set_rx_mode(to); 175