]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Bluetooth: hci_conn: fail SCO/ISO via hci_conn_failed if ACL gone early
authorPauli Virtanen <pav@iki.fi>
Sat, 19 Aug 2023 13:33:36 +0000 (16:33 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Sep 2023 07:48:07 +0000 (09:48 +0200)
[ Upstream commit 3344d318337d9dca928fd448e966557ec5063f85 ]

Not calling hci_(dis)connect_cfm before deleting conn referred to by a
socket generally results to use-after-free.

When cleaning up SCO connections when the parent ACL is deleted too
early, use hci_conn_failed to do the connection cleanup properly.

We also need to clean up ISO connections in a similar situation when
connecting has started but LE Create CIS is not yet sent, so do it too
here.

Fixes: ca1fd42e7dbf ("Bluetooth: Fix potential double free caused by hci_conn_unlink")
Reported-by: syzbot+cf54c1da6574b6c1b049@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/linux-bluetooth/00000000000013b93805fbbadc50@google.com/
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/bluetooth/hci_conn.c

index 4f31340c2c93207e9e34affd1ae277b03ad5b5f6..eb2802ef34bfe8fa0c15e13483cc66da73102974 100644 (file)
@@ -1040,6 +1040,29 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
        return conn;
 }
 
+static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
+{
+       if (!reason)
+               reason = HCI_ERROR_REMOTE_USER_TERM;
+
+       /* Due to race, SCO/ISO conn might be not established yet at this point,
+        * and nothing else will clean it up. In other cases it is done via HCI
+        * events.
+        */
+       switch (conn->type) {
+       case SCO_LINK:
+       case ESCO_LINK:
+               if (HCI_CONN_HANDLE_UNSET(conn->handle))
+                       hci_conn_failed(conn, reason);
+               break;
+       case ISO_LINK:
+               if (conn->state != BT_CONNECTED &&
+                   !test_bit(HCI_CONN_CREATE_CIS, &conn->flags))
+                       hci_conn_failed(conn, reason);
+               break;
+       }
+}
+
 static void hci_conn_unlink(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
@@ -1062,14 +1085,7 @@ static void hci_conn_unlink(struct hci_conn *conn)
                        if (!test_bit(HCI_UP, &hdev->flags))
                                continue;
 
-                       /* Due to race, SCO connection might be not established
-                        * yet at this point. Delete it now, otherwise it is
-                        * possible for it to be stuck and can't be deleted.
-                        */
-                       if ((child->type == SCO_LINK ||
-                            child->type == ESCO_LINK) &&
-                           HCI_CONN_HANDLE_UNSET(child->handle))
-                               hci_conn_del(child);
+                       hci_conn_cleanup_child(child, conn->abort_reason);
                }
 
                return;