CVE-2026-19595 Overview
CVE-2026-19595 is an out-of-bounds write vulnerability [CWE-787] in the Zephyr RTOS user-mode syscall verifier z_vrfy_rtio_cqe_get_mempool_buffer() located in subsys/rtio/rtio_syscalls.c. The verifier validates its buff and buff_len output parameters using K_SYSCALL_MEMORY_READ() instead of K_SYSCALL_MEMORY_WRITE(). An unprivileged user-mode thread with access to an RTIO context can invoke the syscall with pointers to memory it may read but not write. The kernel then performs supervisor-mode stores through those addresses, either bypassing memory domain write protection or triggering a fatal kernel fault.
Critical Impact
An unprivileged user thread can force kernel-mode writes into memory marked read-only for its memory domain, or reliably halt the device by targeting .text or .rodata in flash.
Affected Products
- Zephyr RTOS builds with CONFIG_USERSPACE enabled
- Zephyr RTOS builds with CONFIG_RTIO_SYS_MEM_BLOCKS enabled (RTIO contexts created via RTIO_DEFINE_WITH_MEMPOOL)
- Architectures using RISC-V PMP or ARM MPU memory protection validators
Discovery Timeline
- 2026-10-19 - CVE-2026-19595 published to NVD
- 2026-10-20 - Last updated in NVD database
Technical Details for CVE-2026-19595
Vulnerability Analysis
The z_vrfy_rtio_cqe_get_mempool_buffer() verifier treats two output parameters as if they were inputs. Both buff and buff_len are pure out-parameters: the implementation z_impl_rtio_cqe_get_mempool_buffer() stores the mempool buffer address and its length through them. By checking them with K_SYSCALL_MEMORY_READ(), the verifier only confirms the calling thread can read those addresses.
Architecture validators enforce the read/write distinction. arch_buffer_validate() on RISC-V PMP accepts the global __rom_region and __rodata_region for reads only. ARM MPU validators similarly accept P_RO_U_RO and P_RW_U_RO regions for reads only. A read-validated pointer is therefore not necessarily writable by the calling thread, yet the kernel proceeds to write through it.
Root Cause
The root cause is incorrect use of a syscall memory-access validator macro. The verifier used K_SYSCALL_MEMORY_READ() on parameters that the implementation later writes. This mismatch between declared and actual access intent allows read-only memory regions to pass validation and reach a supervisor-mode store.
Attack Vector
An unprivileged user-mode thread that has been granted access to an RTIO context through rtio_access_grant() invokes rtio_cqe_get_mempool_buffer(). It supplies buff and buff_len pointing at memory it may read but not write. It also supplies a completion-queue entry whose flags field it fully controls, with RTIO_CQE_FLAG_MEMPOOL_BUFFER set in flags[7:0], and flags[19:8] and flags[31:20] providing the block index and count.
Two outcomes follow. If the target lies in a K_MEM_PARTITION_P_RW_U_RO partition, the kernel store succeeds and deposits partly attacker-chosen values into memory the memory domain marked read-only for that thread. If the target lies in globally readable but unwritable memory such as .text or .rodata in flash, the store faults in kernel mode. The fault reaches z_fatal_error() and the default k_sys_fatal_error_handler() halts or reboots the device.
The read-permission check bounds the damage: the address must still be readable by the calling thread, so kernel-private memory cannot be targeted and no confidential data is disclosed.
{
K_OOPS(K_SYSCALL_OBJ(r, K_OBJ_RTIO));
K_OOPS(K_SYSCALL_MEMORY_READ(cqe, sizeof(struct rtio_cqe)));
- K_OOPS(K_SYSCALL_MEMORY_READ(buff, sizeof(void *)));
- K_OOPS(K_SYSCALL_MEMORY_READ(buff_len, sizeof(uint32_t)));
+ K_OOPS(K_SYSCALL_MEMORY_WRITE(buff, sizeof(void *)));
+ K_OOPS(K_SYSCALL_MEMORY_WRITE(buff_len, sizeof(uint32_t)));
return z_impl_rtio_cqe_get_mempool_buffer(r, cqe, buff, buff_len);
}
#include <zephyr/syscalls/rtio_cqe_get_mempool_buffer_mrsh.c>
Source: Zephyr commit bea9340. The patch replaces both read validators with K_SYSCALL_MEMORY_WRITE(), so a thread lacking write permission is terminated by K_OOPS before the implementation runs. The cqe argument correctly remains read-validated.
Detection Methods for CVE-2026-19595
Indicators of Compromise
- Unexpected invocations of k_sys_fatal_error_handler() from kernel-mode faults originating in z_impl_rtio_cqe_get_mempool_buffer().
- Device halts or reboots correlated with user-mode threads holding RTIO access grants.
- Unexplained modification of data in memory partitions declared K_MEM_PARTITION_P_RW_U_RO.
Detection Strategies
- Audit Zephyr builds for the combination of CONFIG_USERSPACE=y and CONFIG_RTIO_SYS_MEM_BLOCKS=y, which is the precondition for exploitation.
- Review all callers of rtio_access_grant() to enumerate user-mode threads capable of reaching the vulnerable syscall.
- Inspect kernel panic logs for faults with program counters inside the RTIO mempool completion path.
Monitoring Recommendations
- Instrument fatal error paths to capture faulting thread identity, address, and syscall number for post-incident analysis.
- Track firmware image hashes across the fleet to confirm all devices run patched Zephyr releases.
- Monitor device uptime and reboot patterns on fielded embedded targets for denial-of-service symptoms.
How to Mitigate CVE-2026-19595
Immediate Actions Required
- Apply the upstream Zephyr patch that replaces K_SYSCALL_MEMORY_READ() with K_SYSCALL_MEMORY_WRITE() for the buff and buff_len parameters in z_vrfy_rtio_cqe_get_mempool_buffer().
- Rebuild and reflash all affected device firmware images.
- Review and minimize the set of user-mode threads granted RTIO access via rtio_access_grant().
Patch Information
The fix is published in Zephyr commit bea93400138362691403b7f81de1e9048681547d and documented in the GitHub Security Advisory GHSA-7337-mc44-5wjm. Both output parameters are now validated as writable, causing K_OOPS to terminate any calling thread lacking write permission before the implementation runs.
Workarounds
- If patching is not immediately possible, disable CONFIG_RTIO_SYS_MEM_BLOCKS to make the vulnerable code path return -ENOTSUP without performing writes.
- Revoke RTIO context access from untrusted user-mode threads where mempool-backed RTIO is not required.
- Avoid declaring sensitive data in K_MEM_PARTITION_P_RW_U_RO partitions reachable from threads that invoke RTIO syscalls.
# Disable the vulnerable configuration path in prj.conf
CONFIG_RTIO_SYS_MEM_BLOCKS=n
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

