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);
|
hci_free_dev(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct btnxpuart_data w8987_data = {
|
static struct btnxpuart_data w8987_data __maybe_unused = {
|
||||||
.helper_fw_name = NULL,
|
.helper_fw_name = NULL,
|
||||||
.fw_name = FIRMWARE_W8987,
|
.fw_name = FIRMWARE_W8987,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct btnxpuart_data w8997_data = {
|
static struct btnxpuart_data w8997_data __maybe_unused = {
|
||||||
.helper_fw_name = FIRMWARE_HELPER,
|
.helper_fw_name = FIRMWARE_HELPER,
|
||||||
.fw_name = FIRMWARE_W8997,
|
.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,88w8987-bt", .data = &w8987_data },
|
||||||
{ .compatible = "nxp,88w8997-bt", .data = &w8997_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,
|
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||||
u8 role);
|
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_hash_flush(struct hci_dev *hdev);
|
||||||
void hci_conn_check_pending(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) {
|
if (!conn->parent) {
|
||||||
struct hci_link *link, *t;
|
struct hci_link *link, *t;
|
||||||
|
|
||||||
list_for_each_entry_safe(link, t, &conn->link_list, list)
|
list_for_each_entry_safe(link, t, &conn->link_list, list) {
|
||||||
hci_conn_unlink(link->conn);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1092,35 +1112,30 @@ static void hci_conn_unlink(struct hci_conn *conn)
|
|||||||
if (!conn->link)
|
if (!conn->link)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hci_conn_put(conn->parent);
|
|
||||||
conn->parent = NULL;
|
|
||||||
|
|
||||||
list_del_rcu(&conn->link->list);
|
list_del_rcu(&conn->link->list);
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
|
||||||
|
hci_conn_drop(conn->parent);
|
||||||
|
hci_conn_put(conn->parent);
|
||||||
|
conn->parent = NULL;
|
||||||
|
|
||||||
kfree(conn->link);
|
kfree(conn->link);
|
||||||
conn->link = NULL;
|
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;
|
struct hci_dev *hdev = conn->hdev;
|
||||||
|
|
||||||
BT_DBG("%s hcon %p handle %d", hdev->name, conn, conn->handle);
|
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->disc_work);
|
||||||
cancel_delayed_work_sync(&conn->auto_accept_work);
|
cancel_delayed_work_sync(&conn->auto_accept_work);
|
||||||
cancel_delayed_work_sync(&conn->idle_work);
|
cancel_delayed_work_sync(&conn->idle_work);
|
||||||
|
|
||||||
if (conn->type == ACL_LINK) {
|
if (conn->type == ACL_LINK) {
|
||||||
hci_conn_unlink(conn);
|
|
||||||
/* Unacked frames */
|
/* Unacked frames */
|
||||||
hdev->acl_cnt += conn->sent;
|
hdev->acl_cnt += conn->sent;
|
||||||
} else if (conn->type == LE_LINK) {
|
} else if (conn->type == LE_LINK) {
|
||||||
@@ -1131,13 +1146,6 @@ int hci_conn_del(struct hci_conn *conn)
|
|||||||
else
|
else
|
||||||
hdev->acl_cnt += conn->sent;
|
hdev->acl_cnt += conn->sent;
|
||||||
} else {
|
} else {
|
||||||
struct hci_conn *acl = conn->parent;
|
|
||||||
|
|
||||||
if (acl) {
|
|
||||||
hci_conn_unlink(conn);
|
|
||||||
hci_conn_drop(acl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unacked ISO frames */
|
/* Unacked ISO frames */
|
||||||
if (conn->type == ISO_LINK) {
|
if (conn->type == ISO_LINK) {
|
||||||
if (hdev->iso_pkts)
|
if (hdev->iso_pkts)
|
||||||
@@ -1160,8 +1168,6 @@ int hci_conn_del(struct hci_conn *conn)
|
|||||||
* rest of hci_conn_del.
|
* rest of hci_conn_del.
|
||||||
*/
|
*/
|
||||||
hci_conn_cleanup(conn);
|
hci_conn_cleanup(conn);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
|
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 */
|
/* Drop all connection on the device */
|
||||||
void hci_conn_hash_flush(struct hci_dev *hdev)
|
void hci_conn_hash_flush(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
struct list_head *head = &hdev->conn_hash.list;
|
||||||
struct hci_conn *c, *n;
|
struct hci_conn *conn;
|
||||||
|
|
||||||
BT_DBG("hdev %s", hdev->name);
|
BT_DBG("hdev %s", hdev->name);
|
||||||
|
|
||||||
list_for_each_entry_safe(c, n, &h->list, list) {
|
/* We should not traverse the list here, because hci_conn_del
|
||||||
c->state = BT_CLOSED;
|
* can remove extra links, which may cause the list traversal
|
||||||
|
* to hit items that have already been released.
|
||||||
hci_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
|
*/
|
||||||
|
while ((conn = list_first_entry_or_null(head,
|
||||||
/* Unlink before deleting otherwise it is possible that
|
struct hci_conn,
|
||||||
* hci_conn_del removes the link which may cause the list to
|
list)) != NULL) {
|
||||||
* contain items already freed.
|
conn->state = BT_CLOSED;
|
||||||
*/
|
hci_disconn_cfm(conn, HCI_ERROR_LOCAL_HOST_TERM);
|
||||||
hci_conn_unlink(c);
|
hci_conn_del(conn);
|
||||||
hci_conn_del(c);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user