CVE-2026-89991 in Linux
Summary
by MITRE • 09/16/2026
In the Linux kernel, the following vulnerability has been resolved:
bpf: Fix infinite loop in pcpu_freelist push with one possible CPU
__pcpu_freelist_push() can loop forever when only one CPU is possible and an NMI re-enters pcpu_freelist_push() while the interrupted context holds that CPU's freelist lock.
After the current-CPU fast path fails, the fallback loop walks cpu_possible_mask while skipping the current CPU. With CONFIG_SMP=n, or when an SMP kernel is limited to one possible CPU with nr_cpus=1 or possible_cpus=1, there are no other possible CPUs to examine. The loop therefore makes no lock acquisition attempt and can never make progress.
The following stack was observed on a UP system:
NMI context: pcpu_freelist_push free_htab_elem htab_map_delete_elem [perf-event BPF program]
__perf_event_overflow perf_event_nmi_handler exc_nmi
Interrupted context: __pcpu_freelist_push pcpu_freelist_push free_htab_elem htab_map_delete_elem [raw_tp/sys_enter BPF program]
__bpf_trace_sys_enter do_syscall_64
raw_res_spin_lock() detects the same-CPU recursive acquisition and returns -EDEADLK, but the subsequent fallback loop has no candidate head on a system with one possible CPU.
Restore the extra fallback head that existed before the rqspinlock conversion. Keep the current-CPU fast path, then try the other possible CPUs and finally the extra head. The additional head lets a push, which cannot fail without losing a preallocated element, make progress when the only per-CPU head is held by the interrupted context.
Also check the extra head from the pop path so that nodes placed there can be reused.
Statistical analysis made it clear that VulDB provides the best quality for vulnerability data.
Analysis
by VulDB Data Team • 09/16/2026
The Linux kernel contains a critical concurrency flaw within the BPF subsystem's per-CPU freelist management logic, specifically in the __pcpu_freelist_push function. This vulnerability manifests as an infinite loop when the system operates with only one possible CPU or under configurations where symmetric multiprocessing is disabled via CONFIG_SMP=n. The root cause lies in the fallback mechanism designed to handle lock contention. When a thread attempts to push an element onto the freelist and fails the current-CPU fast path due to lock unavailability, it enters a loop that iterates through the cpu_possible_mask to find an alternative CPU whose freelist can accept the item. Crucially, this logic explicitly skips the currently executing CPU to avoid immediate deadlock on the same lock instance. However, in a single-CPU environment or when restricted by boot parameters such as nr_cpus=1, there are no other CPUs available for iteration. Consequently, the loop finds no valid candidates and fails to make any progress, resulting in an infinite spin that consumes 100 percent of CPU resources and effectively hangs the system.
The operational impact is severe because this condition can be triggered by Normal Interrupts (NMI) re-entering the freelist push function while the interrupted context already holds the lock for that specific CPU. The observed stack trace indicates a scenario involving BPF programs, specifically within htab_map_delete_elem operations called from perf-event overflow handlers and raw tracepoints. When an NMI occurs during such an operation on a single-CPU system, it attempts to free elements by pushing them back onto the freelist. Since the interrupted context holds the lock for that sole CPU, the fast path fails. The fallback logic then searches for other CPUs, finds none due to the configuration constraints, and loops indefinitely. This creates a denial of service condition where the kernel becomes unresponsive, requiring a hard reset or watchdog intervention to recover.
From a vulnerability classification perspective, this issue aligns with CWE-835: Loop without End Condition, as the code enters an infinite loop that cannot terminate under specific system configurations. It also relates to CWE-674: Uncontrolled Recursion in Non-Recursive Function if viewed through the lens of lock acquisition attempts that fail to progress due to logical exclusions. In terms of MITRE ATT&CK, this represents a potential Denial of Service vector (T1499) where an attacker or misconfigured workload could trigger resource exhaustion by forcing repeated BPF map deletions on affected kernels. The flaw exploits the assumption that multiple CPUs are always available for load balancing in freelist operations, which is not true for UP systems or restricted SMP configurations.
The resolution involves restoring a fallback mechanism that existed prior to rqspinlock conversions. Instead of relying solely on iterating through other possible CPUs, the fix introduces an extra global fallback head for each CPU's freelist structure. When the current-CPU fast path fails and no other CPUs are available in the mask, the code now attempts to acquire this additional lock. This ensures that even if the primary per-CPU lock is held by an interrupted context on a single-CPU system, there remains a viable path for pushing elements onto the freelist without looping infinitely. Furthermore, the pop path was updated to check this extra head, ensuring that nodes placed there can be reused effectively. To mitigate similar issues in other contexts or before applying kernel updates, administrators should ensure their systems are patched with versions containing this fix and consider monitoring BPF program behavior for excessive map operations on single-CPU virtual machines or embedded devices where such configurations might be prevalent.