mirror of
https://github.com/php/php-src.git
synced 2024-09-21 18:07:23 +00:00
Merge branch 'PHP-7.2' into PHP-7.3
This commit is contained in:
commit
0da13086bd
4
NEWS
4
NEWS
@ -16,6 +16,10 @@ PHP NEWS
|
||||
. Fixed bug #77287 (Opcache literal compaction is incompatible with EXT
|
||||
opcodes). (Nikita)
|
||||
|
||||
- OpenSSL:
|
||||
. Fixed bug #77390 (feof might hang on TLS streams in case of fragmented TLS
|
||||
records). (Abyl Valg, Jakub Zelenka)
|
||||
|
||||
07 Feb 2019, PHP 7.3.2
|
||||
|
||||
- Core:
|
||||
|
@ -2,14 +2,16 @@
|
||||
|
||||
const WORKER_ARGV_VALUE = 'RUN_WORKER';
|
||||
|
||||
function phpt_notify()
|
||||
const WORKER_DEFAULT_NAME = 'server';
|
||||
|
||||
function phpt_notify($worker = WORKER_DEFAULT_NAME)
|
||||
{
|
||||
ServerClientTestCase::getInstance()->notify();
|
||||
ServerClientTestCase::getInstance()->notify($worker);
|
||||
}
|
||||
|
||||
function phpt_wait()
|
||||
function phpt_wait($worker = WORKER_DEFAULT_NAME)
|
||||
{
|
||||
ServerClientTestCase::getInstance()->wait();
|
||||
ServerClientTestCase::getInstance()->wait($worker);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -20,11 +22,11 @@ class ServerClientTestCase
|
||||
{
|
||||
private $isWorker = false;
|
||||
|
||||
private $workerHandle;
|
||||
private $workerHandle = [];
|
||||
|
||||
private $workerStdIn;
|
||||
private $workerStdIn = [];
|
||||
|
||||
private $workerStdOut;
|
||||
private $workerStdOut = [];
|
||||
|
||||
private static $instance;
|
||||
|
||||
@ -46,26 +48,41 @@ class ServerClientTestCase
|
||||
$this->isWorker = $isWorker;
|
||||
}
|
||||
|
||||
private function spawnWorkerProcess($code)
|
||||
private function spawnWorkerProcess($worker, $code)
|
||||
{
|
||||
if (defined("PHP_WINDOWS_VERSION_MAJOR")) {
|
||||
$ini = php_ini_loaded_file();
|
||||
$cmd = sprintf('%s %s "%s" %s', PHP_BINARY, $ini ? "-n -c $ini" : "", __FILE__, WORKER_ARGV_VALUE);
|
||||
$ini = php_ini_loaded_file();
|
||||
$cmd = sprintf(
|
||||
'%s %s "%s" %s',
|
||||
PHP_BINARY, $ini ? "-n -c $ini" : "",
|
||||
__FILE__,
|
||||
WORKER_ARGV_VALUE
|
||||
);
|
||||
} else {
|
||||
$cmd = sprintf('%s "%s" %s', PHP_BINARY, __FILE__, WORKER_ARGV_VALUE);
|
||||
$cmd = sprintf(
|
||||
'%s "%s" %s %s',
|
||||
PHP_BINARY,
|
||||
__FILE__,
|
||||
WORKER_ARGV_VALUE,
|
||||
$worker
|
||||
);
|
||||
}
|
||||
$this->workerHandle = proc_open($cmd, [['pipe', 'r'], ['pipe', 'w'], STDERR], $pipes);
|
||||
$this->workerStdIn = $pipes[0];
|
||||
$this->workerStdOut = $pipes[1];
|
||||
$this->workerHandle[$worker] = proc_open(
|
||||
$cmd,
|
||||
[['pipe', 'r'], ['pipe', 'w'], STDERR],
|
||||
$pipes
|
||||
);
|
||||
$this->workerStdIn[$worker] = $pipes[0];
|
||||
$this->workerStdOut[$worker] = $pipes[1];
|
||||
|
||||
fwrite($this->workerStdIn, $code . "\n---\n");
|
||||
fwrite($this->workerStdIn[$worker], $code . "\n---\n");
|
||||
}
|
||||
|
||||
private function cleanupWorkerProcess()
|
||||
private function cleanupWorkerProcess($worker)
|
||||
{
|
||||
fclose($this->workerStdIn);
|
||||
fclose($this->workerStdOut);
|
||||
proc_close($this->workerHandle);
|
||||
fclose($this->workerStdIn[$worker]);
|
||||
fclose($this->workerStdOut[$worker]);
|
||||
proc_close($this->workerHandle[$worker]);
|
||||
}
|
||||
|
||||
private function stripPhpTagsFromCode($code)
|
||||
@ -90,21 +107,28 @@ class ServerClientTestCase
|
||||
eval($code);
|
||||
}
|
||||
|
||||
public function run($proc1Code, $proc2Code)
|
||||
public function run($masterCode, $workerCode)
|
||||
{
|
||||
$this->spawnWorkerProcess($this->stripPhpTagsFromCode($proc2Code));
|
||||
eval($this->stripPhpTagsFromCode($proc1Code));
|
||||
$this->cleanupWorkerProcess();
|
||||
if (!is_array($workerCode)) {
|
||||
$workerCode = [WORKER_DEFAULT_NAME => $workerCode];
|
||||
}
|
||||
foreach ($workerCode as $worker => $code) {
|
||||
$this->spawnWorkerProcess($worker, $this->stripPhpTagsFromCode($code));
|
||||
}
|
||||
eval($this->stripPhpTagsFromCode($masterCode));
|
||||
foreach ($workerCode as $worker => $code) {
|
||||
$this->cleanupWorkerProcess($worker);
|
||||
}
|
||||
}
|
||||
|
||||
public function wait()
|
||||
public function wait($worker)
|
||||
{
|
||||
fgets($this->isWorker ? STDIN : $this->workerStdOut);
|
||||
fgets($this->isWorker ? STDIN : $this->workerStdOut[$worker]);
|
||||
}
|
||||
|
||||
public function notify()
|
||||
public function notify($worker)
|
||||
{
|
||||
fwrite($this->isWorker ? STDOUT : $this->workerStdIn, "\n");
|
||||
fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
119
ext/openssl/tests/bug77390.phpt
Normal file
119
ext/openssl/tests/bug77390.phpt
Normal file
@ -0,0 +1,119 @@
|
||||
--TEST--
|
||||
Bug #76705: feof might hang on TLS streams in case of fragmented TLS records
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded("openssl")) die("skip openssl not loaded");
|
||||
if (!function_exists("proc_open")) die("skip no proc_open");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$certFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug77390.pem.tmp';
|
||||
$cacertFile = __DIR__ . DIRECTORY_SEPARATOR . 'bug77390-ca.pem.tmp';
|
||||
|
||||
$peerName = 'bug77390';
|
||||
$clientCode = <<<'CODE'
|
||||
$context = stream_context_create(['ssl' => ['verify_peer' => false, 'peer_name' => '%s']]);
|
||||
|
||||
phpt_wait('server');
|
||||
phpt_notify('proxy');
|
||||
|
||||
phpt_wait('proxy');
|
||||
$fp = stream_socket_client("ssl://127.0.0.1:10012", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT, $context);
|
||||
stream_set_blocking($fp, false);
|
||||
|
||||
$read = [$fp];
|
||||
$buf = '';
|
||||
$printed = false;
|
||||
while (stream_select($read, $write, $except, 1000)) {
|
||||
$chunk = stream_get_contents($fp, 4096);
|
||||
if ($chunk !== "") {
|
||||
var_dump($chunk);
|
||||
$buf .= $chunk;
|
||||
} elseif (!$printed) {
|
||||
$printed = true;
|
||||
var_dump($chunk);
|
||||
}
|
||||
if ($buf === 'hello, world') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
phpt_notify('server');
|
||||
phpt_notify('proxy');
|
||||
CODE;
|
||||
$clientCode = sprintf($clientCode, $peerName);
|
||||
|
||||
$serverCode = <<<'CODE'
|
||||
$context = stream_context_create(['ssl' => ['local_cert' => '%s']]);
|
||||
|
||||
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
|
||||
$fp = stream_socket_server("ssl://127.0.0.1:10011", $errornum, $errorstr, $flags, $context);
|
||||
phpt_notify();
|
||||
|
||||
$conn = stream_socket_accept($fp);
|
||||
fwrite($conn, 'hello, world');
|
||||
|
||||
phpt_wait();
|
||||
fclose($conn);
|
||||
CODE;
|
||||
$serverCode = sprintf($serverCode, $certFile);
|
||||
|
||||
$proxyCode = <<<'CODE'
|
||||
phpt_wait();
|
||||
|
||||
$upstream = stream_socket_client("tcp://127.0.0.1:10011", $errornum, $errorstr, 3000, STREAM_CLIENT_CONNECT);
|
||||
stream_set_blocking($upstream, false);
|
||||
|
||||
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
|
||||
$server = stream_socket_server("tcp://127.0.0.1:10012", $errornum, $errorstr, $flags);
|
||||
phpt_notify();
|
||||
|
||||
$conn = stream_socket_accept($server);
|
||||
stream_set_blocking($conn, false);
|
||||
|
||||
$read = [$upstream, $conn];
|
||||
while (stream_select($read, $write, $except, 1)) {
|
||||
foreach ($read as $fp) {
|
||||
$data = stream_get_contents($fp);
|
||||
if ($fp === $conn) {
|
||||
fwrite($upstream, $data);
|
||||
} else {
|
||||
if ($data !== '' && $data[0] === chr(23)) {
|
||||
$parts = str_split($data, (int) ceil(strlen($data) / 3));
|
||||
foreach ($parts as $part) {
|
||||
fwrite($conn, $part);
|
||||
usleep(1000);
|
||||
}
|
||||
} else {
|
||||
fwrite($conn, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (feof($upstream)) {
|
||||
break;
|
||||
}
|
||||
$read = [$upstream, $conn];
|
||||
}
|
||||
|
||||
phpt_wait();
|
||||
CODE;
|
||||
|
||||
include 'CertificateGenerator.inc';
|
||||
$certificateGenerator = new CertificateGenerator();
|
||||
$certificateGenerator->saveCaCert($cacertFile);
|
||||
$certificateGenerator->saveNewCertAsFileWithKey($peerName, $certFile);
|
||||
|
||||
include 'ServerClientTestCase.inc';
|
||||
ServerClientTestCase::getInstance()->run($clientCode, [
|
||||
'server' => $serverCode,
|
||||
'proxy' => $proxyCode,
|
||||
]);
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug77390.pem.tmp');
|
||||
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug77390-ca.pem.tmp');
|
||||
?>
|
||||
--EXPECT--
|
||||
string(0) ""
|
||||
string(12) "hello, world"
|
@ -2453,30 +2453,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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user