CVE-2026-23294 Overview
CVE-2026-23294 is a race condition in the Linux kernel's BPF devmap implementation affecting PREEMPT_RT kernels. The flaw resides in the per-CPU xdp_dev_bulk_queue (bq) structure, which can be accessed concurrently by multiple preemptible tasks on the same CPU. The original code assumed bq_enqueue() and __dev_flush() ran atomically on the same CPU under local_bh_disable(). On PREEMPT_RT, local_bh_disable() only calls migrate_disable() and does not prevent preemption, allowing CFS scheduling to interrupt bq_xmit_all() and let another task corrupt the shared queue.
Critical Impact
Local attackers with the ability to trigger XDP redirect paths on PREEMPT_RT kernels can cause double-free and use-after-free conditions in kernel memory, leading to denial of service or potential privilege escalation.
Affected Products
- Linux kernel builds with PREEMPT_RT enabled
- Kernel versions prior to commits 1872e75375c4, 6c10b019785d, and ab1a56c9d991
- Systems using BPF/XDP devmap redirection with real-time preemption
Discovery Timeline
- 2026-03-25 - CVE-2026-23294 published to NVD
- 2026-04-02 - Last updated in NVD database
Technical Details for CVE-2026-23294
Vulnerability Analysis
The vulnerability is a race condition [CWE-362] in the BPF devmap subsystem. The per-CPU xdp_dev_bulk_queue structure buffers XDP frames for bulk transmission via ndo_xdp_xmit. Under PREEMPT_RT, the existing serialization assumption breaks because local_bh_disable() does not disable preemption when PREEMPT_RT_NEEDS_BH_LOCK is not set.
Four distinct races result from this design gap. First, bq_xmit_all() snapshots cnt = bq->count and iterates bq->q[0..cnt-1]. A preempting task entering bq_enqueue() can trigger a second bq_xmit_all() on the same queue, transmitting and freeing the same frames. When the original task resumes, it dereferences stale pointers, producing use-after-free.
Second, concurrent bq_enqueue() calls mutate bq->count and bq->q[] while another path reads them, corrupting queue state. Third, __dev_flush() clears bq->dev_rx and bq->xdp_prog after bq_xmit_all() returns. A preempting bq_enqueue() observing non-NULL dev_rx skips re-adding bq to the flush list, orphaning the enqueued frame. Fourth, both tasks may call __list_del_clearprev() on the same flush_node, with the second dereferencing a NULL prev pointer.
Root Cause
The root cause is an incorrect synchronization assumption. The devmap code relied on local_bh_disable() to provide atomicity between bq_enqueue() and __dev_flush() on the same CPU. On PREEMPT_RT, this primitive only disables migration, not preemption, allowing CFS to schedule another task on the same CPU mid-operation.
Attack Vector
Exploitation requires local access and the ability to invoke XDP redirect paths, typically through network namespace manipulation or BPF program loading. An attacker triggers concurrent ndo_xdp_xmit operations and xdp_do_flush calls on the same CPU to force the race window. Successful exploitation corrupts kernel memory through use-after-free on freed xdp_frame pointers.
The vulnerability manifests in the devmap bulk queue logic. See the upstream commits referenced below for the technical fix that introduces a local_lock_t guarded by local_lock_nested_bh().
Detection Methods for CVE-2026-23294
Indicators of Compromise
- Kernel oops, panic, or KASAN reports referencing bq_xmit_all, bq_enqueue, __dev_flush, or __list_del_clearprev
- Use-after-free or double-free splats involving xdp_frame structures in kernel logs
- Unexpected XDP frame loss or duplication on PREEMPT_RT systems running BPF redirect programs
Detection Strategies
- Enable KASAN and lockdep on test systems to surface concurrent access to per-CPU devmap structures
- Audit loaded BPF programs that use bpf_redirect_map against devmap entries on real-time kernels
- Monitor dmesg and journal logs for kernel warnings originating in kernel/bpf/devmap.c
Monitoring Recommendations
- Collect kernel ring buffer telemetry centrally and alert on BPF subsystem stack traces
- Track BPF program load events via audit subsystem to identify unprivileged users invoking XDP redirect logic
- Inventory hosts running PREEMPT_RT kernels and prioritize them for patch validation
How to Mitigate CVE-2026-23294
Immediate Actions Required
- Apply the upstream stable kernel updates containing commits 1872e75375c4, 6c10b019785d, and ab1a56c9d991
- Restrict CAP_BPF and CAP_NET_ADMIN to trusted administrators to limit who can load XDP redirect programs
- Validate that distribution-provided real-time kernels include the devmap local_lock_nested_bh() fix
Patch Information
The fix adds a local_lock_t to xdp_dev_bulk_queue and acquires it in both bq_enqueue() and __dev_flush() using local_lock_nested_bh(). On non-RT kernels this is a compile-time annotation with no runtime cost. On PREEMPT_RT, it provides a per-CPU sleeping lock that serializes access. Refer to the kernel commit 1872e75375c4, kernel commit 6c10b019785d, and kernel commit ab1a56c9d991 for implementation details.
Workarounds
- Disable PREEMPT_RT and run a standard preemption kernel if real-time scheduling is not required
- Unload or remove BPF programs that perform XDP redirects through devmap until the patch is deployed
- Use seccomp or LSM policies to block unprivileged BPF program loading on exposed hosts
# Verify running kernel and PREEMPT_RT status
uname -a
zcat /proc/config.gz | grep -E 'CONFIG_PREEMPT_RT|CONFIG_BPF_SYSCALL'
# Restrict unprivileged BPF
sysctl -w kernel.unprivileged_bpf_disabled=1
echo 'kernel.unprivileged_bpf_disabled=1' >> /etc/sysctl.d/90-bpf-hardening.conf
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

