Skip to content

[PW_SID:1097482] [RFC] Bluetooth: btusb: wait for rx_work before freeing data on disconnect#217

Open
BluezTestBot wants to merge 6 commits into
workflowfrom
1097482
Open

[PW_SID:1097482] [RFC] Bluetooth: btusb: wait for rx_work before freeing data on disconnect#217
BluezTestBot wants to merge 6 commits into
workflowfrom
1097482

Conversation

@BluezTestBot
Copy link
Copy Markdown

syzbot reports a slab-use-after-free in skb_dequeue() called from
btusb_rx_work(), with the freed object being the btusb_data struct
released by btusb_disconnect() via usb_unbind_interface() -> kfree().

The race:

btusb_close() (via hci_unregister_dev -> hdev->close)
cancel_delayed_work(&data->rx_work); <-- non-sync
...
btusb_stop_traffic(data); <-- kills URBs

A URB completion callback fired between the non-sync cancel and
btusb_stop_traffic() can call data->recv_acl() -> hci_recv_frame(),
which enqueues to data->acl_q and schedules data->rx_work again.
The cancel above already returned, so the newly-scheduled rx_work
is left pending. btusb_disconnect() then proceeds to kfree(data)
while rx_work may still execute, dereferencing data->acl_q in
skb_dequeue().

Drain rx_work in btusb_disconnect() before kfree(data). At that
point hci_unregister_dev() has fully returned, btusb_close() has
already killed all URBs via btusb_stop_traffic(), so no new
scheduling can happen. Any rx_work item that was re-scheduled by a
late URB callback in the close path is guaranteed to be drained.

This runs without hci_req_sync_lock held (it was acquired by
hci_dev_do_close and released before btusb_disconnect resumes), so
the sync cancel has no deadlock interaction with the close path.

Fixes: 800fe5e ("Bluetooth: btusb: Add support for queuing during polling interval")
Reported-by: syzbot+d06554f43a8fb48030b0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d06554f43a8fb48030b0
Signed-off-by: Philipp Weber kernel@phwe.de

drivers/bluetooth/btusb.c | 9 +++++++++
1 file changed, 9 insertions(+)

base-commit: ab5fce87a778cb780a05984a2ca448f2b41aafbf

tedd-an and others added 6 commits May 13, 2026 17:39
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.
syzbot reports a slab-use-after-free in skb_dequeue() called from
btusb_rx_work(), with the freed object being the btusb_data struct
released by btusb_disconnect() via usb_unbind_interface() -> kfree().

The race:

  btusb_close() (via hci_unregister_dev -> hdev->close)
    cancel_delayed_work(&data->rx_work);   <-- non-sync
    ...
    btusb_stop_traffic(data);              <-- kills URBs

A URB completion callback fired between the non-sync cancel and
btusb_stop_traffic() can call data->recv_acl() -> hci_recv_frame(),
which enqueues to data->acl_q and schedules data->rx_work again.
The cancel above already returned, so the newly-scheduled rx_work
is left pending. btusb_disconnect() then proceeds to kfree(data)
while rx_work may still execute, dereferencing data->acl_q in
skb_dequeue().

Drain rx_work in btusb_disconnect() before kfree(data). At that
point hci_unregister_dev() has fully returned, btusb_close() has
already killed all URBs via btusb_stop_traffic(), so no new
scheduling can happen. Any rx_work item that was re-scheduled by a
late URB callback in the close path is guaranteed to be drained.

This runs without hci_req_sync_lock held (it was acquired by
hci_dev_do_close and released before btusb_disconnect resumes), so
the sync cancel has no deadlock interaction with the close path.

Fixes: 800fe5e ("Bluetooth: btusb: Add support for queuing during polling interval")
Reported-by: syzbot+d06554f43a8fb48030b0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d06554f43a8fb48030b0
Signed-off-by: Philipp Weber <kernel@phwe.de>
@github-actions
Copy link
Copy Markdown

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

@github-actions
Copy link
Copy Markdown

GitLint
Desc: Run gitlint
Duration: 0.33 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: 25.52 seconds
Result: PASS

@github-actions
Copy link
Copy Markdown

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

@github-actions
Copy link
Copy Markdown

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

@github-actions
Copy link
Copy Markdown

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

@github-actions
Copy link
Copy Markdown

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

@github-actions
Copy link
Copy Markdown

IncrementalBuild
Desc: Incremental build with the patches in the series
Duration: 24.21 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.

3 participants