[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CABBYNZ+yVWssa09NB+ahp-N87sLXRqYF58-GJK-Vx8jn-Sa5Uw@mail.gmail.com>
Date: Fri, 24 Feb 2023 13:02:29 -0800
From: Luiz Augusto von Dentz <luiz.dentz@...il.com>
To: Zhengping Jiang <jiangzp@...gle.com>
Cc: linux-bluetooth@...r.kernel.org, marcel@...tmann.org,
mmandlik@...gle.com, chromeos-bluetooth-upstreaming@...omium.org,
"David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>,
Johan Hedberg <johan.hedberg@...il.com>,
Paolo Abeni <pabeni@...hat.com>, linux-kernel@...r.kernel.org,
netdev@...r.kernel.org
Subject: Re: [kernel PATCH v2 1/1] Bluetooth: hci_sync: clear workqueue before
clear mgmt cmd
Hi Zhengping,
On Fri, Feb 24, 2023 at 11:53 AM Zhengping Jiang <jiangzp@...gle.com> wrote:
>
> Clear cmd_sync_work queue before clearing the mgmt cmd list to avoid
> racing conditions which cause use-after-free.
>
> When powering off the adapter, the mgmt cmd list will be cleared. If a
> work is queued in the cmd_sync_work queue at the same time, it will
> cause the risk of use-after-free, as the cmd pointer is not checked
> before use.
>
> Signed-off-by: Zhengping Jiang <jiangzp@...gle.com>
> ---
>
> Changes in v2:
> - Add function to clear the queue without stop the timer
>
> Changes in v1:
> - Clear cmd_sync_work queue before clearing the mgmt cmd list
>
> net/bluetooth/hci_sync.c | 21 ++++++++++++++++++++-
> 1 file changed, 20 insertions(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
> index 117eedb6f709..b70365dfff0c 100644
> --- a/net/bluetooth/hci_sync.c
> +++ b/net/bluetooth/hci_sync.c
> @@ -636,6 +636,23 @@ void hci_cmd_sync_init(struct hci_dev *hdev)
> INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire);
> }
>
> +static void hci_pend_cmd_sync_clear(struct hci_dev *hdev)
> +{
> + struct hci_cmd_sync_work_entry *entry, *tmp;
> +
> + mutex_lock(&hdev->cmd_sync_work_lock);
> + list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) {
> + if (entry->destroy) {
> + hci_req_sync_lock(hdev);
> + entry->destroy(hdev, entry->data, -ECANCELED);
> + hci_req_sync_unlock(hdev);
> + }
> + list_del(&entry->list);
> + kfree(entry);
> + }
> + mutex_unlock(&hdev->cmd_sync_work_lock);
> +}
> +
> void hci_cmd_sync_clear(struct hci_dev *hdev)
> {
> struct hci_cmd_sync_work_entry *entry, *tmp;
> @@ -4842,8 +4859,10 @@ int hci_dev_close_sync(struct hci_dev *hdev)
>
> if (!auto_off && hdev->dev_type == HCI_PRIMARY &&
> !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
> - hci_dev_test_flag(hdev, HCI_MGMT))
> + hci_dev_test_flag(hdev, HCI_MGMT)) {
> + hci_pend_cmd_sync_clear(hdev);
Any particular reason why you are not using hci_cmd_sync_clear
instead? We also may want to move the clearing logic to
hci_dev_close_sync since it should be equivalent to
hci_request_cancel_all.
> __mgmt_power_off(hdev);
> + }
>
> hci_inquiry_cache_flush(hdev);
> hci_pend_le_actions_clear(hdev);
> --
> 2.39.2.722.g9855ee24e9-goog
>
--
Luiz Augusto von Dentz
Powered by blists - more mailing lists