Commit d1d6c6e
committed
listen: ip bind: fix numeric iface parse overrunning caller sockaddr_in
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.1 parent fd1e670 commit d1d6c6e
1 file changed
Lines changed: 21 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
447 | 447 | | |
448 | 448 | | |
449 | 449 | | |
450 | | - | |
451 | | - | |
452 | | - | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
453 | 471 | | |
454 | 472 | | |
455 | 473 | | |
| |||
0 commit comments