diff options
author | Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> | 2014-02-07 02:48:26 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-02-10 17:34:34 -0500 |
commit | ac4c8868837a7c70ebb3eaf2298324a3b61b214e (patch) | |
tree | 1f7410a566554747361af7b05c2a29b9ca83cccb /net/bridge | |
parent | 424bb9c97cc1992018950485ca7410779b8ea21d (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.c | 6 |
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 | } |
217 | out: | ||
218 | spin_unlock_bh(&br->hash_lock); | ||
215 | } | 219 | } |
216 | 220 | ||
217 | void br_fdb_cleanup(unsigned long _data) | 221 | void br_fdb_cleanup(unsigned long _data) |