This is a note to let you know that I've just added the patch titled batman-adv: avoid potential race condition when adding a new neighbour to the 3.13-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: batman-adv-avoid-potential-race-condition-when-adding-a-new-neighbour.patch and it can be found in the queue-3.13 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From foo@baz Thu Feb 27 20:11:26 PST 2014 From: Antonio Quartulli <antonio@xxxxxxxxxxxxx> Date: Wed, 29 Jan 2014 11:25:12 +0100 Subject: batman-adv: avoid potential race condition when adding a new neighbour From: Antonio Quartulli <antonio@xxxxxxxxxxxxx> [ Upstream commit 08bf0ed29c7ded45c477d08618220dd200c3524a ] When adding a new neighbour it is important to atomically perform the following: - check if the neighbour already exists - append the neighbour to the proper list If the two operations are not performed in an atomic context it is possible that two concurrent insertions add the same neighbour twice. Signed-off-by: Antonio Quartulli <antonio@xxxxxxxxxxxxx> Signed-off-by: Marek Lindner <mareklindner@xxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- net/batman-adv/bat_iv_ogm.c | 22 ++++++++++++++++------ net/batman-adv/originator.c | 36 ++++++++++++++++++++++++++++++++++++ net/batman-adv/originator.h | 4 ++++ 3 files changed, 56 insertions(+), 6 deletions(-) --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -268,7 +268,7 @@ batadv_iv_ogm_neigh_new(struct batadv_ha struct batadv_orig_node *orig_neigh) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); - struct batadv_neigh_node *neigh_node; + struct batadv_neigh_node *neigh_node, *tmp_neigh_node; neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, orig_node); if (!neigh_node) @@ -276,14 +276,24 @@ batadv_iv_ogm_neigh_new(struct batadv_ha spin_lock_init(&neigh_node->bat_iv.lq_update_lock); - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Creating new neighbor %pM for orig_node %pM on interface %s\n", - neigh_addr, orig_node->orig, hard_iface->net_dev->name); - spin_lock_bh(&orig_node->neigh_list_lock); - hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); + tmp_neigh_node = batadv_neigh_node_get(orig_node, hard_iface, + neigh_addr); + if (!tmp_neigh_node) { + hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); + } else { + kfree(neigh_node); + batadv_hardif_free_ref(hard_iface); + neigh_node = tmp_neigh_node; + } spin_unlock_bh(&orig_node->neigh_list_lock); + if (!tmp_neigh_node) + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Creating new neighbor %pM for orig_node %pM on interface %s\n", + neigh_addr, orig_node->orig, + hard_iface->net_dev->name); + out: return neigh_node; } --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -511,6 +511,42 @@ void batadv_purge_orig_ref(struct batadv _batadv_purge_orig(bat_priv); } +/** + * batadv_neigh_node_get - retrieve a neighbour from the list + * @orig_node: originator which the neighbour belongs to + * @hard_iface: the interface where this neighbour is connected to + * @addr: the address of the neighbour + * + * Looks for and possibly returns a neighbour belonging to this originator list + * which is connected through the provided hard interface. + * Returns NULL if the neighbour is not found. + */ +struct batadv_neigh_node * +batadv_neigh_node_get(const struct batadv_orig_node *orig_node, + const struct batadv_hard_iface *hard_iface, + const uint8_t *addr) +{ + struct batadv_neigh_node *tmp_neigh_node, *res = NULL; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tmp_neigh_node, &orig_node->neigh_list, list) { + if (!batadv_compare_eth(tmp_neigh_node->addr, addr)) + continue; + + if (tmp_neigh_node->if_incoming != hard_iface) + continue; + + if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + continue; + + res = tmp_neigh_node; + break; + } + rcu_read_unlock(); + + return res; +} + int batadv_orig_seq_print_text(struct seq_file *seq, void *offset) { struct net_device *net_dev = (struct net_device *)seq->private; --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -31,6 +31,10 @@ void batadv_orig_node_free_ref_now(struc struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, const uint8_t *addr); struct batadv_neigh_node * +batadv_neigh_node_get(const struct batadv_orig_node *orig_node, + const struct batadv_hard_iface *hard_iface, + const uint8_t *addr); +struct batadv_neigh_node * batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, const uint8_t *neigh_addr, struct batadv_orig_node *orig_node); Patches currently in stable-queue which might be from antonio@xxxxxxxxxxxxx are queue-3.13/batman-adv-avoid-potential-race-condition-when-adding-a-new-neighbour.patch queue-3.13/batman-adv-fix-tt-crc-computation-by-ensuring-byte-order.patch queue-3.13/batman-adv-free-skb-on-tvlv-parsing-success.patch -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html