Skip to content

Commit b9d3dbc

Browse files
committed
Merge branch 'bug72333' into PHP-7.0
2 parents 8e45583 + 960e5cd commit b9d3dbc

File tree

4 files changed

+130
-73
lines changed

4 files changed

+130
-73
lines changed

NEWS

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ PHP NEWS
1616
(somedaysummer)
1717

1818
- OpenSSL:
19-
. Fixed bug #74159 (Writing a large buffer to a non-blocking encrypted stream
20-
fails with "bad write retry"). (trowski)
19+
. Fixed bug #72333 (fwrite() on non-blocking SSL sockets doesn't work).
20+
(Jakub Zelenka)
2121

2222
- PDO MySQL:
2323
. Fixed bug #71003 (Expose MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT to PDO

ext/openssl/tests/bug72333.phpt

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
Bug #72333: fwrite() on non-blocking SSL sockets doesn't work
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("openssl")) die("skip openssl not loaded");
6+
if (!function_exists("proc_open")) die("skip no proc_open");
7+
?>
8+
--FILE--
9+
<?php
10+
$serverCode = <<<'CODE'
11+
$context = stream_context_create(['ssl' => ['local_cert' => __DIR__ . '/bug54992.pem']]);
12+
13+
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
14+
$fp = stream_socket_server("ssl://127.0.0.1:10011", $errornum, $errorstr, $flags, $context);
15+
phpt_notify();
16+
$conn = stream_socket_accept($fp);
17+
18+
for ($i = 0; $i < 5; $i++) {
19+
fread($conn, 100000);
20+
usleep(20000);
21+
}
22+
CODE;
23+
24+
$clientCode = <<<'CODE'
25+
$context = stream_context_create(['ssl' => ['verify_peer' => false, 'peer_name' => 'bug54992.local']]);
26+
27+
phpt_wait();
28+
$fp = stream_socket_client("ssl://127.0.0.1:10011", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT, $context);
29+
stream_set_blocking($fp, 0);
30+
31+
function blocking_fwrite($fp, $buf) {
32+
$write = [$fp];
33+
$total = 0;
34+
while (stream_select($read, $write, $except, 180)) {
35+
$result = fwrite($fp, $buf);
36+
$total += $result;
37+
if ($total >= strlen($buf)) {
38+
return $total;
39+
}
40+
$buf = substr($buf, $total);
41+
}
42+
}
43+
44+
$str1 = str_repeat("a", 5000000);
45+
blocking_fwrite($fp, $str1);
46+
echo "done";
47+
CODE;
48+
49+
include 'ServerClientTestCase.inc';
50+
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
51+
?>
52+
--EXPECT--
53+
done
54+

ext/openssl/tests/bug74159.phpt

Lines changed: 62 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,103 +4,109 @@ Bug #74159: Writing a large buffer to non-blocking encrypted streams fails
44
<?php
55
if (!extension_loaded("openssl")) die("skip openssl not loaded");
66
if (!function_exists("proc_open")) die("skip no proc_open");
7+
if (OPENSSL_VERSION_NUMBER < 0x10001001) die("skip OpenSSLv1.0.1 required");
8+
?>
79
--FILE--
810
<?php
11+
// the server code is doing many readings in a short interval which is
12+
// not really reliable on more powerful machine but cover different
13+
// scenarios which might be useful. More reliable test is bug72333.phpt
914
$serverCode = <<<'CODE'
10-
$serverUri = "ssl://127.0.0.1:64321";
11-
$serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
12-
$serverCtx = stream_context_create(['ssl' => [
13-
'local_cert' => __DIR__ . '/bug54992.pem',
14-
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER,
15-
]]);
15+
$serverUri = "ssl://127.0.0.1:10012";
16+
$serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
17+
$serverCtx = stream_context_create(['ssl' => [
18+
'local_cert' => __DIR__ . '/bug54992.pem',
19+
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER,
20+
]]);
1621
1722
$server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx);
18-
phpt_notify();
23+
phpt_notify();
1924
2025
$client = stream_socket_accept($server, 1);
2126
2227
if (!$client) {
23-
exit();
24-
}
28+
exit();
29+
}
2530
2631
$data = '';
27-
while (strlen($data) < 0xfffff) {
28-
$buffer = fread($client, 8192);
29-
if (empty($buffer)) {
30-
exit();
31-
}
32-
$data .= $buffer;
33-
usleep(100);
34-
}
35-
32+
while (strlen($data) < 0xfffff) {
33+
$buffer = fread($client, 8192);
34+
if (empty($buffer)) {
35+
exit();
36+
}
37+
$data .= $buffer;
38+
usleep(100);
39+
}
40+
3641
fclose($client);
3742
CODE;
3843

3944
$clientCode = <<<'CODE'
4045
function streamRead($stream) : int {
41-
return strlen(fread($stream, 8192));
42-
}
46+
return strlen(fread($stream, 8192));
47+
}
4348
4449
function streamWrite($stream, $data) : int {
45-
return fwrite($stream, $data);
46-
}
50+
return fwrite($stream, $data);
51+
}
4752
4853
function waitForWrite(...$streams) : bool {
49-
$read = null;
50-
$except = null;
51-
while($streams && !($n = stream_select($read, $streams, $except, 1)));
52-
return $n > 0;
53-
}
54+
$read = null;
55+
$except = null;
56+
while($streams && !($n = stream_select($read, $streams, $except, 1)));
57+
return $n > 0;
58+
}
5459
5560
function waitForRead(...$streams) : bool {
56-
$write = null;
57-
$except = null;
58-
while ($streams && !($n = stream_select($streams, $write, $except, 1)));
59-
return $n > 0;
60-
}
61+
$write = null;
62+
$except = null;
63+
while ($streams && !($n = stream_select($streams, $write, $except, 1)));
64+
return $n > 0;
65+
}
6166
6267
set_error_handler(function ($errno, $errstr) {
63-
exit("$errstr\n");
64-
});
68+
exit("$errstr\n");
69+
});
6570
66-
$serverUri = "tcp://127.0.0.1:64321";
67-
$clientFlags = STREAM_CLIENT_CONNECT;
68-
$clientCtx = stream_context_create(['ssl' => [
69-
'verify_peer' => true,
70-
'cafile' => __DIR__ . '/bug54992-ca.pem',
71-
'peer_name' => 'bug54992.local',
72-
]]);
71+
$serverUri = "tcp://127.0.0.1:10012";
72+
$clientFlags = STREAM_CLIENT_CONNECT;
73+
$clientCtx = stream_context_create(['ssl' => [
74+
'verify_peer' => true,
75+
'cafile' => __DIR__ . '/bug54992-ca.pem',
76+
'peer_name' => 'bug54992.local',
77+
]]);
7378
7479
phpt_wait();
7580
7681
$fp = stream_socket_client($serverUri, $errno, $errstr, 1, $clientFlags, $clientCtx);
7782
7883
stream_set_blocking($fp, false);
79-
while (0 === ($n = stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT)));
84+
while (0 === ($n = stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT)));
8085
8186
$data = str_repeat("a", 0xfffff);
82-
$written = 0;
83-
$total = $written;
84-
while(!empty($data)) {
85-
$written = streamWrite($fp, $data);
86-
$total += $written;
87-
$data = substr($data, $written);
88-
waitForWrite($fp);
89-
}
90-
printf("Written %d bytes\n", $total);
87+
$written = 0;
88+
$total = $written;
89+
while(!empty($data)) {
90+
$written = streamWrite($fp, $data);
91+
$total += $written;
92+
$data = substr($data, $written);
93+
waitForWrite($fp);
94+
}
95+
printf("Written %d bytes\n", $total);
9196
9297
while(waitForRead($fp)) {
93-
streamRead($fp);
94-
if (feof($fp)) {
95-
break;
96-
}
97-
}
98+
streamRead($fp);
99+
if (feof($fp)) {
100+
break;
101+
}
102+
}
98103
99104
exit("DONE\n");
100105
CODE;
101106

102107
include 'ServerClientTestCase.inc';
103108
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
109+
?>
104110
--EXPECTF--
105111
Written 1048575 bytes
106112
DONE

ext/openssl/xp_ssl.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,21 +1661,8 @@ int php_openssl_setup_crypto(php_stream *stream,
16611661
}
16621662

16631663
#ifdef SSL_MODE_RELEASE_BUFFERS
1664-
do {
1665-
long mode = SSL_get_mode(sslsock->ssl_handle);
1666-
SSL_set_mode(sslsock->ssl_handle, mode | SSL_MODE_RELEASE_BUFFERS);
1667-
} while (0);
1668-
#endif
1669-
1670-
do {
1671-
long mode = SSL_get_mode(sslsock->ssl_handle);
1672-
SSL_set_mode(sslsock->ssl_handle, mode | SSL_MODE_ENABLE_PARTIAL_WRITE);
1673-
} while (0);
1674-
1675-
do {
1676-
long mode = SSL_get_mode(sslsock->ssl_handle);
1677-
SSL_set_mode(sslsock->ssl_handle, mode | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
1678-
} while (0);
1664+
SSL_set_mode(sslsock->ssl_handle, SSL_get_mode(sslsock->ssl_handle) | SSL_MODE_RELEASE_BUFFERS);
1665+
#endif
16791666

16801667
if (cparam->inputs.session) {
16811668
if (cparam->inputs.session->ops != &php_openssl_socket_ops) {
@@ -1814,6 +1801,16 @@ static int php_openssl_enable_crypto(php_stream *stream,
18141801

18151802
if (SUCCESS == php_set_sock_blocking(sslsock->s.socket, 0)) {
18161803
sslsock->s.is_blocked = 0;
1804+
/* The following mode are added only if we are able to change socket
1805+
* to non blocking mode which is also used for read and write */
1806+
SSL_set_mode(
1807+
sslsock->ssl_handle,
1808+
(
1809+
SSL_get_mode(sslsock->ssl_handle) |
1810+
SSL_MODE_ENABLE_PARTIAL_WRITE |
1811+
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
1812+
)
1813+
);
18171814
}
18181815

18191816
timeout = sslsock->is_client ? &sslsock->connect_timeout : &sslsock->s.timeout;

0 commit comments

Comments
 (0)