Messages in this thread Patch in this message |  | | From | hkbinbin <> | | Subject | [PATCH v2] Bluetooth: hci_event: fix OOB read and infinite loop in hci_le_create_big_complete_evt | | Date | Fri, 10 Apr 2026 16:19:36 +0000 |
| |
From: ZhiTao Ou <hkbinbinbin@gmail.com>
hci_le_create_big_complete_evt() iterates over BT_BOUND connections for a BIG handle using a while loop, accessing ev->bis_handle[i++] on each iteration. However, there is no check that i stays within ev->num_bis before the array access.
When a controller sends a LE_Create_BIG_Complete event with fewer bis_handle entries than there are BT_BOUND connections for that BIG, or with num_bis=0, the loop reads beyond the valid bis_handle[] flex array into adjacent heap memory. Since the out-of-bounds values typically exceed HCI_CONN_HANDLE_MAX (0x0EFF), hci_conn_set_handle() rejects them and the connection remains in BT_BOUND state. The same connection is then found again by hci_conn_hash_lookup_big_state(), creating an infinite loop with hci_dev_lock held.
Fix this by:
- Breaking out of the loop when i reaches ev->num_bis and cleaning up all remaining BT_BOUND connections, then terminating the BIG since a mismatch between the host and controller state indicates failure.
- Properly cleaning up the connection when hci_conn_set_handle() fails, instead of calling continue which leaves it in BT_BOUND state where it would be found again by the same lookup on the next iteration.
Fixes: a0bfde167b50 ("Bluetooth: ISO: Add support for connecting multiple BISes") Cc: stable@vger.kernel.org Signed-off-by: ZhiTao Ou <hkbinbinbin@gmail.com> --- net/bluetooth/hci_event.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 286529d2e554..64b5b497c491 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -7085,9 +7085,15 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, continue; } + if (i >= ev->num_bis) + break; + if (hci_conn_set_handle(conn, - __le16_to_cpu(ev->bis_handle[i++]))) + __le16_to_cpu(ev->bis_handle[i++]))) { + hci_connect_cfm(conn, HCI_ERROR_UNSPECIFIED); + hci_conn_del(conn); continue; + } conn->state = BT_CONNECTED; set_bit(HCI_CONN_BIG_CREATED, &conn->flags); @@ -7096,7 +7102,22 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, hci_iso_setup_path(conn); } - if (!ev->status && !i) + if (conn) { + /* More bound connections than BIS handles reported by the + * controller -- treat this as a failure for the entire BIG + * and clean up any remaining BT_BOUND connections. + */ + do { + hci_connect_cfm(conn, HCI_ERROR_UNSPECIFIED); + hci_conn_del(conn); + } while ((conn = hci_conn_hash_lookup_big_state(hdev, + ev->handle, + BT_BOUND, + HCI_ROLE_MASTER))); + + hci_cmd_sync_queue(hdev, hci_iso_term_big_sync, + UINT_PTR(ev->handle), NULL); + } else if (!ev->status && !i) { /* If no BISes have been connected for the BIG, * terminate. This is in case all bound connections * have been closed before the BIG creation @@ -7104,6 +7125,7 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, */ hci_cmd_sync_queue(hdev, hci_iso_term_big_sync, UINT_PTR(ev->handle), NULL); + } hci_dev_unlock(hdev); } -- 2.51.0
|  |