From dc2ffdeed7d5c17eeb4f706f530eccafb425f92a Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 17 Jan 2019 18:05:13 +0000 Subject: [PATCH] Fix bug #77390 (feof might hang on TLS streams in case of fragmented TLS records) Simplified version of the fix from Abyl Valg so credit to him. --- NEWS | 4 ++++ ext/openssl/tests/bug77390.phpt | 11 ++++++++--- ext/openssl/xp_ssl.c | 34 +++++++++++++-------------------- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/NEWS b/NEWS index dbf4216bb5..3485917350 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,10 @@ PHP NEWS . Fixed bug #77361 (configure fails on 64-bit AIX when opcache enabled). (Kevin Adler) +- OpenSSL: + . Fixed bug #77390 (feof might hang on TLS streams in case of fragmented TLS + records). (Abyl Valg, Jakub Zelenka) + - PDO: . Fixed bug #77273 (array_walk_recursive corrupts value types leading to PDO failure). (Nikita) diff --git a/ext/openssl/tests/bug77390.phpt b/ext/openssl/tests/bug77390.phpt index d746a5d4aa..7f15329640 100644 --- a/ext/openssl/tests/bug77390.phpt +++ b/ext/openssl/tests/bug77390.phpt @@ -23,10 +23,16 @@ $clientCode = <<<'CODE' $read = [$fp]; $buf = ''; + $printed = false; while (stream_select($read, $write, $except, 1000)) { $chunk = stream_get_contents($fp, 4096); - var_dump($chunk); - $buf .= $chunk; + if ($chunk !== "") { + var_dump($chunk); + $buf .= $chunk; + } elseif (!$printed) { + $printed = true; + var_dump($chunk); + } if ($buf === 'hello, world') { break; } @@ -110,5 +116,4 @@ ServerClientTestCase::getInstance()->run($clientCode, [ ?> --EXPECT-- string(0) "" -string(0) "" string(12) "hello, world" diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index a5a4c4dbfb..5117eb2e99 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -2405,30 +2405,22 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val alive = 0; } else if (php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) { if (sslsock->ssl_active) { - int n; - - do { - n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf)); - if (n <= 0) { - int err = SSL_get_error(sslsock->ssl_handle, n); - - if (err == SSL_ERROR_SYSCALL) { + int n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf)); + if (n <= 0) { + int err = SSL_get_error(sslsock->ssl_handle, n); + switch (err) { + case SSL_ERROR_SYSCALL: alive = php_socket_errno() == EAGAIN; break; - } - - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { - /* re-negotiate */ - continue; - } - - /* any other problem is a fatal error */ - alive = 0; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + alive = 1; + break; + default: + /* any other problem is a fatal error */ + alive = 0; } - /* either peek succeeded or there was an error; we - * have set the alive flag appropriately */ - break; - } while (1); + } } else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EAGAIN) { alive = 0; } -- 2.40.0