]> granicus.if.org Git - php/commitdiff
Fix bug #77390 (feof might hang on TLS streams in case of fragmented TLS records)
authorJakub Zelenka <bukka@php.net>
Thu, 17 Jan 2019 18:05:13 +0000 (18:05 +0000)
committerJakub Zelenka <bukka@php.net>
Fri, 25 Jan 2019 14:13:11 +0000 (14:13 +0000)
Simplified version of the fix from Abyl Valg so credit to him.

NEWS
ext/openssl/tests/bug77390.phpt
ext/openssl/xp_ssl.c

diff --git a/NEWS b/NEWS
index dbf4216bb52b6041605191c6a40aafee10357687..348591735097896c1147e9e0ab3e4a4e747eb091 100644 (file)
--- 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)
index d746a5d4aac1b606ecd456f8817f1af2729c14c2..7f153296401f536b7a47646bbe816ee1d73f295f 100644 (file)
@@ -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"
index a5a4c4dbfb2cb3290331547d7a5f7243602d6790..5117eb2e99f4f90217a5fcd96287badb15501716 100644 (file)
@@ -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;
                                        }