diff options
Diffstat (limited to 'batman-adv/patches/0028-batman-adv-Reduce-tt_local-hash-refcnt-only-for-remo.patch')
| -rw-r--r-- | batman-adv/patches/0028-batman-adv-Reduce-tt_local-hash-refcnt-only-for-remo.patch | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/batman-adv/patches/0028-batman-adv-Reduce-tt_local-hash-refcnt-only-for-remo.patch b/batman-adv/patches/0028-batman-adv-Reduce-tt_local-hash-refcnt-only-for-remo.patch new file mode 100644 index 0000000..a6ffb25 --- /dev/null +++ b/batman-adv/patches/0028-batman-adv-Reduce-tt_local-hash-refcnt-only-for-remo.patch @@ -0,0 +1,69 @@ +From: Sven Eckelmann <sven@narfation.org> +Date: Sat, 23 Feb 2019 15:09:05 +0100 +Subject: batman-adv: Reduce tt_local hash refcnt only for removed entry + +The batadv_hash_remove is a function which searches the hashtable for an +entry using a needle, a hashtable bucket selection function and a compare +function. It will lock the bucket list and delete an entry when the compare +function matches it with the needle. It returns the pointer to the +hlist_node which matches or NULL when no entry matches the needle. + +The batadv_tt_local_remove is not itself protected in anyway to avoid that +any other function is modifying the hashtable between the search for the +entry and the call to batadv_hash_remove. It can therefore happen that the +entry either doesn't exist anymore or an entry was deleted which is not the +same object as the needle. In such an situation, the reference counter (for +the reference stored in the hashtable) must not be reduced for the needle. +Instead the reference counter of the actually removed entry has to be +reduced. + +Otherwise the reference counter will underflow and the object might be +freed before all its references were dropped. The kref helpers reported +this problem as: + + refcount_t: underflow; use-after-free. + +Fixes: af912d77181f ("batman-adv: protect tt_local_entry from concurrent delete events") +Signed-off-by: Sven Eckelmann <sven@narfation.org> + +Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/0c86a0511e97de502276900c5d6f22b09e042d21 + +diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c +index 7502cb54c152d06d78c88d9f8fb841cada9f3b5d..d2ecfdbdc64956b238f0554b4c354df9a9e9f26a 100644 +--- a/net/batman-adv/translation-table.c ++++ b/net/batman-adv/translation-table.c +@@ -1332,9 +1332,10 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, + unsigned short vid, const char *message, + bool roaming) + { ++ struct batadv_tt_local_entry *tt_removed_entry; + struct batadv_tt_local_entry *tt_local_entry; + u16 flags, curr_flags = BATADV_NO_FLAGS; +- void *tt_entry_exists; ++ struct hlist_node *tt_removed_node; + + tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); + if (!tt_local_entry) +@@ -1363,15 +1364,18 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, + */ + batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); + +- tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash, ++ tt_removed_node = batadv_hash_remove(bat_priv->tt.local_hash, + batadv_compare_tt, + batadv_choose_tt, + &tt_local_entry->common); +- if (!tt_entry_exists) ++ if (!tt_removed_node) + goto out; + +- /* extra call to free the local tt entry */ +- batadv_tt_local_entry_put(tt_local_entry); ++ /* drop reference of remove hash entry */ ++ tt_removed_entry = hlist_entry(tt_removed_node, ++ struct batadv_tt_local_entry, ++ common.hash_entry); ++ batadv_tt_local_entry_put(tt_removed_entry); + + out: + if (tt_local_entry) |
