Bluetooth: ISO: Avoid circular locking dependency
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 7 Dec 2022 00:34:42 +0000 (16:34 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 1 Feb 2023 07:34:22 +0000 (08:34 +0100)
[ Upstream commit 241f51931c35085449502c10f64fb3ecd6e02171 ]

This attempts to avoid circular locking dependency between sock_lock
and hdev_lock:

WARNING: possible circular locking dependency detected
6.0.0-rc7-03728-g18dd8ab0a783 #3 Not tainted
------------------------------------------------------
kworker/u3:2/53 is trying to acquire lock:
ffff888000254130 (sk_lock-AF_BLUETOOTH-BTPROTO_ISO){+.+.}-{0:0}, at:
iso_conn_del+0xbd/0x1d0
but task is already holding lock:
ffffffff9f39a080 (hci_cb_list_lock){+.+.}-{3:3}, at:
hci_le_cis_estabilished_evt+0x1b5/0x500
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (hci_cb_list_lock){+.+.}-{3:3}:
       __mutex_lock+0x10e/0xfe0
       hci_le_remote_feat_complete_evt+0x17f/0x320
       hci_event_packet+0x39c/0x7d0
       hci_rx_work+0x2bf/0x950
       process_one_work+0x569/0x980
       worker_thread+0x2a3/0x6f0
       kthread+0x153/0x180
       ret_from_fork+0x22/0x30
-> #1 (&hdev->lock){+.+.}-{3:3}:
       __mutex_lock+0x10e/0xfe0
       iso_connect_cis+0x6f/0x5a0
       iso_sock_connect+0x1af/0x710
       __sys_connect+0x17e/0x1b0
       __x64_sys_connect+0x37/0x50
       do_syscall_64+0x43/0x90
       entry_SYSCALL_64_after_hwframe+0x62/0xcc
-> #0 (sk_lock-AF_BLUETOOTH-BTPROTO_ISO){+.+.}-{0:0}:
       __lock_acquire+0x1b51/0x33d0
       lock_acquire+0x16f/0x3b0
       lock_sock_nested+0x32/0x80
       iso_conn_del+0xbd/0x1d0
       iso_connect_cfm+0x226/0x680
       hci_le_cis_estabilished_evt+0x1ed/0x500
       hci_event_packet+0x39c/0x7d0
       hci_rx_work+0x2bf/0x950
       process_one_work+0x569/0x980
       worker_thread+0x2a3/0x6f0
       kthread+0x153/0x180
       ret_from_fork+0x22/0x30
other info that might help us debug this:
Chain exists of:
  sk_lock-AF_BLUETOOTH-BTPROTO_ISO --> &hdev->lock --> hci_cb_list_lock
 Possible unsafe locking scenario:
       CPU0                    CPU1
       ----                    ----
  lock(hci_cb_list_lock);
                               lock(&hdev->lock);
                               lock(hci_cb_list_lock);
  lock(sk_lock-AF_BLUETOOTH-BTPROTO_ISO);
 *** DEADLOCK ***
4 locks held by kworker/u3:2/53:
 #0: ffff8880021d9130 ((wq_completion)hci0#2){+.+.}-{0:0}, at:
 process_one_work+0x4ad/0x980
 #1: ffff888002387de0 ((work_completion)(&hdev->rx_work)){+.+.}-{0:0},
 at: process_one_work+0x4ad/0x980
 #2: ffff888001ac0070 (&hdev->lock){+.+.}-{3:3}, at:
 hci_le_cis_estabilished_evt+0xc3/0x500
 #3: ffffffff9f39a080 (hci_cb_list_lock){+.+.}-{3:3}, at:
 hci_le_cis_estabilished_evt+0x1b5/0x500

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Stable-dep-of: 6a5ad251b7cd ("Bluetooth: ISO: Fix possible circular locking dependency")
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/bluetooth/iso.c

index 26db929..df57cbe 100644 (file)
@@ -261,13 +261,13 @@ static int iso_connect_bis(struct sock *sk)
 
        if (!bis_capable(hdev)) {
                err = -EOPNOTSUPP;
-               goto done;
+               goto unlock;
        }
 
        /* Fail if out PHYs are marked as disabled */
        if (!iso_pi(sk)->qos.out.phy) {
                err = -EINVAL;
-               goto done;
+               goto unlock;
        }
 
        hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst, iso_pi(sk)->dst_type,
@@ -275,22 +275,27 @@ static int iso_connect_bis(struct sock *sk)
                               iso_pi(sk)->base);
        if (IS_ERR(hcon)) {
                err = PTR_ERR(hcon);
-               goto done;
+               goto unlock;
        }
 
        conn = iso_conn_add(hcon);
        if (!conn) {
                hci_conn_drop(hcon);
                err = -ENOMEM;
-               goto done;
+               goto unlock;
        }
 
+       hci_dev_unlock(hdev);
+       hci_dev_put(hdev);
+
+       lock_sock(sk);
+
        /* Update source addr of the socket */
        bacpy(&iso_pi(sk)->src, &hcon->src);
 
        err = iso_chan_add(conn, sk, NULL);
        if (err)
-               goto done;
+               goto release;
 
        if (hcon->state == BT_CONNECTED) {
                iso_sock_clear_timer(sk);
@@ -300,7 +305,11 @@ static int iso_connect_bis(struct sock *sk)
                iso_sock_set_timer(sk, sk->sk_sndtimeo);
        }
 
-done:
+release:
+       release_sock(sk);
+       return err;
+
+unlock:
        hci_dev_unlock(hdev);
        hci_dev_put(hdev);
        return err;
@@ -324,13 +333,13 @@ static int iso_connect_cis(struct sock *sk)
 
        if (!cis_central_capable(hdev)) {
                err = -EOPNOTSUPP;
-               goto done;
+               goto unlock;
        }
 
        /* Fail if either PHYs are marked as disabled */
        if (!iso_pi(sk)->qos.in.phy && !iso_pi(sk)->qos.out.phy) {
                err = -EINVAL;
-               goto done;
+               goto unlock;
        }
 
        /* Just bind if DEFER_SETUP has been set */
@@ -340,7 +349,7 @@ static int iso_connect_cis(struct sock *sk)
                                    &iso_pi(sk)->qos);
                if (IS_ERR(hcon)) {
                        err = PTR_ERR(hcon);
-                       goto done;
+                       goto unlock;
                }
        } else {
                hcon = hci_connect_cis(hdev, &iso_pi(sk)->dst,
@@ -348,7 +357,7 @@ static int iso_connect_cis(struct sock *sk)
                                       &iso_pi(sk)->qos);
                if (IS_ERR(hcon)) {
                        err = PTR_ERR(hcon);
-                       goto done;
+                       goto unlock;
                }
        }
 
@@ -356,15 +365,20 @@ static int iso_connect_cis(struct sock *sk)
        if (!conn) {
                hci_conn_drop(hcon);
                err = -ENOMEM;
-               goto done;
+               goto unlock;
        }
 
+       hci_dev_unlock(hdev);
+       hci_dev_put(hdev);
+
+       lock_sock(sk);
+
        /* Update source addr of the socket */
        bacpy(&iso_pi(sk)->src, &hcon->src);
 
        err = iso_chan_add(conn, sk, NULL);
        if (err)
-               goto done;
+               goto release;
 
        if (hcon->state == BT_CONNECTED) {
                iso_sock_clear_timer(sk);
@@ -377,7 +391,11 @@ static int iso_connect_cis(struct sock *sk)
                iso_sock_set_timer(sk, sk->sk_sndtimeo);
        }
 
-done:
+release:
+       release_sock(sk);
+       return err;
+
+unlock:
        hci_dev_unlock(hdev);
        hci_dev_put(hdev);
        return err;
@@ -831,20 +849,23 @@ static int iso_sock_connect(struct socket *sock, struct sockaddr *addr,
        bacpy(&iso_pi(sk)->dst, &sa->iso_bdaddr);
        iso_pi(sk)->dst_type = sa->iso_bdaddr_type;
 
+       release_sock(sk);
+
        if (bacmp(&iso_pi(sk)->dst, BDADDR_ANY))
                err = iso_connect_cis(sk);
        else
                err = iso_connect_bis(sk);
 
        if (err)
-               goto done;
+               return err;
+
+       lock_sock(sk);
 
        if (!test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
                err = bt_sock_wait_state(sk, BT_CONNECTED,
                                         sock_sndtimeo(sk, flags & O_NONBLOCK));
        }
 
-done:
        release_sock(sk);
        return err;
 }
@@ -1099,28 +1120,22 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
 {
        struct sock *sk = sock->sk;
        struct iso_pinfo *pi = iso_pi(sk);
-       int err;
 
        BT_DBG("sk %p", sk);
 
-       lock_sock(sk);
-
        if (test_and_clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
                switch (sk->sk_state) {
                case BT_CONNECT2:
+                       lock_sock(sk);
                        iso_conn_defer_accept(pi->conn->hcon);
                        sk->sk_state = BT_CONFIG;
                        release_sock(sk);
                        return 0;
                case BT_CONNECT:
-                       err = iso_connect_cis(sk);
-                       release_sock(sk);
-                       return err;
+                       return iso_connect_cis(sk);
                }
        }
 
-       release_sock(sk);
-
        return bt_sock_recvmsg(sock, msg, len, flags);
 }