Skip to content

Commit

Permalink
Bluetooth: hci_event: Fix using rcu_read_(un)lock while iterating
Browse files Browse the repository at this point in the history
[ 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: a0bfde1 ("Bluetooth: ISO: Add support for connecting multiple BISes")
Signed-off-by: Luiz Augusto von Dentz <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
  • Loading branch information
Vudentz authored and gregkh committed Dec 19, 2024
1 parent 11dc486 commit 0108132
Showing 1 changed file with 11 additions and 22 deletions.
33 changes: 11 additions & 22 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -6821,38 +6821,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();
conn->state = BT_CONNECTED;
set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
hci_debugfs_create_conn(conn);
hci_conn_add_sysfs(conn);
hci_iso_setup_path(conn);
}

rcu_read_unlock();

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

0 comments on commit 0108132

Please sign in to comment.