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

From: Luiz Augusto von Dentz
Date: Fri Feb 24 2023 - 16:02:52 EST


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