A security flaw identified as CVE-2024-56610 was recently discovered and fixed in the Linux kernel, specifically affecting the Kernel Concurrency Sanitizer (KCSAN) when used with PREEMPT_RT real-time kernels. This bug led to kernel "splats" (crash dumps) caused by sleeping locks being used in contexts that don't allow sleeping, potentially destabilizing or crashing the entire system.

In this post, we'll break down what caused this bug, walk through the technical details, explore the patch and how it works, and provide exploit guidance for vulnerability researchers and kernel maintainers. We'll use clear, simple language and some code snippets to illustrate the issue.

The Problem

KCSAN is a tool inside the Linux kernel for detecting data races at runtime. It tries to report any suspicious memory operations that could signal a race condition (a classic concurrency bug). To avoid flooding the kernel logs, KCSAN keeps an in-kernel report filter list that stops duplicate reports.

But this filter list was being guarded by a regular spinlock_t, meaning that on PREEMPT_RT kernels (real-time patches enabled), this lock can *sleep*—and that doesn't work in all contexts, such as inside an IRQ (interrupt) handler.

Consider this crash from a KCSAN-enabled, PREEMPT_RT kernel

BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48
in_atomic(): 1, irqs_disabled(): 1, non_block: , pid: , name: swapper/1
...
rt_spin_lock+x68/x170
kcsan_skip_report_debugfs+x43/xe
print_report+xb5/x590
kcsan_report_known_origin+x1b1/x1d

Here, KCSAN tried to obtain the filterlist spinlock in an atomic context (interrupt), but the lock implementation was able to sleep. That led to this dangerous and illegal situation—a classic recipe for kernel panics or lock-ups.

Inside kernel/kcsan/report.c, the report filter list lock looked like this

static DEFINE_SPINLOCK(report_filterlist_lock);
// ...later in the code...
spin_lock(&report_filterlist_lock);
/* filter logic */
spin_unlock(&report_filterlist_lock);

Key Problem: On PREEMPT_RT, even spinlocks may sleep if acquired in contexts where sleeping is illegal (like IRQ handlers!). This is because PREEMPT_RT replaces some spinlocks with sleeping locks for better real-time response, but IRQ code must always use raw spinlocks.

That tried to lock report_filterlist_lock.

- The PREEMPT_RT mutex implementation WARNed: "sleeping function called from invalid context" (deadly for kernel scheduling).

The Fix: Use a Raw Spinlock

Raw spinlocks (raw_spinlock_t) on Linux are never replaced with sleeping mutexes and are always safe to use in interrupt or atomic contexts.

Here's the essential fix that landed upstream

// kernel/kcsan/report.c

- static DEFINE_SPINLOCK(report_filterlist_lock);
+ static DEFINE_RAW_SPINLOCK(report_filterlist_lock);

...
- spin_lock(&report_filterlist_lock);
+ raw_spin_lock(&report_filterlist_lock);

/* filter logic */

- spin_unlock(&report_filterlist_lock);
+ raw_spin_unlock(&report_filterlist_lock);

#### Upstream Patch Reference

- kcsan: Turn report_filterlist_lock into a raw_spinlock

Memory Allocation Caution

Normally, allocations for filter changes happen under lock, but since that could sleep, the fixed code must pre-allocate any memory outside the locked section:

void *new_filter = NULL;
if (need_to_add_entry)
    new_filter = kmalloc(..., GFP_KERNEL); // allocating before locking!

raw_spin_lock(&report_filterlist_lock);
// modify filter list with pre-allocated new_filter
raw_spin_unlock(&report_filterlist_lock);

If the filter isn't modified, just free the allocated memory after unlocking.

Exploit Potential

Can an attacker trigger this bug in real life?
This bug is not directly exploitable for privilege escalation, but it's important in deterministic real-time environments. If untrusted code triggers frequent data races, it could cause the kernel to crash (DoS) by hitting this bug repeatedly.

Enable KCSAN and PREEMPT_RT (uncommon but used in diagnostics or real-time systems).

- From userspace, execute code that causes repeated KCSAN reports, possibly through syscalls or via debugfs.

Cause the kernel to hit a lock under IRQ context, leading to system crash or hang.

Proof-of-Concept:
You would need a PREEMPT_RT kernel and a way to trigger a KCSAN race from code likely to execute in an IRQ or with hardirqs off (think: intense concurrent workloads, or code modifying kernel objects from workqueues/interrupts).

Kernel Developers: If creating locking around data, know which context your code is called from!

- Real-Time Application Writers: Monitor for any kernel splats relating to lock sleeping, and inform kernel maintainers if you see them.

References

- Linux Kernel Patch Commit
- PREEMPT_RT Documentation
- KCSAN Kernel Documentation
- Original Issue Discussion

Conclusion

While CVE-2024-56610 is unlikely to be a direct attack vector, it reveals the complexity of kernel correctness in real-time environments. The fix—a straightforward switch to raw_spinlock_t—shows that even minor locking misunderstandings can have serious consequences in context-aware code.

Always review your locks in the kernel!
Small details can keep the world’s servers—and your custom kernels—running safely.


*(Exclusive to this writeup: this summary was written in clear terms for easy understanding, with actionable code context, proof-of-concept outline, and guidance for both users and developers.)*

Timeline

Published on: 12/27/2024 15:15:20 UTC
Last modified on: 05/04/2025 09:59:47 UTC