Commit ab39b113 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Luiz Augusto von Dentz says:

====================
bluetooth pull request for net:

 - Fixes to debugfs registration
 - Fix use-after-free in hci_remove_ltk/hci_remove_irk
 - Fixes to ISO channel support
 - Fix missing checks for invalid L2CAP DCID
 - Fix l2cap_disconnect_req deadlock
 - Add lock to protect HCI_UNREGISTER

* tag 'for-net-2023-06-05' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: L2CAP: Add missing checks for invalid DCID
  Bluetooth: ISO: use correct CIS order in Set CIG Parameters event
  Bluetooth: ISO: don't try to remove CIG if there are bound CIS left
  Bluetooth: Fix l2cap_disconnect_req deadlock
  Bluetooth: hci_qca: fix debugfs registration
  Bluetooth: fix debugfs registration
  Bluetooth: hci_sync: add lock to protect HCI_UNREGISTER
  Bluetooth: Fix use-after-free in hci_remove_ltk/hci_remove_irk
  Bluetooth: ISO: Fix CIG auto-allocation to select configurable CIG
  Bluetooth: ISO: consider right CIS when removing CIG at cleanup
====================

Link: https://lore.kernel.org/r/20230606003454.2392552-1-luiz.dentz@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 20c47646 75767213
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -78,7 +78,8 @@ enum qca_flags {
	QCA_HW_ERROR_EVENT,
	QCA_SSR_TRIGGERED,
	QCA_BT_OFF,
	QCA_ROM_FW
	QCA_ROM_FW,
	QCA_DEBUGFS_CREATED,
};

enum qca_capabilities {
@@ -635,6 +636,9 @@ static void qca_debugfs_init(struct hci_dev *hdev)
	if (!hdev->debugfs)
		return;

	if (test_and_set_bit(QCA_DEBUGFS_CREATED, &qca->flags))
		return;

	ibs_dir = debugfs_create_dir("ibs", hdev->debugfs);

	/* read only */
+1 −0
Original line number Diff line number Diff line
@@ -350,6 +350,7 @@ enum {
enum {
	HCI_SETUP,
	HCI_CONFIG,
	HCI_DEBUGFS_CREATED,
	HCI_AUTO_OFF,
	HCI_RFKILLED,
	HCI_MGMT,
+3 −1
Original line number Diff line number Diff line
@@ -515,6 +515,7 @@ struct hci_dev {
	struct work_struct	cmd_sync_work;
	struct list_head	cmd_sync_work_list;
	struct mutex		cmd_sync_work_lock;
	struct mutex		unregister_lock;
	struct work_struct	cmd_sync_cancel_work;
	struct work_struct	reenable_adv_work;

@@ -1201,7 +1202,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev,
		if (id != BT_ISO_QOS_CIS_UNSET && id != c->iso_qos.ucast.cis)
			continue;

		if (ba_type == c->dst_type && !bacmp(&c->dst, ba)) {
		/* Match destination address if set */
		if (!ba || (ba_type == c->dst_type && !bacmp(&c->dst, ba))) {
			rcu_read_unlock();
			return c;
		}
+13 −9
Original line number Diff line number Diff line
@@ -947,8 +947,8 @@ static void find_cis(struct hci_conn *conn, void *data)
{
	struct iso_list_data *d = data;

	/* Ignore broadcast */
	if (!bacmp(&conn->dst, BDADDR_ANY))
	/* Ignore broadcast or if CIG don't match */
	if (!bacmp(&conn->dst, BDADDR_ANY) || d->cig != conn->iso_qos.ucast.cig)
		return;

	d->count++;
@@ -963,12 +963,17 @@ static void cis_cleanup(struct hci_conn *conn)
	struct hci_dev *hdev = conn->hdev;
	struct iso_list_data d;

	if (conn->iso_qos.ucast.cig == BT_ISO_QOS_CIG_UNSET)
		return;

	memset(&d, 0, sizeof(d));
	d.cig = conn->iso_qos.ucast.cig;

	/* Check if ISO connection is a CIS and remove CIG if there are
	 * no other connections using it.
	 */
	hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_BOUND, &d);
	hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECT, &d);
	hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECTED, &d);
	if (d.count)
		return;
@@ -1766,24 +1771,23 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)

	memset(&data, 0, sizeof(data));

	/* Allocate a CIG if not set */
	/* Allocate first still reconfigurable CIG if not set */
	if (qos->ucast.cig == BT_ISO_QOS_CIG_UNSET) {
		for (data.cig = 0x00; data.cig < 0xff; data.cig++) {
		for (data.cig = 0x00; data.cig < 0xf0; data.cig++) {
			data.count = 0;
			data.cis = 0xff;

			hci_conn_hash_list_state(hdev, cis_list, ISO_LINK,
						 BT_BOUND, &data);
			hci_conn_hash_list_state(hdev, find_cis, ISO_LINK,
						 BT_CONNECT, &data);
			if (data.count)
				continue;

			hci_conn_hash_list_state(hdev, cis_list, ISO_LINK,
			hci_conn_hash_list_state(hdev, find_cis, ISO_LINK,
						 BT_CONNECTED, &data);
			if (!data.count)
				break;
		}

		if (data.cig == 0xff)
		if (data.cig == 0xf0)
			return false;

		/* Update CIG */
+6 −4
Original line number Diff line number Diff line
@@ -1416,10 +1416,10 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)

int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type)
{
	struct smp_ltk *k;
	struct smp_ltk *k, *tmp;
	int removed = 0;

	list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
	list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
		if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_type)
			continue;

@@ -1435,9 +1435,9 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type)

void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type)
{
	struct smp_irk *k;
	struct smp_irk *k, *tmp;

	list_for_each_entry_rcu(k, &hdev->identity_resolving_keys, list) {
	list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) {
		if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type)
			continue;

@@ -2686,7 +2686,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
{
	BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);

	mutex_lock(&hdev->unregister_lock);
	hci_dev_set_flag(hdev, HCI_UNREGISTER);
	mutex_unlock(&hdev->unregister_lock);

	write_lock(&hci_dev_list_lock);
	list_del(&hdev->list);
Loading