From 3a37e4042e4c12135a2cdc6a9877d37e7d2cf67f Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Mon, 9 Mar 2020 14:37:03 +0100 Subject: [PATCH 1/3] 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. --- ext/standard/streamsfuncs.c | 2 +- main/network.c | 4 +++- main/streams/xp_socket.c | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 8f0bd8bc8e179..6fbfb0bcdc504 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -366,7 +366,7 @@ PHP_FUNCTION(stream_socket_sendto) } } - RETURN_LONG(php_stream_xport_sendto(stream, data, datalen, (int)flags, target_addr ? &sa : NULL, sl)); + RETURN_LONG(php_stream_xport_sendto(stream, data, datalen, (int)flags, target_addr_len ? &sa : NULL, sl)); } /* }}} */ diff --git a/main/network.c b/main/network.c index 21f17e8ade0c3..2632a003ebfd1 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(in6, 0, sizeof(struct sockaddr_in6)); +#else memset(sa, 0, sizeof(struct sockaddr)); +#endif if (*addr == '[') { colon = memchr(addr + 1, ']', addrlen-1); diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index acdb1f8876ca7..301b7326aa83b 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); @@ -395,6 +401,7 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void xparam->inputs.addr, xparam->inputs.addrlen); if (xparam->outputs.returncode == -1) { + fprintf(stderr, "sockerr %d\n", WSAGetLastError()); char *err = php_socket_strerror(php_socket_errno(), NULL, 0); php_error_docref(NULL, E_WARNING, "%s\n", err); From 378f326efc44615e443c603e46812a4df4531291 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Mon, 9 Mar 2020 15:05:06 +0100 Subject: [PATCH 2/3] oops --- main/streams/xp_socket.c | 1 - 1 file changed, 1 deletion(-) diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index 301b7326aa83b..0ae0c0f77bfe6 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -401,7 +401,6 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void xparam->inputs.addr, xparam->inputs.addrlen); if (xparam->outputs.returncode == -1) { - fprintf(stderr, "sockerr %d\n", WSAGetLastError()); char *err = php_socket_strerror(php_socket_errno(), NULL, 0); php_error_docref(NULL, E_WARNING, "%s\n", err); From 59f541eea24e0098944f6fd22244ef798c513687 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 11 Mar 2020 10:16:04 +0100 Subject: [PATCH 3/3] Update main/network.c Co-Authored-By: Nikita Popov --- main/network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/network.c b/main/network.c index 2632a003ebfd1..f00c775c6f3fb 100644 --- a/main/network.c +++ b/main/network.c @@ -515,7 +515,7 @@ PHPAPI int php_network_parse_network_address_with_port(const char *addr, zend_lo memset(in6, 0, sizeof(struct sockaddr_in6)); #else - memset(sa, 0, sizeof(struct sockaddr)); + memset(in4, 0, sizeof(struct sockaddr_in)); #endif if (*addr == '[') {