On June 2024, a critical vulnerability was identified and patched in the Linux kernel affecting the eBPF (Extended Berkeley Packet Filter) subsystem—specifically, in the way tail calls interact with program replacement ("freplace"). The flaw, tracked as CVE-2024-47794, could allow an attacker to create an infinite tail call loop, crashing the system and potentially causing a denial of service.

In this post, we’ll break down what caused this issue, show code snippets to illustrate the problem and the fix, reference official upstream kernel patches, and help you understand how this affects your Linux systems.

eBPF Tail Calls and freplace: The Basics

eBPF allows custom code to run in the kernel with safety checks. It’s used for things like tracing, filtering, and sandboxing. Tail calls let eBPF programs jump into other eBPF programs using a map (like prog_array), allowing complex chains.

freplace is a feature where you can extend or replace a function inside a BPF program with another one, offering flexibility and modularity.

But, this flexibility came with a dangerous edge case...

You have a BPF program that supports tail calls via a prog_array map.

2. You use freplace to extend/rewrite one of the functions in the chain.

The replaced function itself performs a tail call, looping the chain back.

4. The tail_call_cnt counter (which usually prevents infinite recursion) gets reset whenever the freplace’d function runs—because it’s seen as a new top-level program.

This loop can be visualized as

entry_tc -> subprog_tc -> entry_freplace --tailcall-> entry_tc (loop back)

The state resets every time entry_freplace is called, so the built-in safety net is bypassed.

Impact

Successful exploitation leads to an unbreakable infinite loop in kernel context, which results in a system panic (crash). This can be a straightforward denial of service (DoS) attack vector wherever untrusted users can load BPF programs.

Affected versions: Most currently supported Linux kernel versions before the patch are susceptible.

Official Patch & References

The patch was committed here (lkml.org) and will be included in stable kernel releases.
Discussion and review:
- Patch 1/1 bpf: Prevent tailcall infinite loop caused by freplace (lkml)
- Patch in kernel.org

Before the patch — problem scenario (simplified)

// entry_tc (main entry)
static __always_inline int entry_tc(struct __sk_buff *skb)
{
    return subprog_tc(skb); // Calls real or freplace’d subprog_tc
}

// in tc_bpf2bpf.c
static int subprog_tc(struct __sk_buff *skb)
{
    // ...
    return BPF_PROG_RUN(entry_freplace, skb); // replaced by freplace
}

// entry_freplace in tailcall_freplace.c (acts like a trampoline or stub)
static int entry_freplace(struct __sk_buff *skb)
{
    // Here, makes a tail call to entry_tc, restarting the chain
    tail_call(skb, &prog_array, 2); // index 2 is entry_tc
    return TC_ACT_OK;
}

Result: when entry_freplace is hit (from a chain starting entry_tc → subprog_tc), tail_call_cnt resets, no stack limit stops the loop, and the kernel dies.

The Fix: How the Kernel Solves It

The patch adds robust checks when adding programs to and from prog_array maps or extending with freplace.

Code Excerpts

// From kernel/bpf/syscall.c
if (prog->type == BPF_PROG_TYPE_EXT) {
    /* Don't allow extension program in prog_array map */
    return -EINVAL;
}

More checks for the relationship between extension and prog_array additions are present, blocking the problematic state entirely.

Exploit Details

Proof of Concept:
Although a full working eBPF exploit is complex and unsafe to host here, the publish kernel self-tests (selftests/bpf/tailcall_freplace.c) demonstrate the vulnerability chain.

Sources and Further Reading

- Upstream patch on LKML
- BPF documentation
- CVE-2024-47794 at cve.org *(when available)*

Conclusion

CVE-2024-47794 is a classic example of how evolving kernel features—freplace and tail calls—can interact in dangerous, unintended ways. The fix is elegant, simple, and broad: cut off any path where infinite recursion could occur. If you’re maintaining any Linux systems using BPF, make sure you’re patched!

If your kernel is unpatched and eBPF is enabled, don’t expose BPF loading to untrusted users!
Apply updates ASAP and stay safe.


*If you found this helpful, stay tuned for more deep-dive kernel vulnerability explorations!*

Timeline

Published on: 01/11/2025 13:15:22 UTC
Last modified on: 05/04/2025 09:39:14 UTC