Published: June 25, 2024
Author: Linux Security Insights
In June 2024, a subtle but critical bug was patched in the Linux kernel’s virtual memory allocation (vmalloc) subsystem. The vulnerability, now identified as CVE-2024-39474, could trigger fatal kernel NULL pointer dereference panics under memory pressure, even when calling code expects such failures to be impossible. This post will break down what happened, why it matters, and how exploiting this bug could cause system instability or denial of service. All explained in straightforward language, with references and code examples.
What is the Problem?
When Linux code wants to allocate memory, it can use a variety of kernel memory allocation flags. One special flag, __GFP_NOFAIL, tells the kernel: never return NULL. If the memory allocation would fail, the kernel will try harder or even trigger the out-of-memory (OOM) killer to free up resources.
However, CVE-2024-39474 describes a situation where, despite this "never fail" promise, a call to vmalloc with __GFP_NOFAIL could still return NULL. That’s a big deal because callers don’t check for NULL in this situation—so the result is a crash.
a421ef303008 ("mm: allow !GFP_KERNEL allocations for kvmalloc") added support for __GFP_NOFAIL.
- dd544141b9eb ("vmalloc: back off when the current task is OOM-killed") tried to be friendly and back off from allocating memory for a task that’s about to be killed.
`c
// This should never return NULL thanks to __GFP_NOFAIL
void *memory = kvcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL | __GFP_NOFAIL);
// Code assumes memory != NULL
if (fatal_signal_pending(current))
break; // exits the allocation loop early
BUT this causes the function to return NULL—in violation of the __GFP_NOFAIL contract!
4. The caller gets a NULL pointer and dereferences it (since they assume it’s never NULL), causing a kernel panic.
Real-world Evidence
During OPLUS KASAN (Kernel Address Sanitizer) testing, this panic was observed. Here’s a snippet from that log:
oom-kill: ... task=gs.intelligence, pid=32454, ...
z_erofs_decompress_queue+x7f/x2258
--> be->decompressed_pages = kvcalloc(be->nr_pages, sizeof(struct page *), GFP_KERNEL | __GFP_NOFAIL);
// kernel panic by NULL pointer dereference.
erofs assume kvmalloc with __GFP_NOFAIL never return NULL.
Essentially, the code tried to decompress some data, called kvcalloc expecting a valid pointer, but got NULL due to the bug. This led directly to a crash.
Denial of Service (DoS) Attack
If a user space or kernel module calls vmalloc, kvmalloc, or related APIs with __GFP_NOFAIL and the system is under memory pressure (triggering the OOM killer), the bug could cause the kernel to panic and crash—even if the OOM-killed process is unrelated. In cloud or multi-user environments, this means an attacker could impose repeated system restarts simply by consuming enough memory and relying on this allocation pattern.
Below is a simplified pseudo-code summary to capture what went wrong
void *vulnerable_kvcalloc(size_t n, size_t size)
{
void *ptr = __vmalloc_node_range(size * n, ...,
GFP_KERNEL | __GFP_NOFAIL, ...);
// 'ptr' should never be NULL, but due to buggy logic, it could be!
if (!ptr) {
// Never expected to reach here!
panic("kvcalloc failed!\n");
}
return ptr;
}
The offending check in the kernel source
// In mm/vmalloc.c, function vm_area_alloc_pages()
if (fatal_signal_pending(current))
break; // returns NULL in OOM-killed scenario
Patch & Fix Details
The fix landed quickly and was as simple as it was effective: skip the fatal signal check if __GFP_NOFAIL is set. This aligns kernel behavior with developer expectations.
Patch Diff Example
- if (fatal_signal_pending(current))
- break;
+ if ((gfp & __GFP_NOFAIL) == && fatal_signal_pending(current))
+ break;
Reference:
- Kernel commit fixing the bug
- Original bug report
What Should Users and Developers Do?
- Update your kernel! If you’re using a Linux version with the vulnerable vmalloc logic, upgrade to a patched kernel.
Conclusion
CVE-2024-39474 is a great example of how complex kernel interactions can violate long-standing expectations and create real-world reliability issues. Thanks to OPLUS and the Linux kernel community, this serious bug was squashed fast.
References and Further Reading
- Linux kernel patch for CVE-2024-39474
- LWN.net discussion on the patch
- kvmalloc and kvcalloc documentation
Timeline
Published on: 07/05/2024 07:15:10 UTC
Last modified on: 07/15/2024 06:50:09 UTC