Commit 9d1d6db4 authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Yongqiang Liu
Browse files

Bluetooth: hci_event: Fix using rcu_read_(un)lock while iterating

stable inclusion
from stable-v6.6.67
commit 0108132d7d76d884e443d18b4f067cdf2811911b
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBEAP1
CVE: CVE-2024-56654

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=0108132d7d76d884e443d18b4f067cdf2811911b



--------------------------------

[ Upstream commit 581dd2dc168fe0ed2a7a5534a724f0d3751c93ae ]

The usage of rcu_read_(un)lock while inside list_for_each_entry_rcu is
not safe since for the most part entries fetched this way shall be
treated as rcu_dereference:

	Note that the value returned by rcu_dereference() is valid
	only within the enclosing RCU read-side critical section [1]_.
	For example, the following is **not** legal::

		rcu_read_lock();
		p = rcu_dereference(head.next);
		rcu_read_unlock();
		x = p->address;	/* BUG!!! */
		rcu_read_lock();
		y = p->data;	/* BUG!!! */
		rcu_read_unlock();

Fixes: a0bfde16 ("Bluetooth: ISO: Add support for connecting multiple BISes")
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarYongqiang Liu <liuyongqiang13@huawei.com>
parent 93cd4ea8
Loading
Loading
Loading
Loading
+11 −22
Original line number Diff line number Diff line
@@ -6814,38 +6814,27 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
		return;

	hci_dev_lock(hdev);
	rcu_read_lock();

	/* Connect all BISes that are bound to the BIG */
	list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
		if (bacmp(&conn->dst, BDADDR_ANY) ||
		    conn->type != ISO_LINK ||
		    conn->iso_qos.bcast.big != ev->handle)
	while ((conn = hci_conn_hash_lookup_big_state(hdev, ev->handle,
						      BT_BOUND))) {
		if (ev->status) {
			hci_connect_cfm(conn, ev->status);
			hci_conn_del(conn);
			continue;
		}

		if (hci_conn_set_handle(conn,
					__le16_to_cpu(ev->bis_handle[i++])))
			continue;

		if (!ev->status) {
		conn->state = BT_CONNECTED;
		set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
			rcu_read_unlock();
		hci_debugfs_create_conn(conn);
		hci_conn_add_sysfs(conn);
		hci_iso_setup_path(conn);
			rcu_read_lock();
			continue;
	}

		hci_connect_cfm(conn, ev->status);
		rcu_read_unlock();
		hci_conn_del(conn);
		rcu_read_lock();
	}

	rcu_read_unlock();

	if (!ev->status && !i)
		/* If no BISes have been connected for the BIG,
		 * terminate. This is in case all bound connections