The Linux kernel powers a massive portion of the world’s infrastructure, from web servers to smartphones. Security issues in the kernel can have far-reaching consequences, especially in subsystems like BPF (Berkeley Packet Filter) that handle untrusted user input and run code in the kernel.

In this long read, we dive deep into CVE-2024-42068, a vulnerability discovered and fixed in the Linux kernel’s BPF subsystem, specifically around improper use of memory protection in set_memory_ro(). We'll break down what went wrong, how it could be exploited, see code snippets, and offer references for further reading.

What is CVE-2024-42068?

This CVE covers a vulnerability where the kernel’s BPF subsystem didn't correctly handle errors returned by set_memory_ro(). As a result, memory that was supposed to be read-only (RO) could actually stay writable in certain error scenarios—this opens the door to privilege escalation or code execution inside the kernel.

Technical Background

The Linux BPF JIT (Just-in-Time) compiler compiles BPF bytecode into native machine code and stores it in memory. After compiling, this memory should be *write-protected* to prevent tampering. The function that does this is set_memory_ro(), which marks a memory region as read-only.

Problem:
If set_memory_ro() fails, earlier kernel code did not properly check the return value. The expectation was "we tried to mark this memory as read-only, let’s assume it worked." But under memory pressure or other rare failure conditions, marking memory as read-only can fail, and the kernel would proceed as if everything went fine.

That means malicious code could potentially overwrite JITed BPF programs—bad news if attackers find a way to misuse this.

Site of the bug: bpf_prog_lock_ro() should check if set_memory_ro() succeeded, but the error was ignored.

Proof-of-Concept (PoC) Code

This kind of bug is hard to exploit directly as a regular user, but for educational purposes, let's see simplified code that demonstrates what went wrong.

Before: Vulnerable Code

// kernel/bpf/core.c (simplified)
void bpf_prog_lock_ro(struct bpf_prog *fp)
{
    set_memory_ro((unsigned long)fp->insnsi, fp->pages);
    // No error checking! Assumes function always succeeds.
}

After: Fixed Code

// After patch
int bpf_prog_lock_ro(struct bpf_prog *fp)
{
    int ret = set_memory_ro((unsigned long)fp->insnsi, fp->pages);
    if (ret) {
        // If set_memory_ro() failed, handle the error!
        pr_err("Failed to set BPF program memory read-only: %d\n", ret);
        return ret;
    }
    return ;
}

Reference:
- Kernel commit fixing the bug
- Linux BPF Mailing List Patch

Potential Exploit Scenario

It’s rare, but possible for regular users to trigger BPF JIT allocations (often via eBPF or seccomp filters). Here's how an attacker could exploit the vulnerability:

Find a way to fail set_memory_ro()

This requires a specific system state, like exhausting page tables or virtual memory area descriptors.

The attacker could overwrite code to inject arbitrary instructions, which the kernel later executes.

While this scenario is tough to pull off, it is valid according to the Linux kernel threat model.

Suppose an attacker manages to reach the following scenario

// Pseudo-code: attacker process
int fd = bpf_prog_load(...); // Load a JITed BPF program

// Under certain circumstances, set_memory_ro silently fails inside kernel.
// Now the attacker knows the memory region "fp->insnsi" is still writable.
// The attacker could (with required permissions) overwrite this memory region.

memcpy(kernel_memory_ptr, my_payload, payload_size);

// When the kernel calls this BPF program, it runs "my_payload"
// (potentially hijacked, malicious code).

*Who is affected?*

Primarily people that allow untrusted users to load eBPF programs, like cloud/hosting providers.

*What does it enable?*

Possible escalation from unprivileged to privileged user (root), or at minimum DoS (denial of service).

Update your kernel!

Make sure you're using a version that includes the fix (mainline commit: b6c8c9ea813e2d5e4668fb8cf3669aadf449b2ea).

References & Further Reading

- Official Linux Kernel Commit
- Linux BPF Mailing List Discussion
- CVE Details for CVE-2024-42068

Summary Table

| Key Component | Details |
|------------------------ |--------------------------------------------------|
| Vulnerability | Improper error handling in set_memory_ro() |
| Component | Linux Kernel BPF |
| How to exploit | Keep code writable, then modify JITed BPF code |
| Severity | High (if preconditions are met) |
| Patch available? | Yes |
| Who should care? | Cloud/server admins, kernel developers |

Conclusion

CVE-2024-42068 is a good example of why kernel code should *never* assume a function works perfectly every time—especially for something as critical as memory protections. Always check return values. For Linux users and admins, update your systems and keep a close eye on BPF-related developments.

Timeline

Published on: 07/29/2024 16:15:06 UTC
Last modified on: 07/30/2024 19:02:12 UTC