Skip to content

[PW_SID:1143156] [v2] Bluetooth: hci_serdev: Fix use-after-free in hci_uart_unregister_device() - #565

Closed
BluezTestBot wants to merge 6 commits into
workflowfrom
1143156
Closed

[PW_SID:1143156] [v2] Bluetooth: hci_serdev: Fix use-after-free in hci_uart_unregister_device()#565
BluezTestBot wants to merge 6 commits into
workflowfrom
1143156

Conversation

@BluezTestBot

Copy link
Copy Markdown

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
and write to hdev->stat 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. Save the PROTO_READY state and clear it under the write lock so
    a concurrent hci_uart_tx_wakeup() cannot re-schedule write_work
  2. Cancel write_work (no new work can be scheduled and no work is
    in flight)
  3. Unregister the HCI device
  4. Close the protocol (may access hu->hdev and the serdev device)
  5. Close the serdev port (safe now that write_work is quiesced and
    protocol is done)
  6. Free the HCI device

Also free any partially transmitted frame (hu->tx_skb) left over by
write_work once the transmit path is quiesced, since hci_uart_close()
would skip hci_uart_flush() because HCI_UART_PROTO_READY is cleared.

Signed-off-by: ZhaoJinming zhaojinming@uniontech.com

Fix a use-after-free in hci_uart_unregister_device() where the HCI
device could be freed (hci_free_dev) before write_work was cancelled,
allowing a concurrently running write_work to access hu->hdev after
the memory had been freed.

The teardown sequence is reordered to mirror the tty/ldisc path
(hci_uart_tty_close) and to account for the serdev-specific teardown:
the serdev port is closed only after write_work and the protocol are
fully torn down, and any partially transmitted frame is freed once the
transmit path is quiesced.

Changes in v2:

  • Clear HCI_UART_PROTO_READY under percpu_down_write() to prevent a
    concurrent hci_uart_tx_wakeup() from re-scheduling write_work via
    the write_wakeup callback once the device is torn down.
  • Cancel write_work before closing the serdev device to avoid a
    use-after-free in the serdev/TTY backend.
  • Close the serdev device after the protocol close, since some protocol
    close handlers (e.g. qca_close) still access the serdev device.
  • Free any partially transmitted frame (hu->tx_skb) after write_work is
    quiesced.

drivers/bluetooth/hci_serdev.c | 46 ++++++++++++++++++++++++++++++++++++------
1 file changed, 40 insertions(+), 6 deletions(-)


base-commit: db2ddb87143519e20a95aa36c60b36107b736a58
change-id: 20260810-bluetooth-hci-serdev-uart-unregister-ce37ebb29283

Best regards,

tedd-an and others added 6 commits August 7, 2026 20:53
This patch adds workflow files for ci:

[sync.yml]
 - The workflow file for scheduled work
 - Sync the repo with upstream repo and rebase the workflow branch
 - Review the patches in the patchwork and creates the PR if needed

[ci.yml]
 - The workflow file for CI tasks
 - Run CI tests when PR is created

Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
This replaces the bzcafe action with bluez/action-ci so we can maintain
everything in the github bluez organization

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This attempts to sync every 5 minutes instead of 30.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
bluez/action-ci uses master as default branch for workflow which is
incorrect for kernel

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
The CI action now creates individual GitHub Check Runs per test, which
requires 'checks: write' permission on the GITHUB_TOKEN. Also make the
pull_request trigger types explicit to include 'reopened', allowing CI
to be retriggered by closing and reopening a PR.
…ce()

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
and write to hdev->stat 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. Save the PROTO_READY state and clear it under the write lock so
   a concurrent hci_uart_tx_wakeup() cannot re-schedule write_work
2. Cancel write_work (no new work can be scheduled and no work is
   in flight)
3. Unregister the HCI device
4. Close the protocol (may access hu->hdev and the serdev device)
5. Close the serdev port (safe now that write_work is quiesced and
   protocol is done)
6. Free the HCI device

Also free any partially transmitted frame (hu->tx_skb) left over by
write_work once the transmit path is quiesced, since hci_uart_close()
would skip hci_uart_flush() because HCI_UART_PROTO_READY is cleared.

Signed-off-by: ZhaoJinming <zhaojinming@uniontech.com>
@github-actions

Copy link
Copy Markdown

CheckPatch
Desc: Run checkpatch.pl script
Duration: 0.75 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

VerifyFixes
Desc: Verify Fixes tag format and validity
Duration: 0.13 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

VerifySignedoff
Desc: Verify Signed-off-by chain
Duration: 0.13 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

GitLint
Desc: Run gitlint
Duration: 0.67 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

SubjectPrefix
Desc: Check subject contains "Bluetooth" prefix
Duration: 0.13 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

BuildKernel
Desc: Build Kernel for Bluetooth
Duration: 27.33 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

CheckAllWarning
Desc: Run linux kernel with all warning enabled
Duration: 29.56 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

CheckSparse
Desc: Run sparse tool with linux kernel
Duration: 28.05 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

BuildKernel32
Desc: Build 32bit Kernel for Bluetooth
Duration: 28.68 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

CheckKernelLLVM
Desc: Build kernel with LLVM + context analysis
Duration: 0.00 seconds
Result: SKIP
Output:

Clang not found

@github-actions

Copy link
Copy Markdown

TestRunnerSetup
Desc: Setup kernel and bluez for test-runner
Duration: 497.18 seconds
Result: PASS

@github-actions

Copy link
Copy Markdown

IncrementalBuild
Desc: Incremental build with the patches in the series
Duration: 25.38 seconds
Result: PASS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants