aboutsummaryrefslogtreecommitdiff
path: root/net/bridge/br_fdb.c
diff options
context:
space:
mode:
authorToshiaki Makita2014-02-07 16:48:26 +0900
committerDavid S. Miller2014-02-10 14:34:34 -0800
commitac4c8868837a7c70ebb3eaf2298324a3b61b214e (patch)
tree1f7410a566554747361af7b05c2a29b9ca83cccb /net/bridge/br_fdb.c
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/br_fdb.c')
-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)
struct net_port_vlans *pv;
u16 vid = 0;
+ spin_lock_bh(&br->hash_lock);
+
/* If old entry was unassociated with any port, then delete it. */
f = __br_fdb_get(br, br->dev->dev_addr, 0);
if (f && f->is_local && !f->dst)
@@ -204,7 +206,7 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
*/
pv = br_get_vlan_info(br);
if (!pv)
- return;
+ goto out;
for_each_set_bit_from(vid, pv->vlan_bitmap, VLAN_N_VID) {
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)
fdb_delete_local(br, NULL, f);
fdb_insert(br, NULL, newaddr, vid);
}
+out:
+ spin_unlock_bh(&br->hash_lock);
}
void br_fdb_cleanup(unsigned long _data)