CVE-2026-78118
Race condition on kernel wait queues: unlocked z_waitq_head() read in the timer expiration handler can yield a stale or sentinel thread pointer on SMP
Description
The kernel helper z_waitq_head() (kernel/include/wait_q.h) reads the head of a thread wait queue, but on SMP systems it was called from several places without holding the scheduler spinlock _sched_spinlock that serializes wait-queue mutation. The consequential call site is z_timer_expiration_handler() in kernel/timer.c, which held only the timer subsystem lock timer_lock while reading timer->wait_q and then unpending, setting the return value of, and readying the thread it obtained. halt_thread() in kernel/sched.c removes an aborted thread from its wait queue while holding only _sched_spinlock, so the two paths are not mutually exclusive. When the last waiter is removed on another CPU inside that window, sys_dlist_peek_head() can return the list sentinel — a pointer into the k_timer object itself — typed as a struct k_thread * (with CONFIG_WAITQ_SCALABLE, rb_get_min() can return an arbitrary node of a tree being restructured), or it can return a pointer to a thread that has already been unpended and, for dynamically allocated threads, freed. The handler then calls unpend_thread_no_timeout(), which performs a sys_dlist_remove() through pointers read from that object, and arch_thread_return_value_set(), which writes unconditionally through the pointer. The result is out-of-bounds and use-after-free writes in supervisor context, plus scheduler state corruption; a milder outcome is a thread that has re-pended elsewhere being woken with a success return value from an unrelated blocking call. All of the primitives needed to drive the interleaving — k_timer_start(), k_timer_status_sync(), k_thread_create() and k_thread_abort() — are system calls, so with CONFIG_USERSPACE enabled an unprivileged user-mode thread can attempt the race against kernel-owned data. Exploitation requires a multi-CPU build (CONFIG_MP_MAX_NUM_CPUS greater than one; the affected region is a no-op on uniprocessor targets), local code execution, and winning a narrow timing window, so the practical outcome is most often a kernel crash rather than controlled corruption. The fix splits the helper into z_waitq_head_locked() for callers that already hold the scheduler spinlock and a z_waitq_head() that acquires it, and brings the timer expiration handler's head read, unpend and ready under a single LOCK_SCHED_SPINLOCK region.
INFO
Published Date :
Oct. 21, 2026, 7:17 p.m.
Last Modified :
Oct. 21, 2026, 7:17 p.m.
Remotely Exploit :
No
Source :
[email protected]
Affected Products
The following products are affected by CVE-2026-78118
vulnerability.
Even if cvefeed.io is aware of the exact versions of the
products
that
are
affected, the information is not represented in the table below.
CVSS Scores
| Score | Version | Severity | Vector | Exploitability Score | Impact Score | Source |
|---|---|---|---|---|---|---|
| CVSS 3.1 | HIGH | e2e69745-5e70-4e92-8431-deb5529a81ad | ||||
| CVSS 3.1 | HIGH | MITRE-CVE | ||||
| CVSS 3.1 | HIGH | [email protected] |
Solution
- Acquire scheduler spinlock for wait queue operations.
- Update timer expiration handler for spinlock protection.
- Split wait queue helper for locked and unlocked access.
- Apply vendor-provided patches for kernel wait queues.
References to Advisories, Solutions, and Tools
Here, you will find a curated list of external links that provide in-depth
information, practical solutions, and valuable tools related to
CVE-2026-78118.
| URL | Resource |
|---|---|
| https://github.com/zephyrproject-rtos/zephyr/commit/a9b21fb354e8468dd15db307c3e599dc68b7ef33 | |
| https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-gm6w-pv43-m3vf |
CWE - Common Weakness Enumeration
While CVE identifies
specific instances of vulnerabilities, CWE categorizes the common flaws or
weaknesses that can lead to vulnerabilities. CVE-2026-78118 is
associated with the following CWEs:
Common Attack Pattern Enumeration and Classification (CAPEC)
Common Attack Pattern Enumeration and Classification
(CAPEC)
stores attack patterns, which are descriptions of the common attributes and
approaches employed by adversaries to exploit the CVE-2026-78118
weaknesses.
We scan GitHub repositories to detect new proof-of-concept exploits. Following list is a collection of public exploits and proof-of-concepts, which have been published on GitHub (sorted by the most recently updated).
Results are limited to the first 15 repositories due to potential performance issues.
The following list is the news that have been mention
CVE-2026-78118 vulnerability anywhere in the article.
The following table lists the changes that have been made to the
CVE-2026-78118 vulnerability over time.
Vulnerability history details can be useful for understanding the evolution of a vulnerability, and for identifying the most recent changes that may impact the vulnerability's severity, exploitability, or other characteristics.
-
New CVE Received by [email protected]
Oct. 21, 2026
Action Type Old Value New Value Added Description The kernel helper z_waitq_head() (kernel/include/wait_q.h) reads the head of a thread wait queue, but on SMP systems it was called from several places without holding the scheduler spinlock _sched_spinlock that serializes wait-queue mutation. The consequential call site is z_timer_expiration_handler() in kernel/timer.c, which held only the timer subsystem lock timer_lock while reading timer->wait_q and then unpending, setting the return value of, and readying the thread it obtained. halt_thread() in kernel/sched.c removes an aborted thread from its wait queue while holding only _sched_spinlock, so the two paths are not mutually exclusive. When the last waiter is removed on another CPU inside that window, sys_dlist_peek_head() can return the list sentinel — a pointer into the k_timer object itself — typed as a struct k_thread * (with CONFIG_WAITQ_SCALABLE, rb_get_min() can return an arbitrary node of a tree being restructured), or it can return a pointer to a thread that has already been unpended and, for dynamically allocated threads, freed. The handler then calls unpend_thread_no_timeout(), which performs a sys_dlist_remove() through pointers read from that object, and arch_thread_return_value_set(), which writes unconditionally through the pointer. The result is out-of-bounds and use-after-free writes in supervisor context, plus scheduler state corruption; a milder outcome is a thread that has re-pended elsewhere being woken with a success return value from an unrelated blocking call. All of the primitives needed to drive the interleaving — k_timer_start(), k_timer_status_sync(), k_thread_create() and k_thread_abort() — are system calls, so with CONFIG_USERSPACE enabled an unprivileged user-mode thread can attempt the race against kernel-owned data. Exploitation requires a multi-CPU build (CONFIG_MP_MAX_NUM_CPUS greater than one; the affected region is a no-op on uniprocessor targets), local code execution, and winning a narrow timing window, so the practical outcome is most often a kernel crash rather than controlled corruption. The fix splits the helper into z_waitq_head_locked() for callers that already hold the scheduler spinlock and a z_waitq_head() that acquires it, and brings the timer expiration handler's head read, unpend and ready under a single LOCK_SCHED_SPINLOCK region. Added CVSS V3.1 AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H Added CWE CWE-362 Added Affected New affected value received. <a href="https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/78xxx/CVE-2026-78118.json">CVE-2026-78118</a> Added Reference https://github.com/zephyrproject-rtos/zephyr/commit/a9b21fb354e8468dd15db307c3e599dc68b7ef33 Added Reference https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-gm6w-pv43-m3vf