diff options
author | Christoph M. Becker <cmbecker69@gmx.de> | 2020-03-11 10:16:04 +0100 |
---|---|---|
committer | Christoph M. Becker <cmbecker69@gmx.de> | 2020-03-11 11:30:15 +0100 |
commit | 53797c206a4304e0c322c39cb02abf891429367e (patch) | |
tree | 4609957fb50b81d618aa6ca33c4e62db394e8eb2 /main | |
parent | 2462f2dab185f53544f2c5335ba6c16a007f3c71 (diff) | |
download | php-git-53797c206a4304e0c322c39cb02abf891429367e.tar.gz |
Fix #78210: Invalid pointer address
This is actually about three distinct issues:
* If an empty string is passed as $address to `stream_socket_sendto()`,
the `sa` is not initialized, so we must not pass it as `addr` to
`php_stream_xport_sendto()`.
* On POSIX, `recvfrom()` truncates messages which are too long to fit
into the specified buffer (unless `MSG_PEEK` is given), discards the
excessive bytes, and returns the buffer length. On Windows, the same
happens, but `recvfrom()` returns `SOCKET_ERROR` with the error code
`WSAEMSGSIZE`. We have to catch this for best POSIX compatibility.
* In `php_network_parse_network_address_with_port()`, we have to zero
`in6` (not only its alias `sa`) to properly support IPv6.
Co-Authored-By: Nikita Popov <nikita.ppv@googlemail.com>
Diffstat (limited to 'main')
-rw-r--r-- | main/network.c | 6 | ||||
-rw-r--r-- | main/streams/xp_socket.c | 6 |
2 files changed, 10 insertions, 2 deletions
diff --git a/main/network.c b/main/network.c index 21f17e8ade..f00c775c6f 100644 --- a/main/network.c +++ b/main/network.c @@ -512,9 +512,11 @@ PHPAPI int php_network_parse_network_address_with_port(const char *addr, zend_lo zend_string *errstr = NULL; #if HAVE_IPV6 struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa; -#endif - memset(sa, 0, sizeof(struct sockaddr)); + memset(in6, 0, sizeof(struct sockaddr_in6)); +#else + memset(in4, 0, sizeof(struct sockaddr_in)); +#endif if (*addr == '[') { colon = memchr(addr + 1, ']', addrlen-1); diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index acdb1f8876..0ae0c0f77b 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -272,6 +272,12 @@ static inline int sock_recvfrom(php_netstream_data_t *sock, char *buf, size_t bu socklen_t sl = sizeof(sa); ret = recvfrom(sock->socket, buf, XP_SOCK_BUF_SIZE(buflen), flags, (struct sockaddr*)&sa, &sl); ret = (ret == SOCK_CONN_ERR) ? -1 : ret; +#ifdef PHP_WIN32 + /* POSIX discards excess bytes without signalling failure; emulate this on Windows */ + if (ret == -1 && WSAGetLastError() == WSAEMSGSIZE) { + ret = buflen; + } +#endif if (sl) { php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl, textaddr, addr, addrlen); |