CVE-2026-23294
Received Received - Intake
Use-After-Free Race in Linux Kernel BPF devmap on PREEMPT_RT

Publication date: 2026-03-25

Last updated on: 2026-04-02

Assigner: kernel.org

Description
In the Linux kernel, the following vulnerability has been resolved: bpf: Fix race in devmap on PREEMPT_RT On PREEMPT_RT kernels, the per-CPU xdp_dev_bulk_queue (bq) can be accessed concurrently by multiple preemptible tasks on the same CPU. 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, local_bh_disable() only calls migrate_disable() (when PREEMPT_RT_NEEDS_BH_LOCK is not set) 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. This leads to several races: 1. Double-free / use-after-free on bq->q[]: bq_xmit_all() snapshots cnt = bq->count, then iterates bq->q[0..cnt-1] to transmit frames. If preempted after the snapshot, a second task can 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. 2. bq->count and bq->q[] corruption: concurrent bq_enqueue() modifying bq->count and bq->q[] while bq_xmit_all() is reading them. 3. dev_rx/xdp_prog teardown race: __dev_flush() clears bq->dev_rx and bq->xdp_prog after bq_xmit_all(). If preempted between bq_xmit_all() return and bq->dev_rx = NULL, a preempting bq_enqueue() sees dev_rx still set (non-NULL), skips adding bq to the flush_list, and enqueues a frame. When __dev_flush() resumes, it clears dev_rx and removes bq from the flush_list, orphaning the newly enqueued frame. 4. __list_del_clearprev() on flush_node: similar to the cpumap race, both tasks can call __list_del_clearprev() on the same flush_node, the second dereferences the prev pointer already set to NULL. The race between task A (__dev_flush -> bq_xmit_all) and task B (bq_enqueue -> bq_xmit_all) on the same CPU: Task A (xdp_do_flush) Task B (ndo_xdp_xmit redirect) ---------------------- -------------------------------- __dev_flush(flush_list) bq_xmit_all(bq) cnt = bq->count /* e.g. 16 */ /* start iterating bq->q[] */ <-- CFS preempts Task A --> bq_enqueue(dev, xdpf) bq->count == DEV_MAP_BULK_SIZE bq_xmit_all(bq, 0) cnt = bq->count /* same 16! */ ndo_xdp_xmit(bq->q[]) /* frames freed by driver */ bq->count = 0 <-- Task A resumes --> ndo_xdp_xmit(bq->q[]) /* use-after-free: frames already freed! */ Fix this by adding a local_lock_t to xdp_dev_bulk_queue and acquiring it in bq_enqueue() and __dev_flush(). These paths already run under local_bh_disable(), so use local_lock_nested_bh() which on non-RT is a pure annotation with no overhead, and on PREEMPT_RT provides a per-CPU sleeping lock that serializes access to the bq.
CVSS Scores
EPSS Scores
Probability:
Percentile:
Meta Information
Published
2026-03-25
Last Modified
2026-04-02
Generated
2026-05-07
AI Q&A
2026-03-25
EPSS Evaluated
2026-05-05
NVD
EUVD
Affected Vendors & Products
Showing 1 associated CPE
Vendor Product Version / Range
linux linux_kernel *
Helpful Resources
Exploitability
CWE
CWE Icon
KEV
KEV Icon
CWE ID Description
CWE-UNKNOWN
Attack-Flow Graph
AI Powered Q&A
Can you explain this vulnerability to me?

This vulnerability exists in the Linux kernel on PREEMPT_RT (real-time) kernels where the per-CPU xdp_dev_bulk_queue (bq) can be accessed concurrently by multiple preemptible tasks on the same CPU. The original code assumed that certain functions (bq_enqueue() and __dev_flush()) would run atomically on the same CPU, but on PREEMPT_RT kernels, preemption is not properly disabled, allowing concurrent access.

This concurrency leads to race conditions such as double-free or use-after-free of frames, corruption of queue counts and pointers, and orphaned frames due to improper synchronization. Specifically, one task can be preempted while transmitting frames, allowing another task to transmit and free the same frames, causing the first task to operate on freed memory.

The fix involves adding a local_lock_t to the xdp_dev_bulk_queue and acquiring this lock in both bq_enqueue() and __dev_flush() to serialize access and prevent these race conditions.


How can this vulnerability impact me? :

This vulnerability can lead to serious stability and security issues in systems running PREEMPT_RT Linux kernels. The race conditions may cause use-after-free and double-free bugs, which can result in kernel crashes, memory corruption, or unpredictable behavior.

Such memory corruption issues could potentially be exploited to execute arbitrary code in kernel context or cause denial of service, impacting system reliability and security.


What immediate steps should I take to mitigate this vulnerability?

The vulnerability is caused by a race condition in the Linux kernel's bpf devmap on PREEMPT_RT kernels. The fix involves adding a local_lock_t to xdp_dev_bulk_queue and acquiring it in bq_enqueue() and __dev_flush() to serialize access and prevent concurrent operations on the same per-CPU queue.

To mitigate this vulnerability immediately, you should update your Linux kernel to a version that includes this fix. This ensures that the local_lock_nested_bh() locking mechanism is in place, preventing the race conditions described.


Ask Our AI Assistant
Need more information? Ask your question to get an AI reply (Powered by our expertise)
0/70
EPSS Chart