CVE-2026-23294 Overview
A race condition vulnerability has been identified in the Linux kernel's BPF devmap implementation affecting PREEMPT_RT kernels. The vulnerability exists in the per-CPU xdp_dev_bulk_queue (bq) which can be accessed concurrently by multiple preemptible tasks on the same CPU, leading to use-after-free conditions and memory corruption.
The original code assumes bq_enqueue() and __dev_flush() run atomically with respect to each other on the same CPU, relying on local_bh_disable() to prevent preemption. However, on PREEMPT_RT kernels, local_bh_disable() only calls migrate_disable() and does not disable preemption, which allows CFS scheduling to preempt a task during bq_xmit_all(), enabling another task on the same CPU to enter bq_enqueue() and operate on the same per-CPU bq concurrently.
Critical Impact
This race condition can lead to double-free, use-after-free, memory corruption, and potential kernel crashes on systems running PREEMPT_RT kernels with XDP/BPF devmap functionality enabled.
Affected Products
- Linux Kernel (PREEMPT_RT configurations)
- Systems using XDP (eXpress Data Path) with BPF devmap redirects
- Real-time Linux distributions with PREEMPT_RT patches
Discovery Timeline
- 2026-03-25 - CVE CVE-2026-23294 published to NVD
- 2026-03-25 - Last updated in NVD database
Technical Details for CVE-2026-23294
Vulnerability Analysis
This vulnerability is a classic race condition (TOCTOU - Time-of-Check Time-of-Use) that manifests specifically on PREEMPT_RT Linux kernel configurations. The root cause lies in the assumption that local_bh_disable() provides sufficient synchronization for per-CPU data structures. On standard kernels, this assumption holds true as bottom-half processing is disabled and preemption is effectively blocked. However, PREEMPT_RT kernels fundamentally change this behavior to achieve real-time scheduling guarantees.
The vulnerability produces multiple dangerous race scenarios:
Double-free / Use-after-free on bq->q[]: When bq_xmit_all() snapshots cnt = bq->count and then iterates bq->q[0..cnt-1] to transmit frames, a preemption can occur. A second task can then call bq_enqueue() -> bq_xmit_all() on the same bq, transmitting and freeing the same frames. When the first task resumes, it operates on stale pointers in bq->q[], causing use-after-free.
bq->count and bq->q[] corruption: Concurrent bq_enqueue() modifying bq->count and bq->q[] while bq_xmit_all() is reading them leads to inconsistent state.
dev_rx/xdp_prog teardown race: When __dev_flush() clears bq->dev_rx and bq->xdp_prog after bq_xmit_all(), a preemption between bq_xmit_all() return and bq->dev_rx = NULL allows a preempting bq_enqueue() to see dev_rx still set, skip adding bq to the flush_list, and enqueue a frame that becomes orphaned.
Root Cause
The fundamental issue is the behavioral difference of local_bh_disable() between standard and PREEMPT_RT kernels. On PREEMPT_RT, when PREEMPT_RT_NEEDS_BH_LOCK is not set, local_bh_disable() only calls migrate_disable() rather than disabling preemption entirely. This allows the Completely Fair Scheduler (CFS) to preempt tasks during critical sections that manipulate the per-CPU xdp_dev_bulk_queue structure.
The code incorrectly assumed that operations within local_bh_disable() / local_bh_enable() pairs would be atomic with respect to other code running on the same CPU, which is not guaranteed on PREEMPT_RT configurations.
Attack Vector
The vulnerability is triggered through normal XDP operation on PREEMPT_RT systems when:
- Task A enters __dev_flush() which calls bq_xmit_all() and snapshots the current count
- CFS scheduler preempts Task A during frame transmission iteration
- Task B begins XDP redirect operations, calling bq_enqueue() which triggers bq_xmit_all() on the same per-CPU queue
- Task B transmits and the driver frees the frames that Task A still holds references to
- Task A resumes and attempts to transmit already-freed frames, causing use-after-free
This race window exists during normal high-throughput XDP processing on real-time systems. The condition requires concurrent XDP redirect operations and specific scheduler timing, making it probabilistic but reproducible under load.
Detection Methods for CVE-2026-23294
Indicators of Compromise
- Kernel panics or oops messages referencing bq_xmit_all, bq_enqueue, or __dev_flush functions
- KASAN (Kernel Address Sanitizer) reports showing use-after-free in devmap-related code paths
- Unexpected system crashes on PREEMPT_RT systems under XDP workloads
- Memory corruption warnings in kernel logs associated with BPF or XDP subsystems
Detection Strategies
- Enable KASAN (Kernel Address Sanitizer) on development and testing systems to detect use-after-free conditions
- Monitor kernel logs for BPF/XDP-related crash reports using dmesg or centralized log aggregation
- Implement kernel live patching detection to identify when vulnerable code paths are executed
- Use kernel tracing tools like ftrace or bpftrace to monitor bq_enqueue and __dev_flush function calls for anomalous patterns
Monitoring Recommendations
- Deploy SentinelOne Singularity agents to detect kernel-level anomalies and exploitation attempts
- Configure alerting for kernel crash patterns specific to XDP/BPF subsystems on PREEMPT_RT hosts
- Monitor system stability metrics on real-time Linux deployments using XDP functionality
- Implement continuous vulnerability scanning to identify unpatched kernel versions in your environment
How to Mitigate CVE-2026-23294
Immediate Actions Required
- Update the Linux kernel to a patched version containing the fix (commits referenced below)
- If immediate patching is not possible, consider temporarily disabling XDP devmap redirect functionality on PREEMPT_RT systems
- Evaluate whether PREEMPT_RT is required for affected workloads; standard kernels are not affected by this specific race
- Prioritize patching for systems running real-time Linux configurations with active XDP/BPF network processing
Patch Information
The vulnerability has been resolved by adding a local_lock_t to xdp_dev_bulk_queue and acquiring it in bq_enqueue() and __dev_flush(). The fix uses local_lock_nested_bh() which on non-RT kernels is a pure annotation with no overhead, while on PREEMPT_RT it provides a per-CPU sleeping lock that properly serializes access to the bq structure.
Official patches are available in the kernel stable tree:
Workarounds
- Disable XDP redirect to devmap on affected PREEMPT_RT systems until patching is possible
- Switch to non-PREEMPT_RT kernel configurations if real-time guarantees are not strictly required
- Reduce XDP processing load to minimize the window for race condition exploitation
- Implement network traffic isolation to limit exposure of affected systems
# Check if system is running PREEMPT_RT kernel
uname -v | grep -i preempt
# Check current kernel version
uname -r
# Verify if XDP devmap is in use
bpftool prog list | grep -i xdp
# After updating kernel, verify patch is applied by checking kernel version
# against the fixed versions in your distribution's security advisories
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


