57 lines
2.1 KiB
Diff
57 lines
2.1 KiB
Diff
From: Sven Eckelmann <sven@narfation.org>
|
|
Date: Thu, 6 Sep 2018 14:35:28 +0200
|
|
Subject: batman-adv: Prevent duplicated tvlv handler
|
|
|
|
The function batadv_tvlv_handler_register is responsible for adding new
|
|
tvlv_handler to the handler_list. It first checks whether the entry
|
|
already is in the list or not. If it is, then the creation of a new entry
|
|
is aborted.
|
|
|
|
But the lock for the list is only held when the list is really modified.
|
|
This could lead to duplicated entries because another context could create
|
|
an entry with the same key between the check and the list manipulation.
|
|
|
|
The check and the manipulation of the list must therefore be in the same
|
|
locked code section.
|
|
|
|
Fixes: 0b6aa0d43767 ("batman-adv: tvlv - basic infrastructure")
|
|
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
|
Acked-by: Marek Lindner <mareklindner@neomailbox.ch>
|
|
|
|
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/acabad79e01740525cf4ff8ce6e9a210b683d420
|
|
|
|
diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c
|
|
index a783420356ae0cd4a6273b3b7a04781242e37a82..1eccc49a793004db82346f9dc3be7fcc2386417b 100644
|
|
--- a/net/batman-adv/tvlv.c
|
|
+++ b/net/batman-adv/tvlv.c
|
|
@@ -528,15 +528,20 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv,
|
|
{
|
|
struct batadv_tvlv_handler *tvlv_handler;
|
|
|
|
+ spin_lock_bh(&bat_priv->tvlv.handler_list_lock);
|
|
+
|
|
tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version);
|
|
if (tvlv_handler) {
|
|
+ spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
|
|
batadv_tvlv_handler_put(tvlv_handler);
|
|
return;
|
|
}
|
|
|
|
tvlv_handler = kzalloc(sizeof(*tvlv_handler), GFP_ATOMIC);
|
|
- if (!tvlv_handler)
|
|
+ if (!tvlv_handler) {
|
|
+ spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
|
|
return;
|
|
+ }
|
|
|
|
tvlv_handler->ogm_handler = optr;
|
|
tvlv_handler->unicast_handler = uptr;
|
|
@@ -546,7 +551,6 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv,
|
|
kref_init(&tvlv_handler->refcount);
|
|
INIT_HLIST_NODE(&tvlv_handler->list);
|
|
|
|
- spin_lock_bh(&bat_priv->tvlv.handler_list_lock);
|
|
kref_get(&tvlv_handler->refcount);
|
|
hlist_add_head_rcu(&tvlv_handler->list, &bat_priv->tvlv.handler_list);
|
|
spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
|