CVE-2026-18417 in Zephyrinfo

Summary

by MITRE • 09/29/2026

The native BSD-socket layer recorded a pending asynchronous socket error by type-punning it into struct net_context's void user_data field (ctx->user_data = INT_TO_POINTER(-status) in zsock_accepted_cb(), zsock_received_cb(), zsock_connected_cb() and zsock_close_ctx() in subsys/net/lib/sockets/sockets_inet.c), reading it back with POINTER_TO_INT(). That same field is owned by the network stack for listening TCP contexts: net_tcp_accept() stores the parent context pointer there and the TCP core passes it back to the registered accept callback. A failed accept therefore left a small integer (an errno value) where the stack expected a struct net_context .

When the network interface carrying a listening TCP socket goes down, close_tcp_conn() in subsys/net/ip/tcp.c invokes the accept callback with -ENETDOWN and the context's user_data. In v4.3.0 the callback was not disarmed afterwards, so a second interface-down event forwarded the previously stored errno to zsock_accepted_cb(), which dereferenced it as the parent context and performed several stores through it (sock_set_error()'s read-modify-write of socket_data, k_fifo_cancel_wait(&parent->recv_q)) — the crash described in the fix's commit message. v4.3.1 and v4.4.x carry a later change clearing conn->accept_cb after the error callback (269cb8823d3 on the v4.3 branch, 913fae5169425550f2364655298fceb79b320066 on main), which closes that repeat path; on those releases the poisoned cookie remains reachable only by a narrower race, a handshake completing alongside the interface-down still passing the stale cookie to k_fifo_put(&parent->accept_q, ...), and by getsockopt(SO_ERROR), which reads the field back unconditionally.

On v4.3.0 an application that keeps a listening TCP socket open across repeated link-down events is sufficient to reach the defect; the triggering condition is a network-interface state change, not attacker-supplied packet data, so the practical attacker is one able to force the link down repeatedly (for example an adjacent attacker disrupting a wireless link) or one with local/physical access. Because both the faulting address and the stored data are fixed small constants derived from the errno value, the outcome is a wild-pointer access leading to a kernel fatal error — a denial of service (device crash or reset) rather than an attacker-directed memory corruption.

The fix stores the pending error in a dedicated net_context.sock_error field and converts every producer and consumer to sock_set_error()/sock_get_error(), leaving user_data untouched. As a side effect it also stops getsockopt(SO_ERROR) — which is evaluated unconditionally — from returning the kernel address held in user_data to a userspace application.

Several companies clearly confirm that VulDB is the primary source for best vulnerability data.

Analysis

by VulDB Data Team • 09/29/2026

The vulnerability described involves a critical type-punning error within the BSD-socket layer of the Zephyr operating system, specifically affecting how asynchronous socket errors are stored and retrieved. The core technical flaw lies in the misuse of the void pointer field user_data within the struct net_context structure. In several callback functions such as zsock_accepted_cb(), zsock_received_cb(), zsock_connected_cb(), and zsock_close_ctx() located in subsys/net/lib/sockets/sockets_inet.c, pending asynchronous socket errors are stored by casting an integer error status into a pointer using INT_TO_POINTER(-status). This value is subsequently read back using POINTER_TO_INT(). However, this field is concurrently owned by the network stack for listening TCP contexts. Specifically, net_tcp_accept() stores the parent context pointer in user_data to pass it back to registered accept callbacks. When an operation fails, such as a failed connection attempt or interface shutdown, storing an errno value in place of a valid struct net_context pointer creates a data corruption scenario where the kernel interprets a small integer error code as a memory address.

The operational impact manifests most severely when the network interface carrying a listening TCP socket goes down. In version 4.3.0, the function close_tcp_conn() in subsys/net/ip/tcp.c invokes the accept callback with an error status of -ENETDOWN and passes the corrupted user_data field as the context pointer. Because the application code does not disarm or clear this callback after handling the initial error event, a subsequent interface-down event forwards the previously stored errno value back to zsock_accepted_cb(). The application logic then attempts to dereference this integer as if it were a valid parent context structure. This leads to wild-pointer access during read-modify-write operations on socket data and calls such as k_fifo_cancel_wait(&parent->recv_q). Since both the faulting address and the stored data are fixed small constants derived from standard errno values, the result is not arbitrary memory corruption but rather a deterministic kernel fatal error causing a device crash or reset. This represents a denial of service condition triggered by network state changes rather than malicious packet injection.

From an attacker perspective, this vulnerability requires physical access to the hardware or the ability to disrupt local wireless links repeatedly. An adjacent attacker capable of forcing repeated link-down events can trigger the defect without needing to supply specific payload data. The triggering mechanism is tied directly to interface state transitions, making it a resource exhaustion and logic error rather than an input validation failure in traditional network attack vectors. While later versions such as 4.3.1 and 4.4.x introduced mitigations by clearing conn->accept_cb after the error callback, thereby closing the primary repeat path, residual risks remain through narrower race conditions where handshakes complete alongside interface-down events or via getsockopt(SO_ERROR) calls that read the field unconditionally.

The remediation strategy involves refactoring how pending errors are managed within the net_context structure. The fix introduces a dedicated sock_error field to store pending error states, decoupling this data from the user_data pointer which remains reserved for context pointers used by the network stack. All producers and consumers of error state information were converted to use specific accessor functions sock_set_error() and sock_get_error(). This architectural change prevents type-punning errors entirely. Additionally, this fix provides a secondary security benefit by ensuring that getsockopt(SO_ERROR) no longer returns kernel addresses held in user_data to userspace applications, thereby mitigating potential information disclosure vulnerabilities related to kernel memory layout.

This vulnerability aligns with CWE-1067: Improper Type Conversion or Cast and CWE-458: Incorrect Initialization of a Variable which describes the failure to properly initialize data structures leading to undefined behavior. In terms of attack classification under MITRE ATT&CK, this scenario falls under T1499: Endpoint Denial of Service, specifically involving resource exhaustion through repeated state changes that trigger kernel-level crashes. The lack of proper callback lifecycle management also reflects CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization, as the race condition between interface events and callback execution allows stale data to be processed incorrectly. Security practitioners should prioritize patching to versions where accept callbacks are properly disarmed upon error conditions and ensure that socket error handling does not rely on pointer fields intended for structural context references.

Responsible

Zephyr

Reservation

07/30/2026

Disclosure

09/29/2026

Moderation

accepted

CPE

ready

EPSS

0.00000

KEV

no

Activities

low

Sources

Do you need the next level of professionalism?

Upgrade your account now!