CVE-2026-98644
NoneCVSS
—
EPSS
0.2%
Published
Oct 18, 2026
CISA due date
—
Cloudanix analysis
A bug in the Linux kernel can let certain network or security programs freeze one CPU for a long time, potentially making the whole system unresponsive until fixed.
- Exploitation
- Local Privilege
- Attacker needs
- Low Privilege
- Complexity
- Moderate
- Impact
- Denial Of Service
- Component
- OS kernel
- Class
- Denial of service
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
The flaw allows a single BPF_MAP_LOOKUP_BATCH or BPF_MAP_LOOKUP_AND_DELETE_BATCH call on an htab-based map to traverse every bucket without yielding the CPU, holding an RCU read lock and elevated bpf_prog_active across long runs of empty buckets or after copy_to_user, which can exceed the soft lockup threshold on large maps under CONFIG_PREEMPT_NONE.
Why it matters to the business
Systems performing frequent batch operations against large BPF hash maps can experience prolonged CPU stalls that trigger watchdogs, degrade responsiveness, or cause crashes, raising operational risk on high-scale Linux hosts until the kernel is updated.
How an attack unfolds
An attacker with the ability to load and invoke BPF programs repeatedly issues BPF_MAP_LOOKUP_BATCH syscalls against an LRU or other htab map containing millions of buckets; the absence of rescheduling points inside the native htab batch path keeps the CPU inside the critical section until the soft lockup watchdog fires.
How to fix it
Update to a kernel containing the referenced fix that inserts cond_resched_tasks_rcu_qs() after 64 consecutive empty buckets and after each copy_to_user inside the per-bucket loop; rebuild and reboot affected hosts.
How to confirm the fix worked
Confirm the running kernel contains commit 75134f16e7dd plus the additional schedule-point changes described; reproduce batch operations against maps with at least 16 M buckets under PREEMPT_NONE and verify no soft lockup occurs.
Typical attack path
- Obtain capability to load BPF programs or control a process that performs batch map operations
- Create or target an htab-based map with a very large bucket count
- Issue repeated BPF_MAP_LOOKUP_BATCH or BPF_MAP_LOOKUP_AND_DELETE_BATCH calls in a tight loop
- Trigger exhaustion of the soft lockup timeout on the target CPU
How to detect it
Search kernel logs for soft lockup watchdog entries that mention bpf, htab, or __htab_map_lookup_and_delete_batch; correlate with processes performing repeated BPF map batch syscalls on large hash maps.
- soft lockup.*__htab_map_lookup_and_delete_batch
- bpf_prog_active elevated
- cond_resched_tasks_rcu_qs
What your security team should do
- Prioritize kernel updates on any host running CONFIG_PREEMPT_NONE or PREEMPT_VOLUNTARY that uses large htab maps
- Audit workloads for use of BPF_MAP_LOOKUP_BATCH on production systems
- Monitor for soft lockup messages involving bpf or htab in system logs
- Apply the fix within normal change windows given the low EPSS and absence from KEV
The record
In the Linux kernel, the following vulnerability has been resolved: bpf: Avoid soft lockup in __htab_map_lookup_and_delete_batch() __htab_map_lookup_and_delete_batch() has no rescheduling point. The batch count bounds how many entries are copied out, not how many buckets are visited, so one BPF_MAP_LOOKUP_BATCH call can walk the map end to end. The empty-bucket fast path is worse: it stays inside a single rcu_read_lock() / bpf_disable_instrumentation() section for any run of consecutive empty buckets. That holds up on small maps, but it falls apart at scale. On a 144-CPU arm64 host running a CONFIG_PREEMPT_NONE kernel, periodic BPF_MAP_LOOKUP_BATCH calls against an LRU hash map with 16,777,216 buckets held a CPU inside the batch op for 77+ seconds and triggered the soft lockup watchdog. Commit 75134f16e7dd ("bpf: Add schedule points in batch ops") fixed this same problem in the generic batch ops, but not in this htab-native path, which every htab-based hash map variant uses for its lookup[_and_delete] batch ops. Complete that fix here. Leave the critical section after 64 consecutive empty buckets, call cond_resched_tasks_rcu_qs(), and resume at the saved bucket cursor. No locks are held at that point, and resuming from the cursor is already the function's behavior for non-empty buckets. Add the same call to the per-bucket loop after copy_to_user(), where every lock has been dropped. cond_resched_rcu() is not enough here: sleeping with bpf_prog_active elevated makes tracing programs on that CPU silently skip their invocations. Plain cond_resched() is not enough either. It is a no-op under PREEMPT and PREEMPT_LAZY, the only models arm64 and x86 have offered since commit 7dadeaa6e851 ("sched: Further restrict the preemption modes"). It is also never a Tasks RCU quiescent state, in any model: the reschedule counts as a preemption. The walking task stays a holdout and stalls every synchronize_rcu_tasks() caller, ftrace and BPF trampoline teardown included, until the syscall returns [1]. cond_resched_tasks_rcu_qs() is the usual tool for that [2]. It reports the quiescent state at each yield and still reschedules as cond_resched() does on PREEMPT_NONE and PREEMPT_VOLUNTARY kernels.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|