CVE-2026-89991 Overview
CVE-2026-89991 is a Linux kernel vulnerability in the Berkeley Packet Filter (BPF) subsystem. The flaw resides in __pcpu_freelist_push(), which can enter an infinite loop when only one CPU is possible and a Non-Maskable Interrupt (NMI) re-enters pcpu_freelist_push() while the interrupted context holds that CPU's freelist lock. The condition affects uniprocessor kernels (CONFIG_SMP=n) and SMP kernels constrained to one possible CPU through nr_cpus=1 or possible_cpus=1. When the current-CPU fast path fails, the fallback loop iterates cpu_possible_mask while skipping the current CPU, leaving no candidate to acquire and preventing progress.
Critical Impact
A BPF program triggered from NMI context can cause an unrecoverable kernel hang on single-CPU Linux systems, resulting in denial of service.
Affected Products
- Linux kernel with BPF support compiled as uniprocessor (CONFIG_SMP=n)
- Linux kernel booted with nr_cpus=1 or possible_cpus=1
- Systems running BPF programs (perf-event, raw tracepoint) that call htab_map_delete_elem
Discovery Timeline
- 2026-09-16 - CVE-2026-89991 published to the National Vulnerability Database
- 2026-09-16 - Last updated in NVD database
Technical Details for CVE-2026-89991
Vulnerability Analysis
The defect is an Infinite Loop denial-of-service condition in the BPF per-CPU freelist implementation. Freelist push and pop operations first attempt to acquire the current CPU's head lock through a fast path. When that acquisition fails, the code falls back to walking cpu_possible_mask to locate an alternate head.
On systems with a single possible CPU, the fallback iteration skips the current CPU and finds no remaining candidates. The loop therefore makes no lock acquisition attempt and spins indefinitely. The raw_res_spin_lock() helper correctly returns -EDEADLK for the same-CPU recursive acquisition, but the caller has nowhere else to try.
The observed call stack shows a perf-event BPF program running in NMI context invoking htab_map_delete_elem → free_htab_elem → pcpu_freelist_push, while the interrupted context was executing an identical path from a raw_tp/sys_enter program. The NMI arrived while the base context held the sole per-CPU freelist lock, producing the wedge.
Root Cause
The root cause is the removal of an extra fallback head during the rqspinlock conversion. Prior to that change, an additional head existed to guarantee forward progress when the only per-CPU head was unavailable. Without it, freelist push, which cannot fail without losing a preallocated element, has no recovery path in the single-CPU-with-NMI scenario.
Attack Vector
Exploitation requires local capability to load and trigger BPF programs, typically requiring CAP_BPF or CAP_SYS_ADMIN. An unprivileged attacker cannot reach this path on hardened systems. Where BPF loading is permitted, a crafted perf-event or tracepoint program that performs hashmap deletions can be timed to fire during another BPF hashmap operation, wedging the kernel.
The patch restores the extra fallback head, keeps the current-CPU fast path, then tries the other possible CPUs and finally the extra head. The pop path is also updated to consult the extra head so that nodes placed there can be reused. See the Linux Kernel Commit Fixes for the applied change.
Detection Methods for CVE-2026-89991
Indicators of Compromise
- A CPU stuck at 100% in kernel context with soft-lockup or RCU stall warnings referencing __pcpu_freelist_push or pcpu_freelist_push
- Kernel backtraces showing htab_map_delete_elem invoked from both an NMI-serviced perf event and an interrupted BPF tracepoint on the same CPU
- Unresponsive uniprocessor Linux hosts running BPF-based observability agents
Detection Strategies
- Collect kernel crash dumps and dmesg output for stack traces matching the published call chain involving pcpu_freelist_push and free_htab_elem
- Inventory hosts booted with CONFIG_SMP=n, nr_cpus=1, or possible_cpus=1 and correlate with BPF program loading events
- Audit bpf() syscall telemetry for loading of perf-event and raw_tp/sys_enter programs that modify BPF hashmaps
Monitoring Recommendations
- Alert on repeated soft-lockup or hard-lockup messages referencing BPF freelist symbols
- Track kernel package versions across the fleet and flag hosts running vulnerable versions prior to the fix commits
- Monitor auditd for SYSCALL entries invoking bpf(BPF_PROG_LOAD) on constrained-CPU systems
How to Mitigate CVE-2026-89991
Immediate Actions Required
- Apply the stable kernel updates referenced by commits a24a146a, a5b5e62b, and efebf649 from git.kernel.org
- Restrict BPF program loading to trusted principals by removing CAP_BPF and CAP_SYS_ADMIN from unprivileged workloads
- Reboot affected uniprocessor or CPU-constrained hosts after patching to ensure the corrected freelist logic is loaded
Patch Information
The fix restores the additional fallback head removed during the rqspinlock conversion and updates both push and pop paths to use it. Patches are available at Linux Kernel Commit Update, Linux Kernel Commit Patches, and Linux Kernel Commit Fixes. Consumers should track their distribution's stable kernel releases for backports.
Workarounds
- Boot with more than one possible CPU where hardware allows, avoiding nr_cpus=1 and possible_cpus=1 kernel command-line parameters
- Disable or unload third-party BPF-based observability agents on constrained-CPU hosts until the patch is applied
- Set kernel.unprivileged_bpf_disabled=1 via sysctl to prevent unprivileged BPF program loading
# Configuration example
sysctl -w kernel.unprivileged_bpf_disabled=1
echo 'kernel.unprivileged_bpf_disabled=1' > /etc/sysctl.d/90-bpf-hardening.conf
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

