Re: [PATCH] Bluetooth: hci_serdev: Fix use-after-free in hci_uart_unregister_device()
Luiz Augusto von Dentz <[email protected]>
| Newsgroups | org.kernel.vger.linux-bluetooth,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CABBYNZ+mwb4z_x-jwdJVftSLDGa3x_v6ghgUd2uND87q8fP1rg@mail.gmail.com> |
Hi ZhaoJinming, On Wed, Aug 5, 2026 at 6:36 AM ZhaoJinming <[email protected]> wrote: > > hci_uart_unregister_device() frees the HCI device (hci_free_dev) > before cancelling write_work via cancel_work_sync(). If write_work > is executing concurrently on another CPU, it can access hu->hdev > (serdev.c:61) and write to hdev->stat (serdev.c:75, 83) after the > memory has been freed. > > Additionally, HCI_UART_PROTO_READY is not cleared until after > cancel_work_sync, so the write_wakeup serdev callback can still > schedule write_work via hci_uart_tx_wakeup() even after > hci_free_dev has freed the device. > > Fix this by mirroring the same ordering used in the tty/ldisc path > (hci_uart_tty_close, hci_ldisc.c:565-593): > 1. Clear HCI_UART_PROTO_READY and close the serdev port > 2. Cancel write_work (no new work can be scheduled) > 3. Unregister the HCI device > 4. Close the protocol (may access hu->hdev, e.g. bcm_close) > 5. Free the HCI device > > Signed-off-by: ZhaoJinming <[email protected]> > --- > drivers/bluetooth/hci_serdev.c | 18 +++++++++++------- > 1 file changed, 11 insertions(+), 7 deletions(-) > > diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c > index 593d9cefbbf9..e06b9d5b3846 100644 > --- a/drivers/bluetooth/hci_serdev.c > +++ b/drivers/bluetooth/hci_serdev.c > @@ -397,18 +397,22 @@ void hci_uart_unregister_device(struct hci_uart *hu) > struct hci_dev *hdev = hu->hdev; > > cancel_work_sync(&hu->init_ready); > - if (test_bit(HCI_UART_REGISTERED, &hu->flags)) > - hci_unregister_dev(hdev); > - hci_free_dev(hdev); > - > - cancel_work_sync(&hu->write_work); > - > - hu->proto->close(hu); > > + /* Clear HCI_UART_PROTO_READY first to prevent the write_wakeup > + * callback from re-scheduling write_work via hci_uart_tx_wakeup(). > + */ > if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { > clear_bit(HCI_UART_PROTO_READY, &hu->flags); > serdev_device_close(hu->serdev); > } > + > + cancel_work_sync(&hu->write_work); > + > + if (test_bit(HCI_UART_REGISTERED, &hu->flags)) > + hci_unregister_dev(hdev); > + > + hu->proto->close(hu); > + hci_free_dev(hdev); > percpu_free_rwsem(&hu->proto_lock); > } > EXPORT_SYMBOL_GPL(hci_uart_unregister_device); > -- > 2.51.0 It looks like sashiko found some problems with these changes: https://sashiko.dev/#/patchset/0BDE51B0554940FB%2B20260805103612.916678-1-zhaojinming%40uniontech.com -- Luiz Augusto von Dentz