Takashi Iwai ce744d
From 1d80d57ffcb55488f0ec0b77928d4f82d16b6a90 Mon Sep 17 00:00:00 2001
Takashi Iwai ce744d
From: Ying Hsu <yinghsu@chromium.org>
Takashi Iwai ce744d
Date: Wed, 11 Jan 2023 03:16:14 +0000
Takashi Iwai ce744d
Subject: [PATCH] Bluetooth: Fix possible deadlock in rfcomm_sk_state_change
Takashi Iwai ce744d
Git-commit: 1d80d57ffcb55488f0ec0b77928d4f82d16b6a90
Takashi Iwai ce744d
Patch-mainline: v6.2-rc5
Takashi Iwai ce744d
References: git-fixes
Takashi Iwai ce744d
Takashi Iwai ce744d
syzbot reports a possible deadlock in rfcomm_sk_state_change [1].
Takashi Iwai ce744d
While rfcomm_sock_connect acquires the sk lock and waits for
Takashi Iwai ce744d
the rfcomm lock, rfcomm_sock_release could have the rfcomm
Takashi Iwai ce744d
lock and hit a deadlock for acquiring the sk lock.
Takashi Iwai ce744d
Here's a simplified flow:
Takashi Iwai ce744d
Takashi Iwai ce744d
Rfcomm_sock_connect: lock_sock(sk)  rfcomm_dlc_open:    rfcomm_lock()
Takashi Iwai ce744d
Takashi Iwai ce744d
Rfcomm_sock_release: rfcomm_sock_shutdown:    rfcomm_lock()    __rfcomm_dlc_close:        rfcomm_k_state_change:	  lock_sock(sk)
Takashi Iwai ce744d
Takashi Iwai ce744d
This patch drops the sk lock before calling rfcomm_dlc_open to
Takashi Iwai ce744d
avoid the possible deadlock and holds sk's reference count to
Takashi Iwai ce744d
prevent use-after-free after rfcomm_dlc_open completes.
Takashi Iwai ce744d
Takashi Iwai ce744d
Reported-by: syzbot+d7ce59...@syzkaller.appspotmail.com
Takashi Iwai ce744d
Fixes: 1804fdf6e494 ("Bluetooth: btintel: Combine setting up MSFT extension")
Takashi Iwai ce744d
Link: https://syzkaller.appspot.com/bug?extid=d7ce59b06b3eb14fd218 [1]
Takashi Iwai ce744d
Takashi Iwai ce744d
Signed-off-by: Ying Hsu <yinghsu@chromium.org>
Takashi Iwai ce744d
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Takashi Iwai ce744d
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai ce744d
Takashi Iwai ce744d
---
Takashi Iwai ce744d
 net/bluetooth/rfcomm/sock.c | 7 ++++++-
Takashi Iwai ce744d
 1 file changed, 6 insertions(+), 1 deletion(-)
Takashi Iwai ce744d
Takashi Iwai ce744d
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
Takashi Iwai ce744d
index 21e24da4847f..4397e14ff560 100644
Takashi Iwai ce744d
--- a/net/bluetooth/rfcomm/sock.c
Takashi Iwai ce744d
+++ b/net/bluetooth/rfcomm/sock.c
Takashi Iwai ce744d
@@ -391,6 +391,7 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
Takashi Iwai ce744d
 	    addr->sa_family != AF_BLUETOOTH)
Takashi Iwai ce744d
 		return -EINVAL;
Takashi Iwai ce744d
 
Takashi Iwai ce744d
+	sock_hold(sk);
Takashi Iwai ce744d
 	lock_sock(sk);
Takashi Iwai ce744d
 
Takashi Iwai ce744d
 	if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
Takashi Iwai ce744d
@@ -410,14 +411,18 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
Takashi Iwai ce744d
 	d->sec_level = rfcomm_pi(sk)->sec_level;
Takashi Iwai ce744d
 	d->role_switch = rfcomm_pi(sk)->role_switch;
Takashi Iwai ce744d
 
Takashi Iwai ce744d
+	/* Drop sock lock to avoid potential deadlock with the RFCOMM lock */
Takashi Iwai ce744d
+	release_sock(sk);
Takashi Iwai ce744d
 	err = rfcomm_dlc_open(d, &rfcomm_pi(sk)->src, &sa->rc_bdaddr,
Takashi Iwai ce744d
 			      sa->rc_channel);
Takashi Iwai ce744d
-	if (!err)
Takashi Iwai ce744d
+	lock_sock(sk);
Takashi Iwai ce744d
+	if (!err && !sock_flag(sk, SOCK_ZAPPED))
Takashi Iwai ce744d
 		err = bt_sock_wait_state(sk, BT_CONNECTED,
Takashi Iwai ce744d
 				sock_sndtimeo(sk, flags & O_NONBLOCK));
Takashi Iwai ce744d
 
Takashi Iwai ce744d
 done:
Takashi Iwai ce744d
 	release_sock(sk);
Takashi Iwai ce744d
+	sock_put(sk);
Takashi Iwai ce744d
 	return err;
Takashi Iwai ce744d
 }
Takashi Iwai ce744d
 
Takashi Iwai ce744d
-- 
Takashi Iwai ce744d
2.35.3
Takashi Iwai ce744d