CVE-2026-46029
Description
In the Linux kernel, the following vulnerability has been resolved:
mm/slab: return NULL early from kmalloc_nolock() in NMI on UP
On UP kernels (!CONFIG_SMP), spin_trylock() is a no-op that unconditionally succeeds even when the lock is already held. As a result, kmalloc_nolock() called from NMI context can re-enter the slab allocator and acquire n->list_lock that the interrupted context is already holding, corrupting slab state.
With CONFIG_DEBUG_SPINLOCK on UP, the following BUG is triggered with the slub_kunit test module:
BUG: spinlock trylock failure on UP on CPU#0, kunit_try_catch/243 [...] Call Trace:
dump_stack_lvl+0x3f/0x60 do_raw_spin_trylock+0x41/0x50 _raw_spin_trylock+0x24/0x50 get_from_partial_node+0x120/0x4d0 ___slab_alloc+0x8a/0x4c0 kmalloc_nolock_noprof+0x164/0x310 [...]
Fix this by returning NULL early when invoked from NMI on a UP kernel.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
kmalloc_nolock() in the Linux kernel returns NULL early when called from NMI context on UP systems to prevent slab corruption from re-entering a held spinlock.
Vulnerability
In the Linux kernel, kmalloc_nolock() on UP kernels (!CONFIG_SMP) can be safely re-entered from NMI context because spin_trylock() is a no-op that always succeeds. This allows the function to acquire n->list_lock while the interrupted context already holds it, corrupting slab allocator state. The issue is demonstrated with CONFIG_DEBUG_SPINLOCK and the slub_kunit test module showing a BUG: spinlock trylock failure on UP trace [1].
Exploitation
An attacker capable of triggering an NMI (Non-Maskable Interrupt) on a UP kernel while kmalloc_nolock() is executing in the interrupted context can cause re-entry into the slab allocator. The NMI handler must call kmalloc_nolock() (or a function that calls it) to reach the vulnerable code path. No special authentication or network access is required, only the ability to raise an NMI, which typically requires local access or certain hardware events.
Impact
Successful exploitation corrupts slab internal state, leading to memory corruption, system crashes, or potential privilege escalation depending on the corrupted data structures. The vulnerability is primarily a denial-of-service risk (system instability, panic) but under controlled conditions could be leveraged for further compromise.
Mitigation
The fix has been applied in the Linux kernel commit 5b31044e649e3e54c2caef135c09b371c2fbcd08 [1]. The patch returns NULL early from kmalloc_nolock() when called from NMI context on UP kernels. Users should update to a kernel version containing this commit or backport the fix. No workaround is available for unpatched systems beyond avoiding NMI-triggering operations.
AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
6a8d95d274be2mm/slab: return NULL early from kmalloc_nolock() in NMI on UP
1 file changed · +5 −1
mm/slub.c+5 −1 modifieddiff --git a/mm/slub.c b/mm/slub.c index 27aa0e2975a5f2..a89df6ddcc5874 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5752,6 +5752,11 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) * sleeping lock on RT. */ return NULL; + + /* On UP, spin_trylock() always succeeds even when it is locked */ + if (!IS_ENABLED(CONFIG_SMP) && in_nmi()) + return NULL; + retry: if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) return NULL; -- cgit 1.3-korg
d66553204a15mm/slab: return NULL early from kmalloc_nolock() in NMI on UP
1 file changed · +4 −1
mm/slub.c+4 −1 modifieddiff --git a/mm/slub.c b/mm/slub.c index 90af21126921d0..e423afa27d1a46 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5304,6 +5304,10 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) return NULL; + /* On UP, spin_trylock() always succeeds even when it is locked */ + if (!IS_ENABLED(CONFIG_SMP) && in_nmi()) + return NULL; + retry: if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) return NULL; -- cgit 1.3-korg
5b31044e649emm/slab: return NULL early from kmalloc_nolock() in NMI on UP
1 file changed · +4 −1
mm/slub.c+4 −1 modifieddiff --git a/mm/slub.c b/mm/slub.c index 161079ac5ba128..0baa906f39ab84 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5339,6 +5339,10 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) return NULL; + /* On UP, spin_trylock() always succeeds even when it is locked */ + if (!IS_ENABLED(CONFIG_SMP) && in_nmi()) + return NULL; + retry: if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) return NULL; -- cgit 1.3-korg
a8d95d274be2mm/slab: return NULL early from kmalloc_nolock() in NMI on UP
1 file changed · +5 −1
mm/slub.c+5 −1 modifieddiff --git a/mm/slub.c b/mm/slub.c index 27aa0e2975a5f2..a89df6ddcc5874 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5752,6 +5752,11 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) * sleeping lock on RT. */ return NULL; + + /* On UP, spin_trylock() always succeeds even when it is locked */ + if (!IS_ENABLED(CONFIG_SMP) && in_nmi()) + return NULL; + retry: if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) return NULL; -- cgit 1.3-korg
d66553204a15mm/slab: return NULL early from kmalloc_nolock() in NMI on UP
1 file changed · +4 −1
mm/slub.c+4 −1 modifieddiff --git a/mm/slub.c b/mm/slub.c index 90af21126921d0..e423afa27d1a46 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5304,6 +5304,10 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) return NULL; + /* On UP, spin_trylock() always succeeds even when it is locked */ + if (!IS_ENABLED(CONFIG_SMP) && in_nmi()) + return NULL; + retry: if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) return NULL; -- cgit 1.3-korg
5b31044e649emm/slab: return NULL early from kmalloc_nolock() in NMI on UP
1 file changed · +4 −1
mm/slub.c+4 −1 modifieddiff --git a/mm/slub.c b/mm/slub.c index 161079ac5ba128..0baa906f39ab84 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5339,6 +5339,10 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) return NULL; + /* On UP, spin_trylock() always succeeds even when it is locked */ + if (!IS_ENABLED(CONFIG_SMP) && in_nmi()) + return NULL; + retry: if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) return NULL; -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"On UP kernels, spin_trylock() is a no-op that unconditionally succeeds even when the lock is already held, allowing kmalloc_nolock() called from NMI context to re-enter the slab allocator and acquire n->list_lock that the interrupted context is already holding."
Attack vector
An attacker who can trigger an NMI (Non-Maskable Interrupt) on a UP (!CONFIG_SMP) kernel can cause kmalloc_nolock() to be invoked while the interrupted context already holds n->list_lock. Because spin_trylock() on UP unconditionally succeeds, the NMI handler re-enters the slab allocator and corrupts slab state. The bug is demonstrated by the slub_kunit test module, which triggers the NMI code path and produces a spinlock trylock failure BUG under CONFIG_DEBUG_SPINLOCK [patch_id=2660299].
Affected code
The vulnerable code is in the function kmalloc_nolock_noprof() in mm/slub.c [patch_id=2660299]. The function previously only guarded against NMI re-entry on PREEMPT_RT kernels, but lacked a check for UP (!CONFIG_SMP) kernels where spin_trylock() is a no-op.
What the fix does
The patch adds an early return of NULL at the top of kmalloc_nolock_noprof() when the kernel is compiled without CONFIG_SMP and the call originates from NMI context [patch_id=2660299]. This prevents the re-entrant slab allocation that would otherwise corrupt slab state. The existing PREEMPT_RT guard already returned NULL for NMI/hardirq on RT kernels; the new check handles the UP case where spin_trylock provides no actual locking.
Preconditions
- configKernel must be compiled without CONFIG_SMP (UP kernel)
- inputkmalloc_nolock() must be called from NMI context
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3News mentions
0No linked articles in our index yet.