Re: [kernel PATCH v2 1/1] Bluetooth: hci_sync: clear workqueue before clear mgmt cmd

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Zhengping,

On Fri, Feb 24, 2023 at 11:53 AM Zhengping Jiang <jiangzp@xxxxxxxxxx> 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@xxxxxxxxxx>
> ---
>
> 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



[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux