diff --git a/ext/openssl/tests/gh13860.phpt b/ext/openssl/tests/gh13860.phpt new file mode 100644 index 0000000000000..b915760bee592 --- /dev/null +++ b/ext/openssl/tests/gh13860.phpt @@ -0,0 +1,49 @@ +--TEST-- +GH-13860 (Incorrect PHP_STREAM_OPTION_CHECK_LIVENESS case in ext/openssl/xp_ssl.c - causing use of dead socket) +--EXTENSIONS-- +openssl +--SKIPIF-- + +--FILE-- +run($clientCode, $serverCode); +?> +--EXPECT-- +bool(true) diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index e01d53656fe62..a0db38c20bc02 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -2575,8 +2575,20 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val php_set_sock_blocking(sslsock->s.socket, 1); sslsock->s.is_blocked = 1; } - } else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT) && php_socket_errno() != EAGAIN) { - alive = 0; + } else { +#ifdef PHP_WIN32 + int ret; +#else + ssize_t ret; +#endif + int err; + + ret = recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT); + err = php_socket_errno(); + if (0 == ret || /* the counterpart did properly shutdown */ + (0 > ret && err != EWOULDBLOCK && err != EAGAIN && err != EMSGSIZE)) { /* there was an unrecoverable error */ + alive = 0; + } } } return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;