mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 20:51:03 +02:00
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/20230519233056.2024340-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -1319,17 +1319,17 @@ static void nxp_serdev_remove(struct serdev_device *serdev)
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
|
||||
static struct btnxpuart_data w8987_data = {
|
||||
static struct btnxpuart_data w8987_data __maybe_unused = {
|
||||
.helper_fw_name = NULL,
|
||||
.fw_name = FIRMWARE_W8987,
|
||||
};
|
||||
|
||||
static struct btnxpuart_data w8997_data = {
|
||||
static struct btnxpuart_data w8997_data __maybe_unused = {
|
||||
.helper_fw_name = FIRMWARE_HELPER,
|
||||
.fw_name = FIRMWARE_W8997,
|
||||
};
|
||||
|
||||
static const struct of_device_id nxpuart_of_match_table[] = {
|
||||
static const struct of_device_id nxpuart_of_match_table[] __maybe_unused = {
|
||||
{ .compatible = "nxp,88w8987-bt", .data = &w8987_data },
|
||||
{ .compatible = "nxp,88w8997-bt", .data = &w8997_data },
|
||||
{ }
|
||||
|
@@ -1327,7 +1327,7 @@ int hci_le_create_cis(struct hci_conn *conn);
|
||||
|
||||
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
u8 role);
|
||||
int hci_conn_del(struct hci_conn *conn);
|
||||
void hci_conn_del(struct hci_conn *conn);
|
||||
void hci_conn_hash_flush(struct hci_dev *hdev);
|
||||
void hci_conn_check_pending(struct hci_dev *hdev);
|
||||
|
||||
|
@@ -1083,8 +1083,28 @@ static void hci_conn_unlink(struct hci_conn *conn)
|
||||
if (!conn->parent) {
|
||||
struct hci_link *link, *t;
|
||||
|
||||
list_for_each_entry_safe(link, t, &conn->link_list, list)
|
||||
hci_conn_unlink(link->conn);
|
||||
list_for_each_entry_safe(link, t, &conn->link_list, list) {
|
||||
struct hci_conn *child = link->conn;
|
||||
|
||||
hci_conn_unlink(child);
|
||||
|
||||
/* If hdev is down it means
|
||||
* hci_dev_close_sync/hci_conn_hash_flush is in progress
|
||||
* and links don't need to be cleanup as all connections
|
||||
* would be cleanup.
|
||||
*/
|
||||
if (!test_bit(HCI_UP, &hdev->flags))
|
||||
continue;
|
||||
|
||||
/* Due to race, SCO connection might be not established
|
||||
* yet at this point. Delete it now, otherwise it is
|
||||
* possible for it to be stuck and can't be deleted.
|
||||
*/
|
||||
if ((child->type == SCO_LINK ||
|
||||
child->type == ESCO_LINK) &&
|
||||
child->handle == HCI_CONN_HANDLE_UNSET)
|
||||
hci_conn_del(child);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1092,35 +1112,30 @@ static void hci_conn_unlink(struct hci_conn *conn)
|
||||
if (!conn->link)
|
||||
return;
|
||||
|
||||
hci_conn_put(conn->parent);
|
||||
conn->parent = NULL;
|
||||
|
||||
list_del_rcu(&conn->link->list);
|
||||
synchronize_rcu();
|
||||
|
||||
hci_conn_drop(conn->parent);
|
||||
hci_conn_put(conn->parent);
|
||||
conn->parent = NULL;
|
||||
|
||||
kfree(conn->link);
|
||||
conn->link = NULL;
|
||||
|
||||
/* Due to race, SCO connection might be not established
|
||||
* yet at this point. Delete it now, otherwise it is
|
||||
* possible for it to be stuck and can't be deleted.
|
||||
*/
|
||||
if (conn->handle == HCI_CONN_HANDLE_UNSET)
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
|
||||
int hci_conn_del(struct hci_conn *conn)
|
||||
void hci_conn_del(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
|
||||
BT_DBG("%s hcon %p handle %d", hdev->name, conn, conn->handle);
|
||||
|
||||
hci_conn_unlink(conn);
|
||||
|
||||
cancel_delayed_work_sync(&conn->disc_work);
|
||||
cancel_delayed_work_sync(&conn->auto_accept_work);
|
||||
cancel_delayed_work_sync(&conn->idle_work);
|
||||
|
||||
if (conn->type == ACL_LINK) {
|
||||
hci_conn_unlink(conn);
|
||||
/* Unacked frames */
|
||||
hdev->acl_cnt += conn->sent;
|
||||
} else if (conn->type == LE_LINK) {
|
||||
@@ -1131,13 +1146,6 @@ int hci_conn_del(struct hci_conn *conn)
|
||||
else
|
||||
hdev->acl_cnt += conn->sent;
|
||||
} else {
|
||||
struct hci_conn *acl = conn->parent;
|
||||
|
||||
if (acl) {
|
||||
hci_conn_unlink(conn);
|
||||
hci_conn_drop(acl);
|
||||
}
|
||||
|
||||
/* Unacked ISO frames */
|
||||
if (conn->type == ISO_LINK) {
|
||||
if (hdev->iso_pkts)
|
||||
@@ -1160,8 +1168,6 @@ int hci_conn_del(struct hci_conn *conn)
|
||||
* rest of hci_conn_del.
|
||||
*/
|
||||
hci_conn_cleanup(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
|
||||
@@ -2462,22 +2468,21 @@ timer:
|
||||
/* Drop all connection on the device */
|
||||
void hci_conn_hash_flush(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c, *n;
|
||||
struct list_head *head = &hdev->conn_hash.list;
|
||||
struct hci_conn *conn;
|
||||
|
||||
BT_DBG("hdev %s", hdev->name);
|
||||
|
||||
list_for_each_entry_safe(c, n, &h->list, list) {
|
||||
c->state = BT_CLOSED;
|
||||
|
||||
hci_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
|
||||
|
||||
/* Unlink before deleting otherwise it is possible that
|
||||
* hci_conn_del removes the link which may cause the list to
|
||||
* contain items already freed.
|
||||
/* We should not traverse the list here, because hci_conn_del
|
||||
* can remove extra links, which may cause the list traversal
|
||||
* to hit items that have already been released.
|
||||
*/
|
||||
hci_conn_unlink(c);
|
||||
hci_conn_del(c);
|
||||
while ((conn = list_first_entry_or_null(head,
|
||||
struct hci_conn,
|
||||
list)) != NULL) {
|
||||
conn->state = BT_CLOSED;
|
||||
hci_disconn_cfm(conn, HCI_ERROR_LOCAL_HOST_TERM);
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user