Skip to content

Commit 2aae14c

Browse files
committed
Fix GH-13860: Incorrect PHP_STREAM_OPTION_CHECK_LIVENESS case in ext/openssl/xp_ssl.c - causing use of dead socket
php_socket_errno() may return a stale value when recv returns a value >= 0. As such, the liveness check is wrong. This is the same bug as #70198 (fixed in GH-1456). So we fix it in the same way. Closes GH-13895.
1 parent 4a14211 commit 2aae14c

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed

NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ PHP NEWS
3232
- Streams:
3333
. Fixed bug GH-13264 (Part 1 - Memory leak on stream filter failure).
3434
(Jakub Zelenka)
35+
. Fixed bug GH-13860 (Incorrect PHP_STREAM_OPTION_CHECK_LIVENESS case in
36+
ext/openssl/xp_ssl.c - causing use of dead socket). (nielsdos)
3537

3638
- Treewide:
3739
. Fix gcc-14 Wcalloc-transposed-args warnings. (Cristian Rodríguez)

ext/openssl/tests/gh13860.phpt

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
--TEST--
2+
GH-13860 (Incorrect PHP_STREAM_OPTION_CHECK_LIVENESS case in ext/openssl/xp_ssl.c - causing use of dead socket)
3+
--EXTENSIONS--
4+
openssl
5+
--SKIPIF--
6+
<?php
7+
if (!function_exists("proc_open")) die("skip no proc_open");
8+
?>
9+
--FILE--
10+
<?php
11+
$serverCode = <<<'CODE'
12+
$serverUri = "tcp://127.0.0.1:64325";
13+
$serverFlags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
14+
$serverCtx = stream_context_create();
15+
16+
$server = stream_socket_server($serverUri, $errno, $errstr, $serverFlags, $serverCtx);
17+
phpt_notify();
18+
19+
$client = @stream_socket_accept($server);
20+
if ($client) {
21+
fwrite($client, "xx");
22+
phpt_wait();
23+
fclose($client);
24+
}
25+
CODE;
26+
27+
$clientCode = <<<'CODE'
28+
$serverUri = "tcp://127.0.0.1:64325";
29+
$clientFlags = STREAM_CLIENT_CONNECT;
30+
31+
phpt_wait();
32+
$fp = stream_socket_client($serverUri);
33+
stream_set_blocking($fp, false);
34+
35+
fread($fp, 2);
36+
37+
phpt_notify();
38+
while (!($in = fread($fp, 2))) {
39+
usleep(1000);
40+
}
41+
var_dump(feof($fp));
42+
fclose($fp);
43+
CODE;
44+
45+
include 'ServerClientTestCase.inc';
46+
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
47+
?>
48+
--EXPECT--
49+
bool(true)

ext/openssl/xp_ssl.c

+14-2
Original file line numberDiff line numberDiff line change
@@ -2575,8 +2575,20 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val
25752575
php_set_sock_blocking(sslsock->s.socket, 1);
25762576
sslsock->s.is_blocked = 1;
25772577
}
2578-
} else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT) && php_socket_errno() != EAGAIN) {
2579-
alive = 0;
2578+
} else {
2579+
#ifdef PHP_WIN32
2580+
int ret;
2581+
#else
2582+
ssize_t ret;
2583+
#endif
2584+
int err;
2585+
2586+
ret = recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK|MSG_DONTWAIT);
2587+
err = php_socket_errno();
2588+
if (0 == ret || /* the counterpart did properly shutdown */
2589+
(0 > ret && err != EWOULDBLOCK && err != EAGAIN && err != EMSGSIZE)) { /* there was an unrecoverable error */
2590+
alive = 0;
2591+
}
25802592
}
25812593
}
25822594
return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;

0 commit comments

Comments
 (0)