---
id: "CVE-2026-90834"
page: "https://infrastack.ai/live/CVE-2026-90834"
kind: "vulnerability"
aliases: ["CVE-2026-90834"]
title: "Zephyr: wrong syscall check lets user threads crash the kernel"
severity: "medium"
cvss: 5.5
epss: null
exploited: false
status: "open"
category: "runtime"
products: []
ecosystems: []
tags: ["embedded", "runtime", "uart", "userspace", "zephyr"]
not_affected_if: ["default-config", "no-userspace", "no-wide-data-uart"]
published_at: "2026-11-10T22:21:14+00:00"
first_seen_at: "2026-11-10T22:27:31+00:00"
updated_at: "2026-11-10T22:30:46+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-90834", "first_seen_at": "2026-11-10T22:27:31+00:00"}]
exploit_sources: []
---

# Zephyr: wrong syscall check lets user threads crash the kernel

Link for people: https://infrastack.ai/live/CVE-2026-90834 (this .md is for agents)

Zephyr's 16-bit UART syscall verifiers check the wrong driver operation, so a user-mode thread can call a NULL function pointer in kernel context. The result is a kernel fault that halts or reboots the device, a denial of service against the whole system.

_Summary, check and fix written by a model from the sources; labelled as such._

## How to check

- Check whether the build sets `CONFIG_USERSPACE` and `CONFIG_UART_WIDE_DATA` (plus `CONFIG_UART_ASYNC_API` for the tx and rx variants).
- Look for user-mode threads that hold access to a UART device object and call `uart_poll_out_u16`, `uart_tx_u16` or `uart_rx_enable_u16`.

## Timeline

- 2026-11-10T22:27:31+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-90834

## Documents

- [advisory] Vendor advisory: github.com https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-xvwx-ww79-r346
- [fix] Patch: github.com https://github.com/zephyrproject-rtos/zephyr/commit/3c13bfd3d3ccdceeb51b884fed5a8d2a49475484

## From the sources

The user-mode syscall verifiers for the 16-bit ("wide data") UART API in drivers/serial/uart_handlers.c validated the wrong driver operation. z_vrfy_uart_poll_out_u16(), z_vrfy_uart_tx_u16() and z_vrfy_uart_rx_enable_u16() each ran K_SYSCALL_DRIVER_UART() against the 8-bit op (poll_out, tx, rx_enable) rather than the 16-bit op that the corresponding implementation dereferences (poll_out_u16, tx_u16, rx_enable_u16). z_impl_uart_poll_out_u16(), z_impl_uart_tx_u16() and z_impl_uart_rx_enable_u16() in include/zephyr/drivers/uart/uart_internal.h call their op unconditionally, with no NULL guard of their own, because the verifier is supposed to have established that the op exists.

CONFIG_UART_WIDE_DATA is an application-selectable option that no driver selects, and only a handful of the serial drivers in the tree implement any _u16 operation; every other driver leaves those struct uart_driver_api members NULL while still providing the 8-bit ops the old check inspected. In a build with CONFIG_USERSPACE and CONFIG_UART_WIDE_DATA (plus CONFIG_UART_ASYNC_API for the uart_tx_u16() and uart_rx_enable_u16() variants), an unprivileged user-mode thread that legitimately holds access to such a UART device object can invoke the _u16 syscall: the object, permission and op checks all pass, and the kernel-side implementation then performs an indirect call through a NULL function pointer while running at supervisor privilege.

The result is a CPU exception taken in kernel context instead of the intended K_OOPS or -ENOSYS return. With the default k_sys_fatal_error_handler() this halts the system (or warm-reboots it under CONFIG_RESET_ON_FATAL_ERROR), so a thread confined by the userspace sandbox can deny service to the whole device — a capability the user-mode privilege boundary is specifically meant to withhold. The call target is a fixed NULL, so there is no attacker-controlled code execution and no memory disclosure; the separate K_SYSCALL_MEMORY_ARRAY_READ()/K_SYSCALL_MEMORY_ARRAY_WRITE() bounds checks on the caller's buffer were and remain correct. The fix points each verifier at the matching _u16 op, using a plain K_SYSCALL_OBJ() object check where the op does not exist or where the implementation already tests it for NULL.

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
