Skip to content

Commit

Permalink
netlink: disable IRQs for netlink_lock_table()
Browse files Browse the repository at this point in the history
[ Upstream commit 1d482e6 ]

Syzbot reports that in mac80211 we have a potential deadlock
between our "local->stop_queue_reasons_lock" (spinlock) and
netlink's nl_table_lock (rwlock). This is because there's at
least one situation in which we might try to send a netlink
message with this spinlock held while it is also possible to
take the spinlock from a hardirq context, resulting in the
following deadlock scenario reported by lockdep:

       CPU0                    CPU1
       ----                    ----
  lock(nl_table_lock);
                               local_irq_disable();
                               lock(&local->queue_stop_reason_lock);
                               lock(nl_table_lock);
  <Interrupt>
    lock(&local->queue_stop_reason_lock);

This seems valid, we can take the queue_stop_reason_lock in
any kind of context ("CPU0"), and call ieee80211_report_ack_skb()
with the spinlock held and IRQs disabled ("CPU1") in some
code path (ieee80211_do_stop() via ieee80211_free_txskb()).

Short of disallowing netlink use in scenarios like these
(which would be rather complex in mac80211's case due to
the deep callchain), it seems the only fix for this is to
disable IRQs while nl_table_lock is held to avoid hitting
this scenario, this disallows the "CPU0" portion of the
reported deadlock.

Note that the writer side (netlink_table_grab()) already
disables IRQs for this lock.

Unfortunately though, this seems like a huge hammer, and
maybe the whole netlink table locking should be reworked.

Reported-by: syzbot+69ff9dff50dcfe14ddd4@syzkaller.appspotmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
jmberg-intel authored and gregkh committed Jun 16, 2021
1 parent cf3f90b commit 76cc8e0
Showing 1 changed file with 4 additions and 2 deletions.
6 changes: 4 additions & 2 deletions net/netlink/af_netlink.c
Expand Up @@ -461,11 +461,13 @@ void netlink_table_ungrab(void)
static inline void
netlink_lock_table(void)
{
unsigned long flags;

/* read_lock() synchronizes us to netlink_table_grab */

read_lock(&nl_table_lock);
read_lock_irqsave(&nl_table_lock, flags);
atomic_inc(&nl_table_users);
read_unlock(&nl_table_lock);
read_unlock_irqrestore(&nl_table_lock, flags);
}

static inline void
Expand Down

0 comments on commit 76cc8e0

Please sign in to comment.