Skip to content

Commit a2ac591

Browse files
lrh2000Vudentz
authored andcommitted
Bluetooth: Fix UAF in hci_conn_hash_flush again
Commit 0614974 ("Bluetooth: hci_conn: Add support for linking multiple hcon") reintroduced a previously fixed bug [1] ("KASAN: slab-use-after-free Read in hci_conn_hash_flush"). This bug was originally fixed by commit 5dc7d23 ("Bluetooth: hci_conn: Fix possible UAF"). The hci_conn_unlink function was added to avoid invalidating the link traversal caused by successive hci_conn_del operations releasing extra connections. However, currently hci_conn_unlink itself also releases extra connections, resulted in the reintroduced bug. This patch follows a more robust solution for cleaning up all connections, by repeatedly removing the first connection until there are none left. This approach does not rely on the inner workings of hci_conn_del and ensures proper cleanup of all connections. Meanwhile, we need to make sure that hci_conn_del never fails. Indeed it doesn't, as it now always returns zero. To make this a bit clearer, this patch also changes its return type to void. Reported-by: [email protected] Closes: https://lore.kernel.org/linux-bluetooth/[email protected]/ Fixes: 0614974 ("Bluetooth: hci_conn: Add support for linking multiple hcon") Signed-off-by: Ruihan Li <[email protected]> Co-developed-by: Luiz Augusto von Dentz <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 2910431 commit a2ac591

File tree

2 files changed

+23
-12
lines changed

2 files changed

+23
-12
lines changed

include/net/bluetooth/hci_core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,7 @@ int hci_le_create_cis(struct hci_conn *conn);
13271327

13281328
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
13291329
u8 role);
1330-
int hci_conn_del(struct hci_conn *conn);
1330+
void hci_conn_del(struct hci_conn *conn);
13311331
void hci_conn_hash_flush(struct hci_dev *hdev);
13321332
void hci_conn_check_pending(struct hci_dev *hdev);
13331333

net/bluetooth/hci_conn.c

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,14 @@ static void hci_conn_unlink(struct hci_conn *conn)
10881088

10891089
hci_conn_unlink(child);
10901090

1091+
/* If hdev is down it means
1092+
* hci_dev_close_sync/hci_conn_hash_flush is in progress
1093+
* and links don't need to be cleanup as all connections
1094+
* would be cleanup.
1095+
*/
1096+
if (!test_bit(HCI_UP, &hdev->flags))
1097+
continue;
1098+
10911099
/* Due to race, SCO connection might be not established
10921100
* yet at this point. Delete it now, otherwise it is
10931101
* possible for it to be stuck and can't be deleted.
@@ -1112,7 +1120,7 @@ static void hci_conn_unlink(struct hci_conn *conn)
11121120
conn->link = NULL;
11131121
}
11141122

1115-
int hci_conn_del(struct hci_conn *conn)
1123+
void hci_conn_del(struct hci_conn *conn)
11161124
{
11171125
struct hci_dev *hdev = conn->hdev;
11181126

@@ -1163,8 +1171,6 @@ int hci_conn_del(struct hci_conn *conn)
11631171
* rest of hci_conn_del.
11641172
*/
11651173
hci_conn_cleanup(conn);
1166-
1167-
return 0;
11681174
}
11691175

11701176
struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
@@ -2465,22 +2471,27 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
24652471
/* Drop all connection on the device */
24662472
void hci_conn_hash_flush(struct hci_dev *hdev)
24672473
{
2468-
struct hci_conn_hash *h = &hdev->conn_hash;
2469-
struct hci_conn *c, *n;
2474+
struct list_head *head = &hdev->conn_hash.list;
2475+
struct hci_conn *conn;
24702476

24712477
BT_DBG("hdev %s", hdev->name);
24722478

2473-
list_for_each_entry_safe(c, n, &h->list, list) {
2474-
c->state = BT_CLOSED;
2475-
2476-
hci_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
2479+
/* We should not traverse the list here, because hci_conn_del
2480+
* can remove extra links, which may cause the list traversal
2481+
* to hit items that have already been released.
2482+
*/
2483+
while ((conn = list_first_entry_or_null(head,
2484+
struct hci_conn,
2485+
list)) != NULL) {
2486+
conn->state = BT_CLOSED;
2487+
hci_disconn_cfm(conn, HCI_ERROR_LOCAL_HOST_TERM);
24772488

24782489
/* Unlink before deleting otherwise it is possible that
24792490
* hci_conn_del removes the link which may cause the list to
24802491
* contain items already freed.
24812492
*/
2482-
hci_conn_unlink(c);
2483-
hci_conn_del(c);
2493+
hci_conn_unlink(conn);
2494+
hci_conn_del(conn);
24842495
}
24852496
}
24862497

0 commit comments

Comments
 (0)