Commit 3344d318 authored by Pauli Virtanen's avatar Pauli Virtanen Committed by Luiz Augusto von Dentz
Browse files

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: ca1fd42e ("Bluetooth: Fix potential double free caused by hci_conn_unlink")
Reported-by: default avatar <syzbot+cf54c1da6574b6c1b049@syzkaller.appspotmail.com>
Closes: https://lore.kernel.org/linux-bluetooth/00000000000013b93805fbbadc50@google.com/


Signed-off-by: default avatarPauli Virtanen <pav@iki.fi>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent db08722f
Loading
Loading
Loading
Loading
+24 −8
Original line number Diff line number Diff line
@@ -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;