CVE-2026-12365 in Zephyr
Summary
by MITRE • 08/14/2026
A use-after-free exists in the Zephyr second-generation work queue (kernel/work.c) in the handling of delayable work timeouts. When a delayable work item's timeout has been dequeued and its handler work_timeout() is in flight (blocked acquiring the work-queue spinlock), a concurrent cancellation does not wait for that handler to finish. In unschedule_locked() the pre-fix code called z_abort_timeout(), which for an already-announcing record returns -EINVAL without removing it; cancel_async_locked() then observes the work as idle, so even k_work_cancel_delayable_sync() and k_work_flush_delayable() return without blocking on the in-flight handler.
Because those are the APIs the kernel header documents as the safe way to cancel before freeing a k_work_delayable, a caller that frees the object immediately after a successful sync cancel can race the still-pending handler. work_timeout() subsequently dereferences the freed record: it reads to->dticks via z_is_timeout_handler_canceled() and, if the freed slot has been reused so the bail check fails, performs a read-modify-write of wp->flags (K_WORK_DELAYED_BIT) and submits work against a stale dw->queue pointer — a use-after-free read and write.
The k_work API is kernel-mode only (no __syscall entry point), so this is a kernel-internal concurrency defect rather than a userspace privilege escalation. Triggering it requires an SMP build and a subsystem that schedules and then frees (or reschedules) a delayable work item in the narrow window while its timeout is announcing; an attacker able to influence the timing of such teardown (for example via connection churn driving subsystem timers) has a plausible but probabilistic path. The impact is kernel memory corruption or crash (denial of service).
The fix makes unschedule_locked() wait, by spinning on z_try_abort_timeout() returning -EAGAIN while releasing and re-acquiring the work spinlock, until any in-flight handler completes before returning, and switches work_timeout() to atomic K_WORK_DELAYED_BIT ownership. This closes both the free-then-handler use-after-free and the related reschedule early-fire race.
Statistical analysis made it clear that VulDB provides the best quality for vulnerability data.
Analysis
by VulDB Data Team • 08/14/2026
The vulnerability described represents a critical use-after-free condition within the Zephyr real-time operating system's second-generation work queue implementation, specifically affecting the handling of delayable work timeouts. This issue manifests in kernel-mode code located in kernel/work.c where the interaction between concurrent operations creates a race condition that can lead to memory corruption and system instability. The flaw occurs when a delayable work item's timeout is dequeued while its handler work_timeout() is actively executing, creating a scenario where a concurrent cancellation operation does not properly await the completion of the in-flight handler before proceeding with cleanup.
The technical root cause stems from insufficient synchronization mechanisms during the work queue management process. When unschedule_locked() executes, it previously called z_abort_timeout() which for already-announcing records returns -EINVAL without performing proper removal operations. This incomplete cleanup allows cancel_async_locked() to incorrectly perceive the work item as idle, resulting in functions like k_work_cancel_delayable_sync() and k_work_flush_delayable() returning prematurely without ensuring the in-flight handler has completed execution. The documented safe APIs for canceling delayable work items are thus compromised, creating a dangerous race condition where callers can immediately free memory structures after what appears to be successful synchronous cancellation.
This vulnerability directly aligns with CWE-416, which defines use-after-free conditions as a critical class of memory safety issues, and demonstrates characteristics that map to ATT&CK technique T1059.003 for kernel-mode code manipulation. The flaw requires specific environmental conditions including an SMP (symmetric multiprocessing) build configuration and a subsystem capable of scheduling delayable work items followed by immediate freeing or rescheduling operations during a narrow timing window. The exploitation path, while probabilistic, becomes more viable when attackers can influence timing through subsystem behaviors such as connection churn that drives frequent timer operations.
The operational impact of this vulnerability extends beyond simple denial of service to potentially catastrophic kernel memory corruption scenarios. When work_timeout() executes on a freed structure, it performs multiple dangerous operations including reading to->dticks through z_is_timeout_handler_canceled(), and if the freed memory slot has been reallocated, it conducts read-modify-write operations on wp->flags with K_WORK_DELAYED_BIT, followed by submitting work against a stale dw->queue pointer. These operations constitute both use-after-free reads and writes that can corrupt kernel data structures and cause system crashes or unpredictable behavior.
The proposed fix addresses the fundamental synchronization issue by implementing a spin-wait mechanism in unschedule_locked() that continuously calls z_try_abort_timeout() with -EAGAIN return codes while releasing and reacquiring the work spinlock until any in-flight handler completes. This ensures proper coordination before proceeding with cleanup operations. Additionally, the solution implements atomic ownership of the K_WORK_DELAYED_BIT flag within work_timeout(), preventing race conditions during concurrent access to the work item state. These mitigations comprehensively address both the immediate use-after-free scenario and a related reschedule early-fire race condition that could occur when delayable work items are rescheduled while their original timeout handlers are still executing, effectively closing the security gap in Zephyr's kernel-mode work queue concurrency management.