Patch "netlink: fix potential deadlock in netlink_set_err()" has been added to the 4.14-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    netlink: fix potential deadlock in netlink_set_err()

to the 4.14-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:
     netlink-fix-potential-deadlock-in-netlink_set_err.patch
and it can be found in the queue-4.14 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit d9a3772e94ce4153e151d4d258f248192b7fa53e
Author: Eric Dumazet <edumazet@xxxxxxxxxx>
Date:   Wed Jun 21 15:43:37 2023 +0000

    netlink: fix potential deadlock in netlink_set_err()
    
    [ 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@xxxxxxxxxxxxxxxxxxxxxxxxx
    Link: https://syzkaller.appspot.com/bug?extid=a7d200a347f912723e5c
    Link: https://lore.kernel.org/netdev/000000000000e38d1605fea5747e@xxxxxxxxxx/T/#u
    Signed-off-by: Eric Dumazet <edumazet@xxxxxxxxxx>
    Cc: Johannes Berg <johannes.berg@xxxxxxxxx>
    Link: https://lore.kernel.org/r/20230621154337.1668594-1-edumazet@xxxxxxxxxx
    Signed-off-by: Jakub Kicinski <kuba@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 4b40edb51b9e5..6aa9849715775 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -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;
 
@@ -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);
diff --git a/net/netlink/diag.c b/net/netlink/diag.c
index 8faa20b4d4573..8c96757d9dc2b 100644
--- a/net/netlink/diag.c
+++ b/net/netlink/diag.c
@@ -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;
@@ -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;
@@ -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;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux