summaryrefslogtreecommitdiff
path: root/batman-adv/patches/0028-batman-adv-Reduce-tt_local-hash-refcnt-only-for-remo.patch
diff options
context:
space:
mode:
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.patch69
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)