[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20190522192115.22666-10-sashal@kernel.org>
Date: Wed, 22 May 2019 15:15:10 -0400
From: Sasha Levin <sashal@...nel.org>
To: linux-kernel@...r.kernel.org, stable@...r.kernel.org
Cc: Linus Lüssing <linus.luessing@...3.blue>,
syzbot+83f2d54ec6b7e417e13f@...kaller.appspotmail.com,
syzbot+050927a651272b145a5d@...kaller.appspotmail.com,
syzbot+979ffc89b87309b1b94b@...kaller.appspotmail.com,
syzbot+f9f3f388440283da2965@...kaller.appspotmail.com,
Sven Eckelmann <sven@...fation.org>,
Simon Wunderlich <sw@...onwunderlich.de>,
Sasha Levin <sashal@...nel.org>, netdev@...r.kernel.org
Subject: [PATCH AUTOSEL 5.1 010/375] batman-adv: mcast: fix multicast tt/tvlv worker locking
From: Linus Lüssing <linus.luessing@...3.blue>
[ Upstream commit a3c7cd0cdf1107f891aff847ad481e34df727055 ]
Syzbot has reported some issues with the locking assumptions made for
the multicast tt/tvlv worker: It was able to trigger the WARN_ON() in
batadv_mcast_mla_tt_retract() and batadv_mcast_mla_tt_add().
While hard/not reproduceable for us so far it seems that the
delayed_work_pending() we use might not be quite safe from reordering.
Therefore this patch adds an explicit, new spinlock to protect the
update of the mla_list and flags in bat_priv and then removes the
WARN_ON(delayed_work_pending()).
Reported-by: syzbot+83f2d54ec6b7e417e13f@...kaller.appspotmail.com
Reported-by: syzbot+050927a651272b145a5d@...kaller.appspotmail.com
Reported-by: syzbot+979ffc89b87309b1b94b@...kaller.appspotmail.com
Reported-by: syzbot+f9f3f388440283da2965@...kaller.appspotmail.com
Fixes: cbebd363b2e9 ("batman-adv: Use own timer for multicast TT and TVLV updates")
Signed-off-by: Linus Lüssing <linus.luessing@...3.blue>
Signed-off-by: Sven Eckelmann <sven@...fation.org>
Signed-off-by: Simon Wunderlich <sw@...onwunderlich.de>
Signed-off-by: Sasha Levin <sashal@...nel.org>
---
net/batman-adv/main.c | 1 +
net/batman-adv/multicast.c | 11 +++--------
net/batman-adv/types.h | 5 +++++
3 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 75750870cf048..f8725786b5961 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -161,6 +161,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
spin_lock_init(&bat_priv->tt.commit_lock);
spin_lock_init(&bat_priv->gw.list_lock);
#ifdef CONFIG_BATMAN_ADV_MCAST
+ spin_lock_init(&bat_priv->mcast.mla_lock);
spin_lock_init(&bat_priv->mcast.want_lists_lock);
#endif
spin_lock_init(&bat_priv->tvlv.container_list_lock);
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index f91b1b6265cfe..1b985ab89c087 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -325,8 +325,6 @@ static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list)
* translation table except the ones listed in the given mcast_list.
*
* If mcast_list is NULL then all are retracted.
- *
- * Do not call outside of the mcast worker! (or cancel mcast worker first)
*/
static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
struct hlist_head *mcast_list)
@@ -334,8 +332,6 @@ static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
struct batadv_hw_addr *mcast_entry;
struct hlist_node *tmp;
- WARN_ON(delayed_work_pending(&bat_priv->mcast.work));
-
hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list,
list) {
if (mcast_list &&
@@ -359,8 +355,6 @@ static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
*
* Adds multicast listener announcements from the given mcast_list to the
* translation table if they have not been added yet.
- *
- * Do not call outside of the mcast worker! (or cancel mcast worker first)
*/
static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
struct hlist_head *mcast_list)
@@ -368,8 +362,6 @@ static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
struct batadv_hw_addr *mcast_entry;
struct hlist_node *tmp;
- WARN_ON(delayed_work_pending(&bat_priv->mcast.work));
-
if (!mcast_list)
return;
@@ -658,7 +650,10 @@ static void batadv_mcast_mla_update(struct work_struct *work)
priv_mcast = container_of(delayed_work, struct batadv_priv_mcast, work);
bat_priv = container_of(priv_mcast, struct batadv_priv, mcast);
+ spin_lock(&bat_priv->mcast.mla_lock);
__batadv_mcast_mla_update(bat_priv);
+ spin_unlock(&bat_priv->mcast.mla_lock);
+
batadv_mcast_start_timer(bat_priv);
}
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index a21b34ed6548f..ed0f6a519de55 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1223,6 +1223,11 @@ struct batadv_priv_mcast {
/** @bridged: whether the soft interface has a bridge on top */
unsigned char bridged:1;
+ /**
+ * @mla_lock: a lock protecting mla_list and mla_flags
+ */
+ spinlock_t mla_lock;
+
/**
* @num_want_all_unsnoopables: number of nodes wanting unsnoopable IP
* traffic
--
2.20.1
Powered by blists - more mailing lists