Un defecto en la asignación dinámica de objetos permite que código sin privilegios ejecute escrituras fuera de límites en memoria del kernel cuando userspace está habilitado
El National Vulnerability Database clasificó como HIGH la vulnerabilidad CVE-2026-19569 en Zephyr RTOS, un sistema operativo de tiempo real ampliamente usado en dispositivos IoT y sistemas embebidos. El defecto reside en la función dynamic_object_create() del archivo kernel/userspace/userspace.c y permite que un thread en modo usuario sin privilegios provoque escrituras fuera de límites en el heap del kernel, escapando del sandbox de CONFIG_USERSPACE. La explotación requiere que el sistema tenga habilitada la combinación CONFIG_USERSPACE con CONFIG_DYNAMIC_OBJECTS — configuración común en implementaciones que necesitan aislamiento entre componentes de firmware y asignación dinámica de recursos en tiempo de ejecución.
Cómo un cálculo sin validación abre la puerta al heap del kernel
El núcleo del problema está en la aritmética de asignación de memoria que dynamic_object_create() ejecuta sin verificar desbordamiento. Cuando el código calcula el tamaño del respaldo para un objeto dinámico del kernel, suma obj_size_get(otype) más el parámetro size que llega directamente desde modo usuario. Para elementos de stack de threads, la función aplica la macro STACK_ELEMENT_DATA_SIZE(size), que redondea hacia arriba y agrega overhead fijo. Ninguna de estas operaciones verifica si el resultado desborda el rango de un entero sin signo.
Un atacante que pase un valor de size cercano a SIZE_MAX provoca que la suma total se desborde y vuelva a un número muy pequeño. El heap del resource pool del kernel entrega entonces un chunk de apenas unos bytes, pero el descriptor del objeto queda etiquetado con el tipo completo solicitado y registrado en la tabla de objetos del kernel con el tamaño original sin validar. La función k_object_alloc_size() está declarada como syscall en include/zephyr/sys/kobject.h, su verificador z_vrfy_k_object_alloc_size() en kernel/userspace/userspace_handler.c es un simple pass-through sin validación, y z_object_alloc() solo revisa el rango del parámetro otype — el parámetro size nunca se acota.
La rama de stack-element amplifica el impacto bajo CONFIG_GEN_PRIV_STACKS
La rama de código que maneja elementos de stack es accesible también a través del syscall k_thread_stack_alloc() en kernel/dynamic.c. Cuando el sistema tiene habilitado CONFIG_GEN_PRIV_STACKS, esta rama almacena un puntero controlado por el atacante como base del stack privilegiado de un thread de usuario. Dado que las verificaciones posteriores de objetos del kernel solo revisan el tipo del objeto y su estado de inicialización, el handle con tamaño truncado pasa sin problemas las validaciones K_SYSCALL_OBJ_INIT() y K_SYSCALL_OBJ_NEVER_INIT().
El syscall de inicialización correspondiente — k_mutex_init(), k_sem_init() o k_thread_create(), según el tipo de objeto — escribe entonces una estructura completa sobre la asignación truncada. El resultado es una escritura fuera de límites en modo supervisor dentro del heap del resource pool del kernel, con tamaño y contenido sustancialmente controlados por el atacante. Esto corrompe los metadatos de chunk de sys_heap y objetos adyacentes del kernel, abriendo camino a ejecución de código en nivel kernel o, como mínimo, corrupción de memoria del kernel y compromiso total del sistema.
Exposición en dispositivos IoT industriales desplegados en la región
Zephyr RTOS es base de firmware en sensores industriales, gateways de edge computing y controladores de infraestructura crítica desplegados en sectores como energía, manufactura y agricultura de precisión en Brasil, México y Argentina. La configuración CONFIG_USERSPACE se habilita típicamente en dispositivos que ejecutan múltiples componentes de firmware de distintos proveedores sobre el mismo hardware — escenario común en plataformas de IoT industrial que buscan aislar código de terceros del núcleo del sistema. CONFIG_DYNAMIC_OBJECTS, por su parte, es seleccionado automáticamente por CONFIG_DYNAMIC_THREAD cuando userspace está activo, lo que amplía la superficie de exposición a cualquier implementación que necesite crear threads en tiempo de ejecución.
La explotación requiere que el thread atacante tenga un resource pool asignado, condición que se cumple en la mayoría de las arquitecturas de firmware modular donde cada componente opera con su propio pool de recursos. No hay evidencia pública de explotación en campo, pero la naturaleza del defecto — accesible desde modo usuario sin autenticación adicional — lo convierte en candidato para cadenas de ataque contra dispositivos con interfaces de red expuestas o que procesan datos no confiables de sensores externos.
Nuestro análisis
CVE-2026-19569 es un caso de manual de por qué las validaciones de entrada en syscalls no pueden delegarse únicamente a verificadores automáticos generados por el sistema de tipos. El verificador z_vrfy_k_object_alloc_size() actúa como pass-through porque el sistema de generación de código de Zephyr asume que los parámetros escalares simples no requieren validación semántica — una suposición que falla cuando esos parámetros alimentan aritmética de asignación de memoria sin protección contra overflow. El patrón se repite en otros RTOSs que implementan separación de privilegios: la complejidad de mantener coherencia entre el modelo de objetos del kernel y las validaciones de syscalls crea puntos ciegos donde un parámetro aparentemente inocuo puede desencadenar corrupción de memoria en modo supervisor.
La corrección reportada rechaza tanto las computaciones que desbordan como libera el descriptor parcialmente construido, pero la pregunta de fondo persiste: ¿cuántos otros syscalls en Zephyr y RTOSs similares confían en que la aritmética de tamaños nunca desbordará, sin verificarlo explícitamente en cada punto de entrada desde modo usuario?