Cloudanix VulnDB

CVE-2026-98861

None

CVSS

—

EPSS

0.2%

Published

Oct 18, 2026

CISA due date

—

Cloudanix analysis

Schedule a fix SSVC: Track

A bug in the Linux kernel's tracing mechanism could let specially crafted code keep running after the kernel thinks it has cleaned it up, potentially crashing the system or allowing deeper attacks.

Exploitation
Local Privilege
Attacker needs
Low Privilege
Complexity
High
Impact
Privilege Gain
Component
OS kernel
Class
Use After Free
Remediation
Upgrade
Effort
Medium
Patch risk
Low

What it actually does

The vulnerability is a use-after-free in fprobe handlers that execute during RCU non-watching periods (idle loop or nohz_full extended quiescent states). Standard synchronize_rcu() and call_rcu() do not wait for these preemption-disabled sections, allowing unregister_fprobe() to free the fprobe while a handler is still running and dereferencing it.

Why it matters to the business

Kernel-level memory corruption in tracing and BPF kprobe-multi paths can cause system instability, crashes, or arbitrary code execution, affecting production Linux workloads that rely on dynamic probes or observability tooling.

How an attack unfolds

An attacker with the ability to register and then unregister an fprobe (via BPF or direct kernel interfaces) times the unregistration so that a handler is executing in an RCU non-watching context. After the fprobe is freed, the still-running handler performs a use-after-free access, which can be leveraged for memory corruption.

How to fix it

Upgrade to a Linux kernel version containing the fix that replaces guard(rcu) with guard(rcu_sched_notrace), adds rcu_is_watching() checks in unregister paths, and ensures early exit from handlers when RCU is not watching. Rebuild and reboot systems with the patched kernel; no configuration changes are required.

How to confirm the fix worked

Confirm the presence of the guard(rcu_sched_notrace) macro usage and the rcu_is_watching() guard in fprobe_ftrace_entry(), fprobe_fgraph_entry(), and fprobe_return() in the kernel source or running binary; verify that synchronize_rcu() paths now also check rcu_is_watching() before freeing fprobe structures.

Typical attack path

  1. Obtain privileges sufficient to load BPF programs or use fprobe registration interfaces
  2. Register an fprobe on a target function that can execute in idle or nohz_full contexts
  3. Trigger execution of the probed function while RCU is not watching
  4. Immediately unregister the fprobe, allowing the grace period to complete without waiting for the handler
  5. Continue execution of the now-freed handler to trigger the use-after-free

How to detect it

Search kernel logs (dmesg, journalctl) for use-after-free or KASAN reports mentioning fprobe, fprobe_ftrace_entry, or unregister_fprobe; inspect BPF program load/unload events around the time of crashes; look for processes using kprobe-multi that coincide with kernel panics.

What your security team should do

  • Prioritize kernel upgrades on systems that expose fprobe or BPF kprobe-multi interfaces to untrusted workloads
  • Monitor for kernel oops or use-after-free warnings in dmesg related to fprobe on production hosts
  • Restrict unprivileged BPF and fprobe registration via existing kernel lockdown or capability controls until patches are applied

The record

In the Linux kernel, the following vulnerability has been resolved: fprobe: Use guard(rcu_sched_notrace) and check rcu_is_watching() unregister_fprobe() and unregister_fprobe_async() (used by BPF kprobe-multi) rely on standard RCU grace periods (synchronize_rcu() and call_rcu()) to wait until in-flight fprobe handlers complete before freeing the fprobe. However, if an fprobe handler executes while RCU is not watching (such as in the idle loop or nohz_full extended quiescent states), standard RCU does not track preemption-disabled sections. Consequently, synchronize_rcu() does not wait for those executions, which can lead to a use-after-free if the fprobe is freed immediately after unregistration. Ensure handlers exit early when !rcu_is_watching(). Furthermore, fprobe_fgraph_entry() and fprobe_ftrace_entry() previously used guard(rcu)() and rcu_read_lock(), which invoke lockdep on every hit under CONFIG_PROVE_LOCKING. This adds overhead and can cause lockdep recursion if probed functions interact with lockdep. Since rhltable_lookup() and rhl_for_each_entry_rcu() use rcu_dereference_all_check() (which checks rcu_read_lock_any_held()), holding preemption disabled via rcu_read_lock_sched_notrace() is fully valid and sufficient so long as rcu_is_watching() is true. Define and use guard(rcu_sched_notrace)() across fprobe_ftrace_entry(), fprobe_fgraph_entry(), and fprobe_return(). This eliminates fast-path rcu_read_lock() and lockdep overhead while guaranteeing safe grace period synchronization.

Affected packages

Ecosystem Package Introduced Fixed