aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Eckelmann <sven@narfation.org>2018-08-12 15:04:41 -0400
committerSimon Wunderlich <sw@simonwunderlich.de>2018-09-06 07:55:20 -0400
commitdff9bc42ab0b2d38c5e90ddd79b238fed5b4c7ad (patch)
treeedb50bc7ab394d558b537397645dc7600c21e473
parenta25bab9d723a08bd0bdafb1529faf9094c690b70 (diff)
batman-adv: Prevent duplicated gateway_node entry
The function batadv_gw_node_add is responsible for adding new gw_node to the gateway_list. It is expecting that the caller already checked that there is not already an entry with the same key or not. 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: c6c8fea29769 ("net: Add batman-adv meshing protocol") Signed-off-by: Sven Eckelmann <sven@narfation.org> Acked-by: Marek Lindner <mareklindner@neomailbox.ch> Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
-rw-r--r--net/batman-adv/gateway_client.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 8b198ee798c9..140c61a3f1ec 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -32,6 +32,7 @@
32#include <linux/kernel.h> 32#include <linux/kernel.h>
33#include <linux/kref.h> 33#include <linux/kref.h>
34#include <linux/list.h> 34#include <linux/list.h>
35#include <linux/lockdep.h>
35#include <linux/netdevice.h> 36#include <linux/netdevice.h>
36#include <linux/netlink.h> 37#include <linux/netlink.h>
37#include <linux/rculist.h> 38#include <linux/rculist.h>
@@ -348,6 +349,9 @@ out:
348 * @bat_priv: the bat priv with all the soft interface information 349 * @bat_priv: the bat priv with all the soft interface information
349 * @orig_node: originator announcing gateway capabilities 350 * @orig_node: originator announcing gateway capabilities
350 * @gateway: announced bandwidth information 351 * @gateway: announced bandwidth information
352 *
353 * Has to be called with the appropriate locks being acquired
354 * (gw.list_lock).
351 */ 355 */
352static void batadv_gw_node_add(struct batadv_priv *bat_priv, 356static void batadv_gw_node_add(struct batadv_priv *bat_priv,
353 struct batadv_orig_node *orig_node, 357 struct batadv_orig_node *orig_node,
@@ -355,6 +359,8 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
355{ 359{
356 struct batadv_gw_node *gw_node; 360 struct batadv_gw_node *gw_node;
357 361
362 lockdep_assert_held(&bat_priv->gw.list_lock);
363
358 if (gateway->bandwidth_down == 0) 364 if (gateway->bandwidth_down == 0)
359 return; 365 return;
360 366
@@ -369,10 +375,8 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
369 gw_node->bandwidth_down = ntohl(gateway->bandwidth_down); 375 gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
370 gw_node->bandwidth_up = ntohl(gateway->bandwidth_up); 376 gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
371 377
372 spin_lock_bh(&bat_priv->gw.list_lock);
373 kref_get(&gw_node->refcount); 378 kref_get(&gw_node->refcount);
374 hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.gateway_list); 379 hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.gateway_list);
375 spin_unlock_bh(&bat_priv->gw.list_lock);
376 380
377 batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 381 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
378 "Found new gateway %pM -> gw bandwidth: %u.%u/%u.%u MBit\n", 382 "Found new gateway %pM -> gw bandwidth: %u.%u/%u.%u MBit\n",
@@ -428,11 +432,14 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv,
428{ 432{
429 struct batadv_gw_node *gw_node, *curr_gw = NULL; 433 struct batadv_gw_node *gw_node, *curr_gw = NULL;
430 434
435 spin_lock_bh(&bat_priv->gw.list_lock);
431 gw_node = batadv_gw_node_get(bat_priv, orig_node); 436 gw_node = batadv_gw_node_get(bat_priv, orig_node);
432 if (!gw_node) { 437 if (!gw_node) {
433 batadv_gw_node_add(bat_priv, orig_node, gateway); 438 batadv_gw_node_add(bat_priv, orig_node, gateway);
439 spin_unlock_bh(&bat_priv->gw.list_lock);
434 goto out; 440 goto out;
435 } 441 }
442 spin_unlock_bh(&bat_priv->gw.list_lock);
436 443
437 if (gw_node->bandwidth_down == ntohl(gateway->bandwidth_down) && 444 if (gw_node->bandwidth_down == ntohl(gateway->bandwidth_down) &&
438 gw_node->bandwidth_up == ntohl(gateway->bandwidth_up)) 445 gw_node->bandwidth_up == ntohl(gateway->bandwidth_up))