CVE Catalog

CVE-2026-12631

MediumCVSS 6.5
Published: Updated: Translated: NVD NIST

Exploitation Probability (EPSS)

Low risk
0.16%

5th percentile - higher than 5% of all known CVEs

Summary

A vulnerability in the Zephyr kernel affects the k_thread_join() and k_thread_abort() system calls. An error in access validation (thread_obj_validate()) allows an unprivileged user thread to invoke these functions on a thread object it does not own. Instead of terminating the offending thread, execution reaches undefined behavior, potentially causing a kernel crash (on Clang) or an access-control bypass (on GCC).

Risk Assessment

The risk includes a local denial-of-service (deterministic system crash by an unprivileged thread) and a potential access-control bypass, which could allow manipulation of unauthorized threads. In environments with CONFIG_USERSPACE, the vulnerability enables escape from the userspace sandbox.

Recommendation

Apply the fix provided by the Zephyr project immediately, which changes the verification expression to ret == 0. Also review configurations with CONFIG_USERSPACE enabled and consider restricting access to system calls until the update is applied.

Other vulnerabilities in Zephyr kernel

See all
Original NVD description (English source)

The Zephyr kernel validates the k_thread_join() and k_thread_abort() system calls (declared __syscall in include/zephyr/kernel.h) through thread_obj_validate() in kernel/thread.c. Its default switch branch is the access-denied path, taken when k_object_validate() returns -EPERM (the calling user thread was never granted access to the target thread object) or -EBADF (the supplied pointer is not a registered kernel object of the right type). That branch invoked K_OOPS(K_SYSCALL_VERIFY_MSG(ret, "access denied")), but K_SYSCALL_VERIFY_MSG treats a true expression as success; the non-zero error code ret therefore read as "verified OK", the kernel oops was never raised, and control fell through to CODE_UNREACHABLE. Because k_thread_join() and k_thread_abort() are system calls, an unprivileged user-mode thread (under CONFIG_USERSPACE) can reach this denial path directly by calling either syscall on a thread object it does not own. Instead of the offending thread being cleanly terminated, execution reaches __builtin_unreachable() while running in supervisor mode inside the syscall handler. On Clang builds CODE_UNREACHABLE emits an illegal-instruction trap, so a user thread can deterministically crash the kernel — a locally triggerable denial of service that escapes the userspace sandbox. On GCC builds the path is undefined behavior: the compiler may drop the return-value handling for thread_obj_validate(), so it can return an undefined bool; if that is false, the caller proceeds into the real k_thread_join()/k_thread_abort() implementation for a thread the user was never authorized to access, an access-control bypass. The fix changes the verification expression to ret == 0, so a denied (non-zero) result now correctly raises K_OOPS and terminates the offending caller.

Vulnerability data from NVD (NIST) · CISA KEV · EPSS