summaryrefslogtreecommitdiff
path: root/net/bluetooth
diff options
context:
space:
mode:
authorPauli Virtanen <pav@iki.fi>2023-08-19 16:33:36 +0300
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2023-08-24 12:22:35 -0700
commit3344d318337d9dca928fd448e966557ec5063f85 (patch)
tree82a6c1b14a5ed03cbee9afc71ab7b35078a454ce /net/bluetooth
parentdb08722fc7d46168fe31d9b8a7b29229dd959f9f (diff)
Bluetooth: hci_conn: fail SCO/ISO via hci_conn_failed if ACL gone early
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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_conn.c32
1 files changed, 24 insertions, 8 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 8b0c8e631324..9d5057cef30a 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1044,6 +1044,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;
@@ -1066,14 +1089,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;