Cloudanix VulnDB

CVE-2026-98536

None

CVSS

—

EPSS

0.2%

Published

Oct 18, 2026

CISA due date

—

Cloudanix analysis

Schedule a fix SSVC: Track

A Linux kernel bug can make computers freeze or crash when background file-writing tasks run at the same time as certain tracing or security tools.

Exploitation
Local Privilege
Attacker needs
Local User
Complexity
Moderate
Impact
Denial Of Service
Component
OS kernel
Class
Race Condition
Remediation
Upgrade
Effort
Medium
Patch risk
Low

What it actually does

The vulnerability prevents reporting a Tasks-RCU quiescent state during each pass of cleanup_offline_cgwb() inside cleanup_offline_cgwbs_workfn() because cond_resched() is a no-op under PREEMPT_DYNAMIC lazy and full modes on arm64/x86; long-running cgwb drains therefore stall any concurrent synchronize_rcu_tasks() caller.

Why it matters to the business

Production Linux systems can experience multi-minute stalls or forced kernel panics from the hung-task detector, disrupting services that rely on BPF program unload, ftrace, or cgroup writeback and increasing risk of unplanned downtime.

How an attack unfolds

A workload or local actor triggers repeated drains of a cgroup writeback domain containing millions of inodes; the drain worker never reports a Tasks-RCU quiescent state, so any BPF trampoline unlink or ftrace_shutdown that calls synchronize_rcu_tasks() blocks while holding locks, causing dozens of tasks to queue in D state until the hung-task timeout fires and panics the host.

How to fix it

Apply a kernel update that replaces the cond_resched() call inside the cgwb drain loop with cond_resched_tasks_rcu_qs() and wrap the call in a do-while construct so every pass reports a quiescent state.

How to confirm the fix worked

Inspect the patched kernel source for the cond_resched_tasks_rcu_qs() invocation inside cleanup_offline_cgwbs_workfn(); reproduce a large-inode cgwb drain while simultaneously detaching a BPF program and confirm synchronize_rcu_tasks() completes promptly without hung-task warnings.

Typical attack path

  1. Create or destroy cgroups to force cgwb offline work
  2. Attach millions of inodes to the dying writeback domain
  3. Trigger a BPF program detach or ftrace operation requiring synchronize_rcu_tasks()
  4. Wait for the drain worker to exceed the hung-task timeout and panic the system

How to detect it

Search kernel logs and dmesg for hung-task warnings containing synchronize_rcu_tasks, ftrace_shutdown, or bpf_trampoline_unlink_prog; correlate with worker threads named cleanup_offline_cgwbs_workfn running for many minutes.

What your security team should do

  • Prioritize kernel upgrades on all arm64 and x86 hosts running PREEMPT_DYNAMIC lazy or full modes
  • Add kernel log monitoring for hung-task events referencing synchronize_rcu_tasks or cleanup_offline_cgwbs_workfn
  • Temporarily avoid lazy preemption if live patching is unavailable and workloads frequently unload BPF programs

The record

In the Linux kernel, the following vulnerability has been resolved: writeback: report a Tasks-RCU quiescent state per cgwb drain pass cleanup_offline_cgwbs_workfn() drains a dying cgwb by calling cleanup_offline_cgwb() until it returns false, with a cond_resched() between passes. On a CONFIG_PREEMPTION kernel that cond_resched() does nothing: _cond_resched() is a plain "return 0", and under PREEMPT_DYNAMIC the full and lazy modes disable it. Since commit 7dadeaa6e851 ("sched: Further restrict the preemption modes") those are the only two models on the architectures with PREEMPT_LAZY support, arm64 and x86 among them, so the drain loop never reports a Tasks-RCU quiescent state. A worker draining a cgwb with millions of attached inodes runs for minutes. On a 6.18 arm64 host in lazy mode the cgwb worker drained one dying cgroup's writeback domain for over 11 minutes. A BPF program unlink (bpf_trampoline_unlink_prog -> bpf_trampoline_update -> unregister_ftrace_direct -> ftrace_shutdown -> synchronize_rcu_tasks()) waited on that grace period while holding the trampoline mutex, 42 tasks queued behind it in D state, and the hung task detector fired at 614 s and panicked the host. Any BPF or ftrace detach during a long drain inherits the drain's length. Fix this by calling cond_resched_tasks_rcu_qs() so we do not stall out anybody who calls sycnrhonize_rcu_tasks(). We put this in a do { } while loop because if we have many small cgroups cleanup_offline_cgwb() will return false and we will never call cond_resched_tasks_rcu_qs(), creating the same problem.

Affected packages

Ecosystem Package Introduced Fixed