Skip to content

Commit

Permalink
netlink: fix potential deadlock in netlink_set_err()
Browse files Browse the repository at this point in the history
[ Upstream commit 8d61f926d42045961e6b65191c09e3678d86a9cf ]

syzbot reported a possible deadlock in netlink_set_err() [1]

A similar issue was fixed in commit 1d482e666b8e ("netlink: disable IRQs
for netlink_lock_table()") in netlink_lock_table()

This patch adds IRQ safety to netlink_set_err() and __netlink_diag_dump()
which were not covered by cited commit.

[1]

WARNING: possible irq lock inversion dependency detected
6.4.0-rc6-syzkaller-00240-g4e9f0ec38852 #0 Not tainted

syz-executor.2/23011 just changed the state of lock:
ffffffff8e1a7a58 (nl_table_lock){.+.?}-{2:2}, at: netlink_set_err+0x2e/0x3a0 net/netlink/af_netlink.c:1612
but this lock was taken by another, SOFTIRQ-safe lock in the past:
 (&local->queue_stop_reason_lock){..-.}-{2:2}

and interrupts could create inverse lock ordering between them.

other info that might help us debug this:
 Possible interrupt unsafe locking scenario:

       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);

 *** DEADLOCK ***

Fixes: 1d482e666b8e ("netlink: disable IRQs for netlink_lock_table()")
Reported-by: syzbot+a7d200a347f912723e5c@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=a7d200a347f912723e5c
Link: https://lore.kernel.org/netdev/000000000000e38d1605fea5747e@google.com/T/#u
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Johannes Berg <johannes.berg@intel.com>
Link: https://lore.kernel.org/r/20230621154337.1668594-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Eric Dumazet authored and ratatouille100 committed Dec 19, 2023
1 parent f3d19a4 commit 97feefd
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 4 deletions.
5 changes: 3 additions & 2 deletions net/netlink/af_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,7 @@ static int do_one_set_err(struct sock *sk, struct netlink_set_err_data *p)
int netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code)
{
struct netlink_set_err_data info;
unsigned long flags;
struct sock *sk;
int ret = 0;

Expand All @@ -1583,12 +1584,12 @@ int netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code)
/* sk->sk_err wants a positive error value */
info.code = -code;

read_lock(&nl_table_lock);
read_lock_irqsave(&nl_table_lock, flags);

sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list)
ret += do_one_set_err(sk, &info);

read_unlock(&nl_table_lock);
read_unlock_irqrestore(&nl_table_lock, flags);
return ret;
}
EXPORT_SYMBOL(netlink_set_err);
Expand Down
5 changes: 3 additions & 2 deletions net/netlink/diag.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
struct net *net = sock_net(skb->sk);
struct netlink_diag_req *req;
struct netlink_sock *nlsk;
unsigned long flags;
struct sock *sk;
int num = 2;
int ret = 0;
Expand Down Expand Up @@ -155,7 +156,7 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
num++;

mc_list:
read_lock(&nl_table_lock);
read_lock_irqsave(&nl_table_lock, flags);
sk_for_each_bound(sk, &tbl->mc_list) {
if (sk_hashed(sk))
continue;
Expand All @@ -176,7 +177,7 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
}
num++;
}
read_unlock(&nl_table_lock);
read_unlock_irqrestore(&nl_table_lock, flags);

done:
cb->args[0] = num;
Expand Down

0 comments on commit 97feefd

Please sign in to comment.