From 25b9e0fdb0f69b59e6d9a75fad1431308bf1b871 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 5 Apr 2024 23:21:32 +0200 Subject: [PATCH] Fix GH-13860: Incorrect PHP_STREAM_OPTION_CHECK_LIVENESS case in ext/openssl/xp_ssl.c - causing use of dead socket php_socket_errno() may return a stale value when recv returns a value >= 0. As such, the liveness check is wrong. This is the same bug as #70198 (fixed in GH-1456). So we fix it in the same way. --- ext/openssl/tests/gh13860.phpt | 49 ++++++++++++++++++++++++++++++++++ ext/openssl/xp_ssl.c | 16 +++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 ext/openssl/tests/gh13860.phpt diff --git a/ext/openssl/tests/gh13860.phpt b/ext/openssl/tests/gh13860.phpt new file mode 100644 index 000000000000..b915760bee59 --- /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 e01d53656fe6..a0db38c20bc0 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;