Skip to content

listen: ip bind: fix numeric iface parse overrunning caller sockaddr_in - #3646

Closed
saghul wants to merge 3 commits into
warmcat:mainfrom
saghul:fix-interface-to-sa-numeric-overflow
Closed

listen: ip bind: fix numeric iface parse overrunning caller sockaddr_in#3646
saghul wants to merge 3 commits into
warmcat:mainfrom
saghul:fix-interface-to-sa-numeric-overflow

Conversation

@saghul

@saghul saghul commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

lws_interface_to_sa() may be handed a buffer as small as a struct
sockaddr_in: lws_socket_bind()'s AF_INET path passes its 16-byte
serv_addr4 (with addrlen = sizeof(serv_addr4)). When ifname is not a
real interface name, the fallback casts that buffer to lws_sockaddr46 *
and calls lws_sa46_parse_numeric_address(), which begins with

memset(sa46, 0, sizeof(*sa46));

sizeof(lws_sockaddr46) is 28 bytes when IPv6 is enabled (it embeds a
struct sockaddr_in6), so this writes 12 bytes past a 16-byte caller
buffer. ASan reports a stack-buffer-overflow in
lws_sa46_parse_numeric_address() for any listen bind to a numeric IPv4
address (eg, lws_socket_bind() -> lws_interface_to_sa() with iface
"127.0.0.1"); in a release build the overrun silently clobbers adjacent
stack.

addrlen is already passed for exactly this reason but was ignored on
this path. Parse into a local full-width lws_sockaddr46 and memcpy back
only min(sa46_socklen(), addrlen) bytes, so the caller's buffer is never
overrun regardless of family.

The 28-byte memset was introduced with the recent
lws_sa46_parse_numeric_address() rework; the (lws_sockaddr46 *)addr cast
predates it and was harmless while the function only wrote the parsed
family's fields.

lws-team and others added 3 commits July 26, 2026 08:53
lws_interface_to_sa() may be handed a buffer as small as a struct
sockaddr_in: lws_socket_bind()'s AF_INET path passes its 16-byte
serv_addr4 (with addrlen = sizeof(serv_addr4)).  When ifname is not a
real interface name, the fallback casts that buffer to lws_sockaddr46 *
and calls lws_sa46_parse_numeric_address(), which begins with

	memset(sa46, 0, sizeof(*sa46));

sizeof(lws_sockaddr46) is 28 bytes when IPv6 is enabled (it embeds a
struct sockaddr_in6), so this writes 12 bytes past a 16-byte caller
buffer.  ASan reports a stack-buffer-overflow in
lws_sa46_parse_numeric_address() for any listen bind to a numeric IPv4
address (eg, lws_socket_bind() -> lws_interface_to_sa() with iface
"127.0.0.1"); in a release build the overrun silently clobbers adjacent
stack.

addrlen is already passed for exactly this reason but was ignored on
this path.  Parse into a local full-width lws_sockaddr46 and memcpy back
only min(sa46_socklen(), addrlen) bytes, so the caller's buffer is never
overrun regardless of family.

The 28-byte memset was introduced with the recent
lws_sa46_parse_numeric_address() rework; the (lws_sockaddr46 *)addr cast
predates it and was harmless while the function only wrote the parsed
family's fields.
@sonarqubecloud

Copy link
Copy Markdown

@lws-team
lws-team force-pushed the main branch 6 times, most recently from 558a432 to 4e59faf Compare July 27, 2026 20:02
@saghul saghul closed this Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants