Where
-Infinity
0
Severity
7.5
Use After Free
AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

The Bluetooth LE host queues received L2CAP connection-oriented channel (CoC) data for deferred processing through a struct kwork embedded in the channel object (lechan->rxwork, handler l2caprxprocess()) whenever the channel uses a dynamic PSM (0x0080-0x00FF). Channel teardown in l2capchandestroy() in subsys/bluetooth/host/l2cap.c cancels the retransmission-timeout work and drains the RX FIFO, but never cancels rxwork. Because that work item was submitted to the system workqueue while HCI receive processing runs on the dedicated Bluetooth RX workqueue (CONFIGBTRECVWORKQBT, the default), a queued rxwork item can outlive the channel it points into.

A remote, unauthenticated peer with an established CoC channel triggers this by sending a data K-frame immediately followed by an L2CAP Disconnect Request. The K-frame submits rxwork to the system workqueue; because both workqueue threads are cooperative and the Bluetooth RX workqueue runs at the higher priority (KPRIOCOOP(CONFIGBTRXPRIO) versus CONFIGSYSTEMWORKQUEUEPRIORITY), the pending item cannot run before the following Disconnect Request is processed in ledisconnreq() -> l2capchandel() -> l2capchandestroy(). The stack then invokes the released() callback, which the API documents as meaning the stack has dropped all references and the application may free the channel memory.

The application therefore frees or re-accepts into an object that the system workqueue still holds in its pending list. If the memory is freed and reallocated, the workqueue later dereferences a list node and a handler function pointer read from reused memory; if the object is re-used for a later connection, l2capchanadd() calls kworkinit() on a still-enqueued work item, corrupting the workqueue's pending list so that unrelated work items are dropped or the queue spins on a looped list. A related variant lets l2caprxprocess() run concurrently with teardown, racing the netbuf unref of lechan->sdu and the clearing of chan->conn.

The fix routes the channel RX work to the Bluetooth workqueue - the same context in which every teardown path runs - and adds an explicit kworkcancel() of lechan->rxwork in l2capchandestroy(), so no reference to the channel survives the released() callback. Configurations without CONFIGBTL2CAPDYNAMICCHANNEL, or that only use SIG-assigned PSMs (EATT 0x0027, OTS 0x0025) which take the inline receive path, are not affected.

First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203