diff options
author | Marek Lindner <mareklindner@neomailbox.ch> | 2015-06-17 20:01:36 +0800 |
---|---|---|
committer | Sasha Levin <sasha.levin@oracle.com> | 2015-10-27 22:13:56 -0400 |
commit | 61b027c7cee9948bbd68d0ca0cca1830ca33d712 (patch) | |
tree | ac0d967e04ae80ba1b5325fff01e9ca4c781fb83 | |
parent | b544c9930ce29ddcd97abc307df72ce5a735f209 (diff) | |
download | linux-rt-61b027c7cee9948bbd68d0ca0cca1830ca33d712.tar.gz |
batman-adv: protect tt_local_entry from concurrent delete events
[ Upstream commit ef72706a0543d0c3a5ab29bd6378fdfb368118d9 ]
The tt_local_entry deletion performed in batadv_tt_local_remove() was neither
protecting against simultaneous deletes nor checking whether the element was
still part of the list before calling hlist_del_rcu().
Replacing the hlist_del_rcu() call with batadv_hash_remove() provides adequate
protection via hash spinlocks as well as an is-element-still-in-hash check to
avoid 'blind' hash removal.
Fixes: 068ee6e204e1 ("batman-adv: roaming handling mechanism redesign")
Reported-by: alfonsname@web.de
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
-rw-r--r-- | net/batman-adv/translation-table.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 5f59e7f899a0..c8c5184a92bb 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1015,6 +1015,7 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, struct batadv_tt_local_entry *tt_local_entry; uint16_t flags, curr_flags = BATADV_NO_FLAGS; struct batadv_softif_vlan *vlan; + void *tt_entry_exists; tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); if (!tt_local_entry) @@ -1042,7 +1043,15 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, * immediately purge it */ batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); - hlist_del_rcu(&tt_local_entry->common.hash_entry); + + tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash, + batadv_compare_tt, + batadv_choose_tt, + &tt_local_entry->common); + if (!tt_entry_exists) + goto out; + + /* extra call to free the local tt entry */ batadv_tt_local_entry_free_ref(tt_local_entry); /* decrease the reference held for this vlan */ |