Skip to content

Commit 67caf26

Browse files
committed
Merge tag 'for-net-2023-05-19' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: - Fix compiler warnings on btnxpuart - Fix potential double free on hci_conn_unlink - Fix UAF on hci_conn_hash_flush * tag 'for-net-2023-05-19' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: btnxpuart: Fix compiler warnings Bluetooth: Unlink CISes when LE disconnects in hci_conn_del Bluetooth: Fix UAF in hci_conn_hash_flush again Bluetooth: Refcnt drop must be placed last in hci_conn_unlink Bluetooth: Fix potential double free caused by hci_conn_unlink ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents ae9b15f + 6ce5169 commit 67caf26

File tree

3 files changed

+45
-40
lines changed

3 files changed

+45
-40
lines changed

drivers/bluetooth/btnxpuart.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,17 +1319,17 @@ static void nxp_serdev_remove(struct serdev_device *serdev)
13191319
hci_free_dev(hdev);
13201320
}
13211321

1322-
static struct btnxpuart_data w8987_data = {
1322+
static struct btnxpuart_data w8987_data __maybe_unused = {
13231323
.helper_fw_name = NULL,
13241324
.fw_name = FIRMWARE_W8987,
13251325
};
13261326

1327-
static struct btnxpuart_data w8997_data = {
1327+
static struct btnxpuart_data w8997_data __maybe_unused = {
13281328
.helper_fw_name = FIRMWARE_HELPER,
13291329
.fw_name = FIRMWARE_W8997,
13301330
};
13311331

1332-
static const struct of_device_id nxpuart_of_match_table[] = {
1332+
static const struct of_device_id nxpuart_of_match_table[] __maybe_unused = {
13331333
{ .compatible = "nxp,88w8987-bt", .data = &w8987_data },
13341334
{ .compatible = "nxp,88w8997-bt", .data = &w8997_data },
13351335
{ }

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: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,44 +1083,59 @@ static void hci_conn_unlink(struct hci_conn *conn)
10831083
if (!conn->parent) {
10841084
struct hci_link *link, *t;
10851085

1086-
list_for_each_entry_safe(link, t, &conn->link_list, list)
1087-
hci_conn_unlink(link->conn);
1086+
list_for_each_entry_safe(link, t, &conn->link_list, list) {
1087+
struct hci_conn *child = link->conn;
1088+
1089+
hci_conn_unlink(child);
1090+
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+
1099+
/* Due to race, SCO connection might be not established
1100+
* yet at this point. Delete it now, otherwise it is
1101+
* possible for it to be stuck and can't be deleted.
1102+
*/
1103+
if ((child->type == SCO_LINK ||
1104+
child->type == ESCO_LINK) &&
1105+
child->handle == HCI_CONN_HANDLE_UNSET)
1106+
hci_conn_del(child);
1107+
}
10881108

10891109
return;
10901110
}
10911111

10921112
if (!conn->link)
10931113
return;
10941114

1095-
hci_conn_put(conn->parent);
1096-
conn->parent = NULL;
1097-
10981115
list_del_rcu(&conn->link->list);
10991116
synchronize_rcu();
11001117

1118+
hci_conn_drop(conn->parent);
1119+
hci_conn_put(conn->parent);
1120+
conn->parent = NULL;
1121+
11011122
kfree(conn->link);
11021123
conn->link = NULL;
1103-
1104-
/* Due to race, SCO connection might be not established
1105-
* yet at this point. Delete it now, otherwise it is
1106-
* possible for it to be stuck and can't be deleted.
1107-
*/
1108-
if (conn->handle == HCI_CONN_HANDLE_UNSET)
1109-
hci_conn_del(conn);
11101124
}
11111125

1112-
int hci_conn_del(struct hci_conn *conn)
1126+
void hci_conn_del(struct hci_conn *conn)
11131127
{
11141128
struct hci_dev *hdev = conn->hdev;
11151129

11161130
BT_DBG("%s hcon %p handle %d", hdev->name, conn, conn->handle);
11171131

1132+
hci_conn_unlink(conn);
1133+
11181134
cancel_delayed_work_sync(&conn->disc_work);
11191135
cancel_delayed_work_sync(&conn->auto_accept_work);
11201136
cancel_delayed_work_sync(&conn->idle_work);
11211137

11221138
if (conn->type == ACL_LINK) {
1123-
hci_conn_unlink(conn);
11241139
/* Unacked frames */
11251140
hdev->acl_cnt += conn->sent;
11261141
} else if (conn->type == LE_LINK) {
@@ -1131,13 +1146,6 @@ int hci_conn_del(struct hci_conn *conn)
11311146
else
11321147
hdev->acl_cnt += conn->sent;
11331148
} else {
1134-
struct hci_conn *acl = conn->parent;
1135-
1136-
if (acl) {
1137-
hci_conn_unlink(conn);
1138-
hci_conn_drop(acl);
1139-
}
1140-
11411149
/* Unacked ISO frames */
11421150
if (conn->type == ISO_LINK) {
11431151
if (hdev->iso_pkts)
@@ -1160,8 +1168,6 @@ int hci_conn_del(struct hci_conn *conn)
11601168
* rest of hci_conn_del.
11611169
*/
11621170
hci_conn_cleanup(conn);
1163-
1164-
return 0;
11651171
}
11661172

11671173
struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
@@ -2462,22 +2468,21 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
24622468
/* Drop all connection on the device */
24632469
void hci_conn_hash_flush(struct hci_dev *hdev)
24642470
{
2465-
struct hci_conn_hash *h = &hdev->conn_hash;
2466-
struct hci_conn *c, *n;
2471+
struct list_head *head = &hdev->conn_hash.list;
2472+
struct hci_conn *conn;
24672473

24682474
BT_DBG("hdev %s", hdev->name);
24692475

2470-
list_for_each_entry_safe(c, n, &h->list, list) {
2471-
c->state = BT_CLOSED;
2472-
2473-
hci_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
2474-
2475-
/* Unlink before deleting otherwise it is possible that
2476-
* hci_conn_del removes the link which may cause the list to
2477-
* contain items already freed.
2478-
*/
2479-
hci_conn_unlink(c);
2480-
hci_conn_del(c);
2476+
/* We should not traverse the list here, because hci_conn_del
2477+
* can remove extra links, which may cause the list traversal
2478+
* to hit items that have already been released.
2479+
*/
2480+
while ((conn = list_first_entry_or_null(head,
2481+
struct hci_conn,
2482+
list)) != NULL) {
2483+
conn->state = BT_CLOSED;
2484+
hci_disconn_cfm(conn, HCI_ERROR_LOCAL_HOST_TERM);
2485+
hci_conn_del(conn);
24812486
}
24822487
}
24832488

0 commit comments

Comments
 (0)