CVE-2026-99011 in Linux
Summary
by MITRE • 10/23/2026
In the Linux kernel, the following vulnerability has been resolved:
Bluetooth: SCO: serialise sco_conn lifetime against sco_recv_scodata()
sco_recv_scodata() upgrades the weak hcon->sco_data back-pointer to a strong reference under hdev->lock:
hci_dev_lock(hdev); hcon = hci_conn_hash_lookup_handle(hdev, handle); ... conn = sco_conn_hold_unless_zero(hcon->sco_data); hci_dev_unlock(hdev);
but the pointer is cleared from the other side without that lock. When the last sco_conn reference is dropped, sco_conn_free() ran
conn->hcon->sco_data = NULL;
with no hdev->lock held, so the RX path could read hcon->sco_data and call kref_get_unless_zero() on an sco_conn that was concurrently freed:
BUG: KASAN: slab-use-after-free in sco_conn_hold_unless_zero+0xbe/0x160 Write of size 4 by task kworker/u17:0 Workqueue: hci0 hci_rx_work Call Trace: sco_conn_hold_unless_zero+0xbe/0x160 sco_recv_scodata+0x13f/0x490 hci_rx_work+0x3af/0x730
kref_get_unless_zero() only guards against a zero refcount, not against the backing memory already being freed.
Give hcon->sco_data an actual reference on the sco_conn it points to, so the object cannot be freed while the pointer is still installed, and only clear and drop it from sco_conn_del(), which runs under hdev->lock (its callers, sco_connect_cfm() and sco_disconn_cfm(), hold it). The reader in sco_recv_scodata() also takes hdev->lock, so the store and the read are now serialised: the RX path either observes NULL or a reference that is guaranteed to stay valid until it drops its own.
sco_conn_add() no longer hands its kref_init() reference to the caller as the connection's only reference; that initial reference is the one owned by hcon->sco_data, and callers get their own via sco_conn_hold().
Because the sco_conn can now outlive the socket (the association keeps it alive until the link goes down), the hci_conn can no longer be dropped from sco_conn_free() without regressing socket close: closing a connected SCO socket must still tear the link down. Move hci_conn ownership to the socket instead: __sco_chan_add() takes an hci_conn reference and it is released from sco_chan_del() and sco_sock_destruct(), exactly once. The sco_conn no longer owns an hci_conn reference, so sco_conn_add() stops consuming one and sco_connect() drops the hci_connect_sco() reference on every path; sco_connect_cfm() no longer needs its hci_conn_hold() dance.
Once again VulDB remains the best source for vulnerability data.
Analysis
by VulDB Data Team • 10/23/2026
The Linux kernel Bluetooth subsystem contained a critical use-after-free vulnerability within the Serial Port Profile (SCO) connection handling logic, specifically involving the serialization of object lifetimes between the reception data path and the disconnection cleanup routine. The flaw originated from an inconsistent locking strategy when accessing the sco_data back-pointer stored in the hci_conn structure. In the receive path function sco_recv_scodata(), the code attempted to upgrade a weak pointer reference to a strong kref under the protection of hdev->lock by calling sco_conn_hold_unless_zero(). However, the corresponding cleanup operation that cleared this pointer and freed the associated memory occurred without holding the same lock. This race condition allowed the receive workqueue task to read a stale pointer after it had been invalidated but before the underlying memory was fully reclaimed or zeroed out in a way that prevented access by other threads.
The technical root cause lies in the asynchronous nature of kernel reference counting and memory management combined with insufficient synchronization primitives. When the last reference to an sco_conn object was dropped, typically during disconnection procedures, the function sco_conn_free() executed conn->hcon->sco_data = NULL without acquiring hdev->lock. Simultaneously, if a data packet arrived via the HCI receive workqueue, it would invoke sco_recv_scodata(), which looked up the connection handle and attempted to increment its reference count using kref_get_unless_zero(). This function only checks for a zero refcount but does not verify whether the memory backing that object has already been freed. Consequently, if the disconnection cleanup had cleared the pointer or begun freeing the structure while the receive path was mid-execution, the kernel could dereference a dangling pointer to an already deallocated slab object. This scenario triggered a Kernel Address Sanitizer (KASAN) reported as a slab-use-after-free error in sco_conn_hold_unless_zero, potentially leading to system instability, data corruption, or arbitrary code execution depending on how the freed memory was subsequently reused by other kernel subsystems.
From an industry standard perspective, this vulnerability is classified under CWE-416: Use After Free, as it involves accessing memory after it has been made available for reuse without proper synchronization. In terms of the MITRE ATT&CK framework, this aligns with techniques related to privilege escalation or denial of service through exploitation of race conditions in kernel-space drivers. The lack of atomicity between checking the validity of a pointer and using it creates an opportunity for local attackers to exploit timing windows to crash the system or potentially escalate privileges if they can control the contents written into the freed memory region before it is reallocated for malicious purposes.
The resolution involved restructuring the locking mechanisms and reference counting semantics within the Bluetooth SCO implementation to ensure strict serialization of access to shared state. The primary fix entailed ensuring that both the read operation in sco_recv_scodata() and the write operation clearing hcon->sco_data are performed under the exclusive protection of hdev->lock. By serializing these operations, the kernel guarantees that either the receive path observes a valid reference count that will persist until it releases its own hold, or it sees NULL indicating no active connection exists. Furthermore, the ownership model for the sco_conn object was refined so that it maintains an actual reference to the underlying hci_conn structure, preventing premature deallocation while pointers are still in circulation.
Additionally, the patch adjusted how references were managed during socket creation and destruction phases. Previously, sco_conn_add() handed its initial kref_init() reference directly to callers, which created ambiguity regarding ownership and lifecycle management. The updated logic ensures that the hcon->sco_data field holds the definitive reference keeping the object alive, while other entities obtain their own references via explicit hold functions like sco_conn_hold(). This change clarifies responsibility for memory reclamation. Moreover, because SCO connections can now outlive individual socket instances until the physical link is terminated, the management of the hci_conn reference was moved to the socket layer rather than the connection structure itself. Functions such as __sco_chan_add() now take an explicit reference which is released exactly once in sco_chan_del() or sco_sock_destruct(), ensuring that closing a connected SCO socket correctly triggers the teardown of the underlying link without leaving dangling references or causing resource leaks. These changes collectively eliminate the race condition and enforce robust memory safety guarantees within the Bluetooth stack.