The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH] Bluetooth: hci_sync: Fix scan response data UAF
@ 2026-07-20 16:47 Chengfeng Ye
  2026-07-20 19:54 ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 2+ messages in thread
From: Chengfeng Ye @ 2026-07-20 16:47 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz
  Cc: linux-bluetooth, linux-kernel, Chengfeng Ye, stable

eir_create_scan_rsp() calls hci_find_adv_instance(), whose return value is
valid only while hdev->lock is held.  After advertising setup was moved to
hci_cmd_sync_work, neither scan response data builder held that lock.
hci_set_ext_scan_rsp_data_sync() also kept the returned pointer while
waiting for the controller and wrote scan_rsp_changed through it afterward.

An advertising termination event can therefore interleave as follows:

  hci_cmd_sync_work                 hci_rx_work
  hci_find_adv_instance()
  __hci_cmd_sync_status()
    wait for controller reply       hci_dev_lock()
                                    hci_remove_adv_instance()
                                      kfree(adv)
  adv->scan_rsp_changed = false

KASAN reported:

  BUG: KASAN: slab-use-after-free in hci_set_ext_scan_rsp_data_sync+0x2e1/0x300
  Write of size 1 at addr ffff88810a45d21d by task kworker/u17:0/88
  Workqueue: hci0 hci_cmd_sync_work
  Call Trace:
   hci_set_ext_scan_rsp_data_sync+0x2e1/0x300
   hci_schedule_adv_instance_sync+0x390/0x4c0
   hci_cmd_sync_work+0x173/0x300
  Allocated by task 87:
   hci_add_adv_instance+0x538/0xac0
   add_advertising+0x885/0x1160
  Freed by task 89:
   kfree+0x131/0x3c0
   hci_remove_adv_instance+0x1d8/0x3b0
   hci_le_ext_adv_term_evt+0x17b/0x730

Hold hdev->lock while looking up the instance, building the scan
response, and clearing its dirty bit.  Clear the bit before waiting for
the controller so no adv_info pointer survives the wait, and restore it
under the lock if the command fails.  This also preserves an update that
races with a successful command because that update sets the bit again.
Protect the legacy scan response builder with the same lock.

Fixes: cba6b758711c ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 2")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
---
 net/bluetooth/hci_sync.c | 32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 532534bc601c..8c69a98c71e8 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -1490,9 +1490,13 @@ static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
 	int err;
 
 	if (instance) {
+		hci_dev_lock(hdev);
+
 		adv = hci_find_adv_instance(hdev, instance);
-		if (!adv || !adv->scan_rsp_changed)
+		if (!adv || !adv->scan_rsp_changed) {
+			hci_dev_unlock(hdev);
 			return 0;
+		}
 	}
 
 	len = eir_create_scan_rsp(hdev, instance, pdu->data);
@@ -1502,15 +1506,27 @@ static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
 	pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
 	pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
 
+	if (adv) {
+		adv->scan_rsp_changed = false;
+		hci_dev_unlock(hdev);
+	}
+
 	err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA,
 				    struct_size(pdu, data, len), pdu,
 				    HCI_CMD_TIMEOUT);
-	if (err)
+	if (err) {
+		if (instance) {
+			hci_dev_lock(hdev);
+			adv = hci_find_adv_instance(hdev, instance);
+			if (adv)
+				adv->scan_rsp_changed = true;
+			hci_dev_unlock(hdev);
+		}
+
 		return err;
+	}
 
-	if (adv) {
-		adv->scan_rsp_changed = false;
-	} else {
+	if (!instance) {
 		memcpy(hdev->scan_rsp_data, pdu->data, len);
 		hdev->scan_rsp_data_len = len;
 	}
@@ -1525,8 +1541,14 @@ static int __hci_set_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
 
 	memset(&cp, 0, sizeof(cp));
 
+	if (instance)
+		hci_dev_lock(hdev);
+
 	len = eir_create_scan_rsp(hdev, instance, cp.data);
 
+	if (instance)
+		hci_dev_unlock(hdev);
+
 	if (hdev->scan_rsp_data_len == len &&
 	    !memcmp(cp.data, hdev->scan_rsp_data, len))
 		return 0;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] Bluetooth: hci_sync: Fix scan response data UAF
  2026-07-20 16:47 [PATCH] Bluetooth: hci_sync: Fix scan response data UAF Chengfeng Ye
@ 2026-07-20 19:54 ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 2+ messages in thread
From: Luiz Augusto von Dentz @ 2026-07-20 19:54 UTC (permalink / raw)
  To: Chengfeng Ye; +Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, stable

Hi,

On Mon, Jul 20, 2026 at 12:47 PM Chengfeng Ye <nicoyip.dev@gmail.com> wrote:
>
> eir_create_scan_rsp() calls hci_find_adv_instance(), whose return value is
> valid only while hdev->lock is held.  After advertising setup was moved to
> hci_cmd_sync_work, neither scan response data builder held that lock.
> hci_set_ext_scan_rsp_data_sync() also kept the returned pointer while
> waiting for the controller and wrote scan_rsp_changed through it afterward.
>
> An advertising termination event can therefore interleave as follows:
>
>   hci_cmd_sync_work                 hci_rx_work
>   hci_find_adv_instance()
>   __hci_cmd_sync_status()
>     wait for controller reply       hci_dev_lock()
>                                     hci_remove_adv_instance()
>                                       kfree(adv)
>   adv->scan_rsp_changed = false
>
> KASAN reported:
>
>   BUG: KASAN: slab-use-after-free in hci_set_ext_scan_rsp_data_sync+0x2e1/0x300
>   Write of size 1 at addr ffff88810a45d21d by task kworker/u17:0/88
>   Workqueue: hci0 hci_cmd_sync_work
>   Call Trace:
>    hci_set_ext_scan_rsp_data_sync+0x2e1/0x300
>    hci_schedule_adv_instance_sync+0x390/0x4c0
>    hci_cmd_sync_work+0x173/0x300
>   Allocated by task 87:
>    hci_add_adv_instance+0x538/0xac0
>    add_advertising+0x885/0x1160
>   Freed by task 89:
>    kfree+0x131/0x3c0
>    hci_remove_adv_instance+0x1d8/0x3b0
>    hci_le_ext_adv_term_evt+0x17b/0x730
>
> Hold hdev->lock while looking up the instance, building the scan
> response, and clearing its dirty bit.  Clear the bit before waiting for
> the controller so no adv_info pointer survives the wait, and restore it
> under the lock if the command fails.  This also preserves an update that
> races with a successful command because that update sets the bit again.
> Protect the legacy scan response builder with the same lock.
>
> Fixes: cba6b758711c ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 2")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
> ---
>  net/bluetooth/hci_sync.c | 32 +++++++++++++++++++++++++++-----
>  1 file changed, 27 insertions(+), 5 deletions(-)
>
> diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
> index 532534bc601c..8c69a98c71e8 100644
> --- a/net/bluetooth/hci_sync.c
> +++ b/net/bluetooth/hci_sync.c
> @@ -1490,9 +1490,13 @@ static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
>         int err;
>
>         if (instance) {
> +               hci_dev_lock(hdev);
> +
>                 adv = hci_find_adv_instance(hdev, instance);
> -               if (!adv || !adv->scan_rsp_changed)
> +               if (!adv || !adv->scan_rsp_changed) {
> +                       hci_dev_unlock(hdev);
>                         return 0;
> +               }
>         }
>
>         len = eir_create_scan_rsp(hdev, instance, pdu->data);
> @@ -1502,15 +1506,27 @@ static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
>         pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
>         pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
>
> +       if (adv) {
> +               adv->scan_rsp_changed = false;
> +               hci_dev_unlock(hdev);
> +       }
> +
>         err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA,
>                                     struct_size(pdu, data, len), pdu,
>                                     HCI_CMD_TIMEOUT);
> -       if (err)
> +       if (err) {
> +               if (instance) {
> +                       hci_dev_lock(hdev);
> +                       adv = hci_find_adv_instance(hdev, instance);
> +                       if (adv)
> +                               adv->scan_rsp_changed = true;
> +                       hci_dev_unlock(hdev);
> +               }
> +
>                 return err;
> +       }
>
> -       if (adv) {
> -               adv->scan_rsp_changed = false;
> -       } else {
> +       if (!instance) {
>                 memcpy(hdev->scan_rsp_data, pdu->data, len);
>                 hdev->scan_rsp_data_len = len;
>         }
> @@ -1525,8 +1541,14 @@ static int __hci_set_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
>
>         memset(&cp, 0, sizeof(cp));
>
> +       if (instance)
> +               hci_dev_lock(hdev);
> +
>         len = eir_create_scan_rsp(hdev, instance, cp.data);
>
> +       if (instance)
> +               hci_dev_unlock(hdev);
> +
>         if (hdev->scan_rsp_data_len == len &&
>             !memcmp(cp.data, hdev->scan_rsp_data, len))
>                 return 0;
> --
> 2.43.0

It looks like Sashiko found some other places where this could be a problem:

https://sashiko.dev/#/patchset/20260720164738.2921802-1-nicoyip.dev%40gmail.com

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-20 19:55 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-20 16:47 [PATCH] Bluetooth: hci_sync: Fix scan response data UAF Chengfeng Ye
2026-07-20 19:54 ` Luiz Augusto von Dentz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox