com php-src: Fix bug #74159: ext/openssl/tests/bug74159.phpt ext/openssl/xp_ssl.c

[email protected] (Aaron Piotrowski)
Newsgroups php.cvs
Message-ID <[email protected]>
Commit:    e9873d9853da2b6153776c2e5ed6858e87f0baa2
Author:    Aaron Piotrowski <[email protected]>         Thu, 23 Feb 2017 20:58:12 -0600
Parents:   330a7b62c3558aa987ee80e12f1914347d3a9eee
Branches:  PHP-7.0

Link:       http://git.php.net/?p=php-src.git;a=commitdiff;h=e9873d9853da2b6153776c2e5ed6858e87f0baa2

Log:
Fix bug #74159

Thanks to @brzuchal for the patch to xp_ssl.c and @DaveRandom for helping debug the problem.

Bugs:
https://bugs.php.net/74159

Changed paths:
  A  ext/openssl/tests/bug74159.phpt
  M  ext/openssl/xp_ssl.c


Diff:
diff --git a/ext/openssl/tests/bug74159.phpt b/ext/openssl/tests/bug74159.phpt
new file mode 100644
index 0000000..0299cf1
--- /dev/null
+++ b/ext/openssl/tests/bug74159.phpt
@@ -0,0 +1,106 @@
+--TEST--
+Bug #74159: Writing a large buffer to non-blocking encrypted streams fails
+--SKIPIF--
+<?php
+if (!extension_loaded("openssl")) die("skip openssl not loaded");
+if (!function_exists("proc_open")) die("skip no proc_open");
+--FILE--
+<?php
+$serverCode = <<<'CODE'
+    $serverUri = "ssl://127.0.0.1:64321";
+    $serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
+    $serverCtx = stream_context_create(['ssl' => [
+        'local_cert' => __DIR__ . '/bug54992.pem',
+        'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER,
+    ]]);
+
+    $server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx);
+    phpt_notify();
+
+    $client = stream_socket_accept($server, 1);
+
+    if (!$client) {
+        exit();
+    }
+
+    $data = '';
+    while (strlen($data) < 0xfffff) {
+        $buffer = fread($client, 8192);
+        if (empty($buffer)) {
+            exit();
+        }
+        $data .= $buffer;
+        usleep(100);
+    }
+    
+    fclose($client);
+CODE;
+
+$clientCode = <<<'CODE'
+    function streamRead($stream) : int {
+        return strlen(fread($stream, 8192));
+    }
+
+    function streamWrite($stream, $data) : int {
+        return fwrite($stream, $data);
+    }
+
+    function waitForWrite(...$streams) : bool {
+        $read = null;
+        $except = null;
+        while($streams && !($n = stream_select($read, $streams, $except, 1)));
+        return $n > 0;
+    }
+
+    function waitForRead(...$streams) : bool {
+        $write = null;
+        $except = null;
+        while ($streams && !($n = stream_select($streams, $write, $except, 1)));
+        return $n > 0;
+    }
+
+    set_error_handler(function ($errno, $errstr) {
+        exit("$errstr\n");
+    });
+
+    $serverUri = "tcp://127.0.0.1:64321";
+    $clientFlags = STREAM_CLIENT_CONNECT;
+    $clientCtx = stream_context_create(['ssl' => [
+        'verify_peer' => true,
+        'cafile' => __DIR__ . '/bug54992-ca.pem',
+        'peer_name' => 'bug54992.local',
+    ]]);
+
+    phpt_wait();
+
+    $fp = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx);
+
+    stream_set_blocking($fp, false);
+    while (0 === ($n = stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_ANY_CLIENT)));
+
+    $data = str_repeat("a", 0xfffff);
+    $written = 0;
+    $total = $written;
+    while(!empty($data)) {
+        $written = streamWrite($fp, $data);
+        $total += $written;
+        $data = substr($data, $written);
+        waitForWrite($fp);
+    }
+    printf("Written %d bytes\n", $total);
+
+    while(waitForRead($fp)) {
+        streamRead($fp);
+        if (feof($fp)) {
+            break;
+        }
+    }
+
+    exit("DONE\n");
+CODE;
+
+include 'ServerClientTestCase.inc';
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+--EXPECTF--
+Written 1048575 bytes
+DONE
diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
index b4387cd..9dd402a 100644
--- a/ext/openssl/xp_ssl.c
+++ b/ext/openssl/xp_ssl.c
@@ -1666,6 +1666,16 @@ int php_openssl_setup_crypto(php_stream *stream,
 		SSL_set_mode(sslsock->ssl_handle, mode | SSL_MODE_RELEASE_BUFFERS);
 	} while (0);
 #endif
+	
+	do {
+		long mode = SSL_get_mode(sslsock->ssl_handle);
+		SSL_set_mode(sslsock->ssl_handle, mode | SSL_MODE_ENABLE_PARTIAL_WRITE);
+	} while (0);
+	
+	do {
+		long mode = SSL_get_mode(sslsock->ssl_handle);
+		SSL_set_mode(sslsock->ssl_handle, mode | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+	} while (0);
 
 	if (cparam->inputs.session) {
 		if (cparam->inputs.session->ops != &php_openssl_socket_ops) {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.