aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorToshiaki Makita <makita.toshiaki@lab.ntt.co.jp>2014-02-07 02:48:26 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-10 17:34:34 -0500
commitac4c8868837a7c70ebb3eaf2298324a3b61b214e (patch)
tree1f7410a566554747361af7b05c2a29b9ca83cccb /net/bridge
parent424bb9c97cc1992018950485ca7410779b8ea21d (diff)
bridge: Prevent possible race condition in br_fdb_change_mac_address
br_fdb_change_mac_address() calls fdb_insert()/fdb_delete() without br->hash_lock. These hash list updates are racy with br_fdb_update()/br_fdb_cleanup(). Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> Acked-by: Vlad Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_fdb.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 0426dff4b3fd..9203d5a1943f 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -191,6 +191,8 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
191 struct net_port_vlans *pv; 191 struct net_port_vlans *pv;
192 u16 vid = 0; 192 u16 vid = 0;
193 193
194 spin_lock_bh(&br->hash_lock);
195
194 /* If old entry was unassociated with any port, then delete it. */ 196 /* If old entry was unassociated with any port, then delete it. */
195 f = __br_fdb_get(br, br->dev->dev_addr, 0); 197 f = __br_fdb_get(br, br->dev->dev_addr, 0);
196 if (f && f->is_local && !f->dst) 198 if (f && f->is_local && !f->dst)
@@ -204,7 +206,7 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
204 */ 206 */
205 pv = br_get_vlan_info(br); 207 pv = br_get_vlan_info(br);
206 if (!pv) 208 if (!pv)
207 return; 209 goto out;
208 210
209 for_each_set_bit_from(vid, pv->vlan_bitmap, VLAN_N_VID) { 211 for_each_set_bit_from(vid, pv->vlan_bitmap, VLAN_N_VID) {
210 f = __br_fdb_get(br, br->dev->dev_addr, vid); 212 f = __br_fdb_get(br, br->dev->dev_addr, vid);
@@ -212,6 +214,8 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
212 fdb_delete_local(br, NULL, f); 214 fdb_delete_local(br, NULL, f);
213 fdb_insert(br, NULL, newaddr, vid); 215 fdb_insert(br, NULL, newaddr, vid);
214 } 216 }
217out:
218 spin_unlock_bh(&br->hash_lock);
215} 219}
216 220
217void br_fdb_cleanup(unsigned long _data) 221void br_fdb_cleanup(unsigned long _data)