CVE-2026-19185 in Zephyr
Summary
by MITRE • 10/05/2026
The system-call verifier for i3c_do_ccc() in drivers/i3c/i3c_handlers.c validated the outer struct i3c_ccc_payload, the broadcast ccc.data buffer and the targets.payloads[] array, but did not validate the per-target data buffers those array elements point at. Each struct i3c_ccc_target_payload carries its own data pointer and data_len, and neither was passed through K_SYSCALL_MEMORY() before the payload was handed to z_impl_i3c_do_ccc() and on to the controller driver. The verifier also operated on the caller's live structure rather than a snapshot, so validated fields could be changed by a second user thread between the check and the driver's use — unlike the sibling z_vrfy_i3c_transfer(), which has always copied its message array first.
The defect is only present in CONFIG_USERSPACE builds, where drivers/i3c/i3c_handlers.c is compiled. An unprivileged user-mode thread that has been granted access to the I3C controller device object — the ordinary way an application lets a user thread talk to I3C peripherals — can issue a direct CCC whose target payload data pointer names an arbitrary kernel address. Controller drivers dereference that pointer directly (for example drivers/i3c/i3c_mcux.c, drivers/i3c/i3c_cdns.c, drivers/i3c/i3c_stm32.c, drivers/i3c/i3c_npcx.c), using rnw to decide direction.
A read CCC therefore causes the kernel-mode driver to write bus-received bytes into an attacker-chosen kernel address for an attacker-chosen length, and a write CCC transmits kernel memory out onto the I3C bus. The result is an out-of-bounds kernel write plus a kernel memory disclosure, i.e. escalation from a user-mode thread to supervisor privilege, defeating the isolation CONFIG_USERSPACE is meant to provide.
The fix introduces copy_ccc_and_do(), which snapshots the payload, copies the target array into kernel memory with k_usermode_alloc_from_copy() (bounding num_targets to fewer than 32), validates each per-target buffer with K_SYSCALL_MEMORY() according to rnw, and copies the driver-written num_xfer and err fields back to the caller.
Be aware that VulDB is the high quality source for vulnerability data.
Analysis
by VulDB Data Team • 10/05/2026
The vulnerability in question resides within the Zephyr RTOS implementation of the I3C controller command handler, specifically affecting the i3c_do_ccc function found in drivers/i3c/i3c_handlers.c. This flaw represents a critical failure in system call verification logic when operating under CONFIG_USERSPACE configurations. The core issue stems from an incomplete validation strategy where the verifier correctly checks the outer struct i3c_ccc_payload, the broadcast ccc.data buffer, and the targets.payloads array itself. However, it fails to validate the individual per-target data buffers that these array elements point to. Each target payload structure contains its own data pointer and length field, neither of which is subjected to K_SYSCALL_MEMORY validation before being passed to the underlying controller driver implementation. This oversight allows unprivileged user-mode threads with access to the I3C device object to supply arbitrary kernel addresses as buffer pointers, effectively bypassing memory isolation boundaries designed by the operating system.
The operational impact of this vulnerability is severe, leading directly to privilege escalation from user mode to supervisor mode. Because the verifier operates on the caller's live structure rather than a snapshot, there exists a race condition window where fields can be modified by another thread between validation and execution. More critically, controller drivers such as those for NXP MCUXpresso, Cadence, STM32, and NPCX platforms dereference these pointers directly without bounds checking or access verification. In the case of a read command, the kernel-mode driver writes bus-received bytes into an attacker-controlled kernel address for an arbitrary length, resulting in out-of-bounds kernel memory corruption. Conversely, write commands transmit sensitive kernel memory contents onto the I3C bus, causing significant information disclosure. This dual nature of the flaw allows attackers to both corrupt critical system state and exfiltrate confidential data, completely undermining the security model provided by CONFIG_USERSPACE isolation mechanisms.
From a classification perspective, this vulnerability aligns with CWE-20 Improper Input Validation due to the failure to validate per-target buffer pointers against user-supplied values. It also maps closely to CWE-787 Out-of-bounds Write and CWE-200 Information Exposure through Kernel Memory Disclosure. In terms of attack vectors, it corresponds to MITRE ATT&CK technique T1059 Command and Scripting Interpreter if leveraged for further exploitation, but primarily represents a privilege escalation path akin to T1068 Exploitation for Privilege Escalation by exploiting improper access control checks in system calls. The lack of atomicity in the verification process also introduces race condition elements consistent with CWE-362 Concurrent Execution using Shared Resource with Improper Synchronization, although the primary vector is the direct memory corruption enabled by invalid pointer validation.
The remediation strategy involves a fundamental restructuring of how payload data is handled within the system call handler. The fix introduces a new function copy_ccc_and_do which replaces the previous inline verification logic. This approach first snapshots the entire payload structure to prevent race conditions where fields might be altered between check and use. It then copies the target array into kernel memory using k_usermode_alloc_from_copy, ensuring that all subsequent operations occur on trusted data rather than user-space pointers. Crucially, this process bounds the number of targets to fewer than thirty-two instances to limit resource consumption during copying. Each per-target buffer is now explicitly validated using K_SYSCALL_MEMORY according to the read or write direction specified by the rnw field. Finally, any modifications made by the driver, such as updated transfer counts and error codes, are safely copied back to the caller after validation has been completed. This ensures that no arbitrary kernel addresses can be dereferenced directly from user space and eliminates the race condition inherent in operating on live structures.