{"id":"CVE-2026-19595","kind":"vulnerability","aliases":["CVE-2026-19595"],"related":[],"title":"Zephyr RTIO: syscall checks read access but writes output pointers","description":"The user-mode syscall verifier z_vrfy_rtio_cqe_get_mempool_buffer() in subsys/rtio/rtio_syscalls.c validated its two output parameters, buff and buff_len, with K_SYSCALL_MEMORY_READ() rather than K_SYSCALL_MEMORY_WRITE(). Both are pure out-parameters: z_impl_rtio_cqe_get_mempool_buffer() stores the mempool buffer address and its length through them. The distinction is enforced by every architecture validator — arch_buffer_validate() on RISC-V PMP explicitly accepts the global __rom_region/__rodata_region for reads only, and the ARM MPU validators accept P_RO_U_RO and P_RW_U_RO regions for reads only — so a read-validated pointer is not necessarily writable by the calling thread.\n\nAn unprivileged user-mode thread that has been granted access to an RTIO context (rtio_access_grant()) can invoke the rtio_cqe_get_mempool_buffer() syscall with buff/buff_len pointing at memory it may read but not write, and with a completion-queue entry whose flags field it fully controls (only RTIO_CQE_FLAG_MEMPOOL_BUFFER in flags[7:0] is required; flags[19:8] and flags[31:20] supply the block index and count). The kernel then performs a pointer-sized and a 4-byte store through those addresses while running in supervisor mode. Reaching the store requires CONFIG_USERSPACE together with CONFIG_RTIO_SYS_MEM_BLOCKS, the configuration behind RTIO_DEFINE_WITH_MEMPOOL; without the latter the implementation returns -ENOTSUP and writes nothing.\n\nTwo outcomes follow. If the target lies in a memory-domain partition declared K_MEM_PARTITION_P_RW_U_RO (privileged read-write, user read-only), the kernel-mode store succeeds and deposits partly attacker-chosen values into memory the memory domain had marked read-only for that thread, bypassing the partition's write protection. If the target lies in globally readable but unwritable memory such as .text/.rodata in flash, the store faults in kernel mode; the fault is delivered to z_fatal_error() and the default k_sys_fatal_error_handler() halts or reboots the device, giving an unprivileged thread a reliable full denial of service.\n\nThe read-permission check does bound 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. The fix replaces both checks 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.","summary":"A thread with RTIO access can pass pointers it may only read, and the kernel writes through them in supervisor mode. That can overwrite read-only memory the thread's memory domain protects, or fault the kernel into a fatal error and halt or reboot the device.","severity":"medium","cvss":6.1,"epss":null,"exploited":false,"exploited_at":null,"products":[],"ecosystems":[],"tags":["embedded","rtio","rtos","runtime","zephyr"],"not_affected_if":["no-rtio-mempool","no-user-threads","no-usespace"],"how_to_check":"- Check whether the build enables both `CONFIG_USERSPACE` and `CONFIG_RTIO_SYS_MEM_BLOCKS`, for example with `grep -E 'CONFIG_(USERSPACE|RTIO_SYS_MEM_BLOCKS)=y' prj.conf` or the generated `.config`\n- Check the Zephyr version in the tree with `git -C zephyr describe --tags` and compare it against the fixed release named in the advisory (unknown in the sources)","fix":"- Upgrade Zephyr to a release that includes the fix replacing `K_SYSCALL_MEMORY_READ()` with `K_SYSCALL_MEMORY_WRITE()` for `buff` and `buff_len` in `z_vrfy_rtio_cqe_get_mempool_buffer()` (fixed version unknown in the sources)\n- Until patched, avoid granting user-mode threads access to RTIO contexts with `rtio_access_grant()` where the feature is in use","status":"open","published_at":"2026-10-19T23:17:36+00:00","first_seen_at":"2026-10-23T21:57:19+00:00","triaged_at":"2026-10-25T04:04:15+00:00","updated_at":"2026-10-25T04:04:15+00:00","category":"runtime","confidence":0.8,"triage":{"at":"2026-10-25T04:04:15Z","model":"claude-haiku-5-5","output":{"fix":"- Upgrade Zephyr to a release that includes the fix replacing `K_SYSCALL_MEMORY_READ()` with `K_SYSCALL_MEMORY_WRITE()` for `buff` and `buff_len` in `z_vrfy_rtio_cqe_get_mempool_buffer()` (fixed version unknown in the sources)\n- Until patched, avoid granting user-mode threads access to RTIO contexts with `rtio_access_grant()` where the feature is in use","reach":"local","title":"Zephyr RTIO: syscall checks read access but writes output pointers","impact":"medium","summary":"A thread with RTIO access can pass pointers it may only read, and the kernel writes through them in supervisor mode. That can overwrite read-only memory the thread's memory domain protects, or fault the kernel into a fatal error and halt or reboot the device.","category":"runtime","nicknames":[],"who_cares":["zephyr","embedded","rtos","rtio"],"confidence":0.8,"needs_auth":"yes","worst_case":"Kernel writes to read-only memory or triggers fatal denial of service","analyst_note":"","how_to_check":"- Check whether the build enables both `CONFIG_USERSPACE` and `CONFIG_RTIO_SYS_MEM_BLOCKS`, for example with `grep -E 'CONFIG_(USERSPACE|RTIO_SYS_MEM_BLOCKS)=y' prj.conf` or the generated `.config`\n- Check the Zephyr version in the tree with `git -C zephyr describe --tags` and compare it against the fixed release named in the advisory (unknown in the sources)","needs_analyst":false,"not_affected_if":["no-usespace","no-rtio-mempool","no-user-threads"],"who_is_affected":"Only Zephyr builds with user mode (CONFIG_USERSPACE) and the RTIO system memory block pool (CONFIG_RTIO_SYS_MEM_BLOCKS) enabled are exposed. The attacker must be an unprivileged user-mode thread that has been granted an RTIO context, so the risk sits inside a device's own software rather than from the network. Builds without user mode, or without the mempool configuration, can skip it.","user_interaction":"no","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000824,"input_tokens":4185,"output_tokens":811,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-19595':13A,16A '-2026':12A,15A '0':246C '19':250C '20':255C '31':254C '4':272C '7':245C '8':251C 'accept':145C,158C 'access':6A,26B,196C,202C 'address':122C,277C,436C 'arch':136C 'architectur':134C 'argument':486C 'arm':155C 'attack':352C 'attacker-chosen':351C 'behind':298C 'block':258C,295C 'bound':432C 'buff':90C,92C 'buff/buff_len':214C 'buffer':82C,117C,121C,137C,211C,242C 'bypass':368C 'byte':273C 'call':184C,443C 'cannot':450C 'check':4A,430C,463C 'chosen':353C 'complet':228C 'completion-queu':227C 'confidenti':455C 'config':287C,291C 'configur':297C 'context':200C 'control':236C 'correct':487C 'count':261C 'cqe':79C,114C,208C,239C,485C 'cve':11A,14A 'damag':434C 'data':456C 'declar':326C 'default':405C 'defin':300C 'deliv':398C 'denial':423C 'deposit':349C 'devic':69B,415C 'disclos':458C 'distinct':129C 'domain':54B,324C,359C 'embed':17B 'enforc':131C 'enotsup':309C 'entri':230C 'error':63B,402C,409C 'everi':133C 'explicit':144C 'fatal':62B,401C,408C 'fault':57B,391C,396C 'field':233C 'fix':460C 'flag':232C,240C,244C,249C,253C 'flash':388C 'follow':315C 'full':422C 'fulli':235C 'get':80C,115C,209C 'give':416C 'global':147C,379C 'grant':195C,203C 'halt':65B,411C 'handler':410C 'impl':112C 'implement':307C,482C 'index':259C 'invok':205C 'k':95C,101C,327C,406C,465C,478C 'kernel':36B,59B,263C,344C,393C,447C 'kernel-mod':343C 'kernel-priv':446C 'lack':472C 'latter':305C 'len':93C 'length':125C 'lie':319C,377C 'mark':361C 'may':31B,219C 'mem':294C,328C 'memori':49B,53B,97C,103C,217C,323C,356C,358C,383C,449C,467C 'memory-domain':322C 'mempool':81C,116C,120C,210C,241C,302C 'mode':42B,73C,190C,282C,345C,394C 'mpu':156C 'must':437C 'necessarili':180C 'noth':312C 'oop':479C 'out-paramet':108C 'outcom':314C 'output':9A,88C 'overwrit':45B 'p':159C,164C,330C 'paramet':89C,110C 'part':350C 'partit':325C,329C,370C 'pass':28B 'perform':265C 'permiss':429C,474C 'pmp':143C 'point':215C 'pointer':10A,29B,177C,268C 'pointer-s':267C 'privat':448C 'privileg':334C 'protect':55B,373C 'pure':107C 'queue':229C 'rather':99C 'reach':283C 'read':5A,33B,47B,98C,151C,170C,175C,220C,336C,340C,363C,428C,490C 'read-on':46B,339C,362C 'read-permiss':427C 'read-valid':174C,489C 'read-writ':335C 'readabl':380C,440C 'reboot':67B,413C 'region':168C 'region/__rodata_region':149C 'reliabl':421C 'remain':488C 'replac':461C 'requir':248C,286C 'return':308C 'risc':141C 'risc-v':140C 'ro':160C,162C,167C,333C 'rom':148C 'rtio':2A,18B,25B,78C,113C,199C,201C,207C,238C,292C,299C 'rtos':19B 'run':279C,483C 'runtim':20B 'rw':165C,331C 'servic':425C 'size':269C 'still':438C 'store':118C,274C,285C,346C,390C 'subsys/rtio/rtio_syscalls.c':84C 'succeed':347C 'supervisor':41B,281C 'suppli':256C 'sys':293C,407C 'syscal':3A,74C,96C,102C,212C,466C 'target':318C,376C,452C 'termin':476C 'text/.rodata':386C 'thread':23B,51B,185C,191C,367C,419C,444C,471C 'togeth':289C 'two':87C,313C 'u':161C,166C,332C 'unprivileg':187C,418C 'unwrit':382C 'user':72C,189C,338C 'user-mod':71C,188C 'userspac':288C 'v':142C 'valid':85C,135C,138C,157C,176C,491C 'valu':354C 'verifi':75C 'vrfi':77C 'whose':231C 'without':303C 'writabl':181C 'write':8A,37B,104C,223C,311C,337C,372C,468C,473C 'z':76C,111C,400C 'zephyr':1A,21B","nicknames":[],"mitigations":[],"who_affected":"Only Zephyr builds with user mode (CONFIG_USERSPACE) and the RTIO system memory block pool (CONFIG_RTIO_SYS_MEM_BLOCKS) enabled are exposed. The attacker must be an unprivileged user-mode thread that has been granted an RTIO context, so the risk sits inside a device's own software rather than from the network. Builds without user mode, or without the mempool configuration, can skip it.","tier":"C","verified":{},"analyst_revisit_at":null,"first_public_at":"2026-10-19T23:17:36+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H","cvss_by":"vulnerabilities@zephyrproject.org","poc_count":0,"sources":[{"source":"nvd","external_id":"CVE-2026-19595","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-19595","severity":null,"published_at":"2026-10-19T23:17:36+00:00","modified_at":"2026-10-20T20:17:24+00:00","first_seen_at":"2026-10-23T21:57:19+00:00","fetched_at":"2026-10-23T22:28:57+00:00","note":null}],"documents":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}