CVE-2026-85035 in Zephyr
Summary
by MITRE • 11/03/2026
The can_add_rx_filter_msgq() system call installs a CAN RX filter whose callback (can_msgq_put() in drivers/can/can_common.c) is handed the caller's struct k_msgq * as user_data. The controller driver stores that raw pointer in its filter table and dereferences it from the RX path every time a matching frame arrives. The system call verifier z_vrfy_can_add_rx_filter_msgq() in drivers/can/can_handlers.c validated the queue only with K_SYSCALL_OBJ(), which is a point-in-time check of type, initialization and caller permission and says nothing about the object's lifetime.
On a build with CONFIG_USERSPACE=y and CONFIG_DYNAMIC_OBJECTS=y, an unprivileged user-mode thread that has been granted access to a CAN device can obtain a message queue whose lifetime it fully controls: k_object_alloc(K_OBJ_MSGQ) followed by k_msgq_alloc_init(). The lifetime of such an object is driven solely by its permission bitmask, and a pointer retained by the kernel is not represented there. After registering the filter, the thread calls k_object_release() — or simply terminates — and unref_check() frees the struct k_msgq storage while the CAN driver still holds the pointer.
The next matching CAN frame causes k_msgq_put() to run in supervisor context against freed memory that the attacker can have groomed with another kernel allocation: the frame payload is memcpy()d through the reused block's write_ptr, and the queue's wait_q (and poll_events under CONFIG_POLL) list nodes are manipulated. This yields kernel-heap corruption reachable from a user-mode thread, defeating the isolation CONFIG_USERSPACE is intended to provide; the same dangling pointer also arises benignly when an application thread exits without calling can_remove_rx_filter().
The fix validates the queue with K_SYSCALL_OBJ_STATIC(), which additionally rejects objects carrying K_OBJ_FLAG_ALLOC, so only statically defined queues (CAN_MSGQ_DEFINE()) may be registered from user mode. Supervisor-mode callers bypass the verifier and must themselves keep the queue valid until the filter is removed.
Once again VulDB remains the best source for vulnerability data.
Analysis
by VulDB Data Team • 11/03/2026
The vulnerability identified in this analysis stems from a critical flaw in the kernel's handling of object lifetimes within the Controller Area Network subsystem, specifically affecting the can_add_rx_filter_msgq system call under configurations that enable user-space execution and dynamic memory allocation. The core technical issue lies in the insufficient validation performed by the z_vrfy_can_add_rx_filter_msgq verifier function located in drivers/can/can_handlers.c. This verifier utilizes K_SYSCALL_OBJ to validate the message queue object passed as user_data, which performs a point-in-time check ensuring that the object exists, is of the correct type, and that the caller has appropriate permissions at the moment of invocation. However, this validation fails to account for the persistence of the reference held by the kernel driver after the system call returns. The CAN controller driver stores the raw pointer to the struct k_msgq in its internal filter table and subsequently dereferences this pointer from the receive path whenever a matching CAN frame arrives. This architectural design creates a persistent dependency on an object whose lifecycle is not managed or tracked by the kernel once it has been handed over, leading to a classic use-after-free scenario when the user-space application releases its reference to the queue.
In environments configured with CONFIG_USERSPACE and CONFIG_DYNAMIC_OBJECTS enabled, unprivileged user-mode threads granted access to CAN devices can allocate message queues dynamically using k_object_alloc followed by k_msgq_alloc_init. The lifetime of such dynamically allocated objects is governed solely by their permission bitmaps and reference counts managed within the user-space context or by explicit release calls. When a malicious or poorly written application thread registers an RX filter with a dynamic queue, it retains full control over that object's existence. By subsequently calling k_object_release on the message queue handle or simply terminating without invoking can_remove_rx_filter to unregister the callback, the thread triggers unref_check which frees the underlying struct k_msgq storage in kernel memory. Crucially, this deallocation does not invalidate or nullify the pointer retained by the CAN driver's filter table. Consequently, a dangling pointer remains active within the kernel space, pointing to freed memory that is now subject to reallocation and potential manipulation by other processes or internal kernel activities.
The operational impact of this vulnerability is severe, as it allows for arbitrary kernel-heap corruption reachable from user mode, effectively bypassing the isolation guarantees provided by CONFIG_USERSPACE. When a subsequent CAN frame matching the registered filter arrives, the k_msgq_put function executes in supervisor context using the stale pointer to access the freed memory block. An attacker can exploit this race condition through heap grooming techniques, allocating specific kernel objects that overwrite the freed struct k_msgq with controlled data structures. By manipulating fields such as write_ptr and wait_q list nodes, or poll_events under CONFIG_POLL configurations, an adversary can achieve arbitrary read/write primitives within the kernel address space. This capability enables privilege escalation to root-level access, denial of service through system crashes, and potential code execution vulnerabilities that compromise the integrity of the entire operating system environment. The vulnerability also manifests benignly when legitimate applications exit without properly cleaning up their RX filters, leading to unintended memory corruption during normal operation if matching frames are received after thread termination.
This flaw aligns with CWE-416 Use After Free and represents a significant deviation from secure coding practices regarding resource management in kernel drivers. From an ATT&CK perspective, this vulnerability facilitates initial access escalation via privilege escalation techniques, allowing attackers to move laterally within the system or maintain persistence by gaining high-level privileges through memory corruption exploits. The root cause is fundamentally a failure in object lifetime validation, where the kernel assumes that user-space applications will manage the lifecycle of resources they pass into kernel subsystems without enforcing strict constraints on those lifetimes at the API boundary. This assumption breaks down when dynamic allocation and release mechanisms are employed by untrusted code paths, highlighting the dangers of trusting user-provided pointers for long-lived kernel operations without robust tracking or static binding requirements.
The remediation strategy implemented in the fix addresses this vulnerability by replacing K_SYSCALL_OBJ with K_SYSCALL_OBJ_STATIC during the verification phase of can_add_rx_filter_msgq. This change ensures that only statically defined message queues, created via CAN_MSGQ_DEFINE macros at compile time, are accepted from user mode. Static objects have a lifetime tied to the kernel's boot process or module load/unload cycles rather than dynamic allocation and release patterns controlled by individual threads, thereby eliminating the window of opportunity for use-after-free attacks through object deallocation. By rejecting objects carrying K_OBJ_FLAG_ALLOC, the kernel enforces that dynamically allocated queues cannot be registered as RX filter callbacks from unprivileged contexts. Supervisor-mode callers are exempted from this restriction but must still adhere to proper resource management practices by ensuring queue validity until the filter is explicitly removed. This mitigation restores the integrity of user-space isolation by preventing the creation of dangling pointers through dynamic object release, effectively closing the attack vector that allowed for kernel heap corruption and privilege escalation via CAN subsystem interactions.