| From foo@baz Thu Oct 18 11:08:35 CEST 2018 |
| From: Sven Eckelmann <sven@narfation.org> |
| Date: Sun, 12 Aug 2018 21:04:45 +0200 |
| Subject: batman-adv: Prevent duplicated tvlv handler |
| |
| From: Sven Eckelmann <sven@narfation.org> |
| |
| [ Upstream commit ae3cdc97dc10c7a3b31f297dab429bfb774c9ccb ] |
| |
| 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: ef26157747d4 ("batman-adv: tvlv - basic infrastructure") |
| Signed-off-by: Sven Eckelmann <sven@narfation.org> |
| Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/batman-adv/tvlv.c | 8 ++++++-- |
| 1 file changed, 6 insertions(+), 2 deletions(-) |
| |
| --- a/net/batman-adv/tvlv.c |
| +++ b/net/batman-adv/tvlv.c |
| @@ -529,15 +529,20 @@ void batadv_tvlv_handler_register(struct |
| { |
| 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; |
| @@ -547,7 +552,6 @@ void batadv_tvlv_handler_register(struct |
| 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); |