# CVE-2026-98644: bpf: Avoid soft lockup in __htab_map_lookup_and_delete_batch()

> A local attacker can trigger a soft lockup in the Linux kernel BPF subsystem by performing batch lookups on large hash maps, causing a denial of service.

- **Severity:** Not scored
- **Exploited in the wild:** Not known
- **Login needed:** Any signed-in user
- **Attackable:** Local or same network only
- **Victim action needed:** Not needed
- **Fix available:** Yes
- **Published:** 18 Oct 2026
- **Updated:** 19 Oct 2026
- **Also known as:** AZL-108839, BELL-CVE-2026-98644, DEBIAN-CVE-2026-98644, GHSA-p6rx-8wrq-4gc7, UBUNTU-CVE-2026-98644

## What is CVE-2026-98644?

CVE-2026-98644 is a denial of service vulnerability in Linux, published on 18 Oct 2026. It can only be exploited from the same machine or local network, with no action from the victim.

### Official description

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.

## Which versions are affected by CVE-2026-98644?


## How do I fix CVE-2026-98644?

Apply the vendor's patch.

## Is CVE-2026-98644 being exploited?

There is no known exploitation of CVE-2026-98644 in the wild and no public exploit code.

## Fix prompt for AI coding agents

```text
Check this codebase for CVE-2026-98644 and fix it if it is affected.

What it is: CVE-2026-98644 is a denial of service vulnerability in Linux, published on 18 Oct 2026. It can only be exploited from the same machine or local network, with no action from the victim.
Exploitation: There is no known exploitation of CVE-2026-98644 in the wild and no public exploit code.

Affected product: Linux. No package-level version data is available, so check the vendor advisory linked from the reference page.

Task:
1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.
2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.
3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.
4. Run the tests and summarise what changed and why.
5. If nothing in the project is affected, say so and change nothing.

Reference: https://insights.sbomify.com/CVE-2026-98644/ (Markdown: https://insights.sbomify.com/CVE-2026-98644/index.md)
```

## Sources

- CVE record: https://www.cve.org/CVERecord?id=CVE-2026-98644
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-98644
- OSV: https://osv.dev/vulnerability/CVE-2026-98644

---
From sbomify Insights: https://insights.sbomify.com/CVE-2026-98644/
Summaries are generated and may contain mistakes; the official description above is the record.
