In June 2024, a critical vulnerability (CVE-2024-36013) was disclosed and patched in the Linux kernel’s Bluetooth stack (specifically, the L2CAP layer). This exclusive writeup breaks down what the bug is, how it can be triggered, and why it’s dangerous. We’ll also review the code, show a basic reproduction scenario, and link to important references and patches.

[References](#references)

1. What is CVE-2024-36013?

A slab-use-after-free bug was fixed in how Linux handles certain Bluetooth connections via the L2CAP protocol. In short: under certain race conditions, the kernel could end up using a pointer after the memory it points to has already been freed — a classic use-after-free (UAF). This could allow local or even remote attackers (if triggering through Bluetooth) to cause a kernel crash, escalate privileges, or potentially gain code execution.

Impacted Components

- File: net/bluetooth/l2cap_core.c

Kernel: All mainline versions prior to the patch (mid-June 2024)

Linux Bluetooth uses l2cap_connect() to start setting up channel connections between two devices.

- While a new channel (chan) is being set up, it is added to a list that is protected by a mutex (chan_lock).

However, after the mutex is unlocked, the code continues to use the chan pointer.

- If (at the same time) another thread like l2cap_conn_del() decides to delete the whole connection and frees all the channels, the original thread may now be holding a pointer to memory that has just been freed!

Technical call stack summary

[use]
l2cap_bredr_sig_cmd
  l2cap_connect
    mutex_lock(&conn->chan_lock);
      chan = pchan->ops->new_connection(pchan); // alloc chan
      __l2cap_chan_add(conn, chan);
        l2cap_chan_hold(chan);
        list_add(&chan->list, &conn->chan_l); // (1)
    mutex_unlock(&conn->chan_lock);
    chan->conf_state // (4) <-- use after free
[free]
l2cap_conn_del
  mutex_lock(&conn->chan_lock);
    foreach chan in conn->chan_l:        // (2)
      l2cap_chan_put(chan);
        l2cap_chan_destroy
          kfree(chan)                   // (3) --> chan freed
  mutex_unlock(&conn->chan_lock);

So, if l2cap_connect has just finished using chan and someone else frees chan, the memory is invalid but the original function may still read from or write to it.


3. The Code Behind the Bug

Here are code snippets to help clarify what’s going on.

Vulnerable l2cap_connect function (before the patch)

// net/bluetooth/l2cap_core.c

struct l2cap_chan *l2cap_connect(...)
{
    mutex_lock(&conn->chan_lock);
    chan = pchan->ops->new_connection(pchan);
    __l2cap_chan_add(conn, chan);
    // ... more setup ...
    mutex_unlock(&conn->chan_lock);

    // CRITICAL: still using chan after possible free!
    if (chan->conf_state == ...) {
        // dangerous usage: use-after-free possible here
    }

    return chan; // returning a possibly freed pointer too!
}

Thread 1 keeps using chan (now freed). BOOM: UAF.

A simplified scenario, showing how this type of bug might be triggered (not a weaponized exploit)

// Pseudocode
// Thread 1
struct l2cap_chan *chan = l2cap_connect(...);

// Thread 2 (could be triggered by disconnect, timeout, etc.)
l2cap_conn_del(chan->conn);

// Back to Thread 1 (chan is now freed, but still used)
if (chan->conf_state == ...) { ... } // Dangling pointer access!

- Use kernel debugging tools like KASAN to prove the UAF

BUG: KASAN: slab-use-after-free in l2cap_connect+xa67/x11a
    net/bluetooth/l2cap_core.c:426
Read of size 8 at addr ffff88810bf040a by task <...>

This type of bug is very dangerous: often, a user with local code execution or even over Bluetooth (in rare cases) could use this for privilege escalation or code execution in the kernel context.


5. Patch and Hardening

The fix was to extend the mutex critical section: basically, make sure all uses of chan in l2cap_connect() occur while still holding the lock, so no other thread can free it.

Additionally, the return type was changed from a pointer to void so that freed pointer values aren’t returned anymore.

Patched code snippet

// net/bluetooth/l2cap_core.c

void l2cap_connect(...)
{
    mutex_lock(&conn->chan_lock);
    chan = pchan->ops->new_connection(pchan);
    __l2cap_chan_add(conn, chan);

    if (chan->conf_state == ...) {
        // All uses are now inside lock: safe!
    }

    mutex_unlock(&conn->chan_lock);
}

This prevents any other thread from freeing chan while it’s still being used—eliminating the use-after-free.


Upstream Patch:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a460aea07974bbacf2864a57a22f3c7e456eaae

Linux Bluetooth L2CAP Subsystem:

https://elixir.bootlin.com/linux/latest/source/net/bluetooth/l2cap_core.c

KASAN Official Documentation (for finding UAF bugs):

https://www.kernel.org/doc/html/latest/dev-tools/kasan.html

CVE Record:

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36013

Conclusion

CVE-2024-36013 is a classic example of how locking order and careful pointer management are critical in kernel code. If you maintain embedded devices or Linux distributions with Bluetooth enabled, patch as soon as possible! Bugs like this—although hard to trigger—are prized by attackers for their power: one wrong pointer, and a malicious user or device might take full control.

*If you found this breakdown useful, share and follow! Stay secure out there.*

Timeline

Published on: 05/23/2024 07:15:08 UTC
Last modified on: 07/03/2024 02:02:37 UTC