diff options
author | Marek Lindner <mareklindner@neomailbox.ch> | 2015-06-17 08:01:36 -0400 |
---|---|---|
committer | Antonio Quartulli <antonio@meshcoding.com> | 2015-08-04 18:31:47 -0400 |
commit | ef72706a0543d0c3a5ab29bd6378fdfb368118d9 (patch) | |
tree | 5a485c9fbb22698333415e7804510ff108d21e20 | |
parent | 354136bcc3c4f40a2813bba8f57ca5267d812d15 (diff) |
batman-adv: protect tt_local_entry from concurrent delete events
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>
-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 38b83c50f936..5e953297d3b2 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
@@ -1037,6 +1037,7 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, | |||
1037 | struct batadv_tt_local_entry *tt_local_entry; | 1037 | struct batadv_tt_local_entry *tt_local_entry; |
1038 | uint16_t flags, curr_flags = BATADV_NO_FLAGS; | 1038 | uint16_t flags, curr_flags = BATADV_NO_FLAGS; |
1039 | struct batadv_softif_vlan *vlan; | 1039 | struct batadv_softif_vlan *vlan; |
1040 | void *tt_entry_exists; | ||
1040 | 1041 | ||
1041 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); | 1042 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
1042 | if (!tt_local_entry) | 1043 | if (!tt_local_entry) |
@@ -1064,7 +1065,15 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, | |||
1064 | * immediately purge it | 1065 | * immediately purge it |
1065 | */ | 1066 | */ |
1066 | batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); | 1067 | batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); |
1067 | hlist_del_rcu(&tt_local_entry->common.hash_entry); | 1068 | |
1069 | tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash, | ||
1070 | batadv_compare_tt, | ||
1071 | batadv_choose_tt, | ||
1072 | &tt_local_entry->common); | ||
1073 | if (!tt_entry_exists) | ||
1074 | goto out; | ||
1075 | |||
1076 | /* extra call to free the local tt entry */ | ||
1068 | batadv_tt_local_entry_free_ref(tt_local_entry); | 1077 | batadv_tt_local_entry_free_ref(tt_local_entry); |
1069 | 1078 | ||
1070 | /* decrease the reference held for this vlan */ | 1079 | /* decrease the reference held for this vlan */ |