CVE-2026-12366: Use-after-free freeing an armed dynamically-allocated k_timer in Zephyr userspace object disposal
Zephyr's dynamic kernel-object disposal path unrefcheck() in kernel/userspace/userspace.c frees an object's storage (kfree(dyn->data)) once its reference count reaches zero, after running a per-object-type cleanup. The cleanup switch handled only KOBJMSGQ and KOBJSTACK; there was no KOBJTIMER case. A dynamically-allocated, initialized, and armed ktimer keeps its embedded struct timeout dnode linked in the global timeout queue (timeoutq), so freeing the timer storage without cancelling the timeout leaves a dangling node in that queue.
When the timer next expires, the timeout machinery walks timeoutq and invokes ztimerexpirationhandler() on the freed node, dereferencing and writing freed (and reusable) kernel heap in kernel/ISR context. This is a deterministic use-after-free that does not depend on SMP: the queued node is simply never unlinked at free time.
The disposal is reachable from an unprivileged user thread under CONFIGUSERSPACE + CONFIGDYNAMICOBJECTS: a thread that holds the last permission on such a timer drops it via the kobjectrelease() syscall (or by exiting, through kthreadpermsallclear()), and can arm the timer itself via the ktimerstart() syscall. The free and the expiration handler run at kernel privilege while the actor is a user thread, so the bug is a sandbox-escape memory-corruption primitive usable for privilege escalation. The fix adds ktimercleanup() (cancel the timeout and wait for any in-flight handler) and calls it for KOBJTIMER before freeing.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
In Zephyr’s dynamic kernel-object disposal path, extend the cleanup switch to include the K_OBJ_TIMER case and invoke k_timer_cleanup() (cancel the timeout and wait for any in-flight handler) before freeing the dynamically allocated k_timer storage (so the embedded _timeout node is unlinked/canceled).
Zephyr kernel userspace dynamic object disposal Cleanup switch / per-object-type cleanup = Add K_OBJ_TIMER handling (call k_timer_cleanup() before freeing timer storage) - Operational
After applying the fix, rebuild/redeploy so that dynamically allocated, armed k_timer objects are cancelled and waited for via k_timer_cleanup() during userspace dynamic object disposal (before k_free(dyn->data)).
Event History
Frequently Asked Questions
What is the severity of CVE-2026-12366?
The severity of CVE-2026-12366 is high, rated at 8.8.
What type of vulnerability is CVE-2026-12366?
CVE-2026-12366 is a Use-after-free vulnerability affecting the Zephyr Project.
How do I fix CVE-2026-12366?
To fix CVE-2026-12366, update to a patched version of the Zephyr Project that addresses the cleanup handling for k_timer objects.
What software is affected by CVE-2026-12366?
CVE-2026-12366 affects the Zephyr Project, specifically within its userspace object disposal mechanism.
What is the risk associated with CVE-2026-12366?
The risk associated with CVE-2026-12366 is rated at 72, indicating significant potential for exploitation.