Skip to content

Commit d75c1d0

Browse files
committed
Fix GH-11175 and GH-11177: Stream socket timeout undefined behaviour
A negative value like -1 may overflow and cause incorrect results in the timeout variable, which causes an immediate timeout. As this is caused by undefined behaviour the exact behaviour depends on the compiler, its version, and the platform. A large overflow is also possible, if an extremely large timeout value is passed we also set an indefinite timeout. This is because the timeout value is at least a 64-bit number and waiting for UINT64_MAX/1000000 seconds is waiting about 584K years. Closes GH-11183.
1 parent 4ca8daf commit d75c1d0

File tree

2 files changed

+32
-12
lines changed

2 files changed

+32
-12
lines changed

NEWS

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ PHP NEWS
1717
. Fixed bug GH-11138 (move_uploaded_file() emits open_basedir warning for
1818
source file). (ilutov)
1919

20+
- Streams:
21+
. Fixed bug GH-11175 (Stream Socket Timeout). (nielsdos)
22+
. Fixed bug GH-11177 (ASAN UndefinedBehaviorSanitizer when timeout = -1
23+
passed to stream_socket_accept/stream_socket_client). (nielsdos)
24+
2025
11 May 2023, PHP 8.1.19
2126

2227
- Core:

ext/standard/streamsfuncs.c

+27-12
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@
3333
#ifndef PHP_WIN32
3434
#define php_select(m, r, w, e, t) select(m, r, w, e, t)
3535
typedef unsigned long long php_timeout_ull;
36+
#define PHP_TIMEOUT_ULL_MAX ULLONG_MAX
3637
#else
3738
#include "win32/select.h"
3839
#include "win32/sockets.h"
3940
#include "win32/console.h"
4041
typedef unsigned __int64 php_timeout_ull;
42+
#define PHP_TIMEOUT_ULL_MAX UINT64_MAX
4143
#endif
4244

4345
#define GET_CTX_OPT(stream, wrapper, name, val) (PHP_STREAM_CONTEXT(stream) && NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), wrapper, name)))
@@ -134,14 +136,21 @@ PHP_FUNCTION(stream_socket_client)
134136
}
135137

136138
/* prepare the timeout value for use */
137-
conv = (php_timeout_ull) (timeout * 1000000.0);
139+
struct timeval *tv_pointer;
140+
if (timeout < 0.0 || timeout >= (double) PHP_TIMEOUT_ULL_MAX / 1000000.0) {
141+
tv_pointer = NULL;
142+
} else {
143+
conv = (php_timeout_ull) (timeout * 1000000.0);
138144
#ifdef PHP_WIN32
139-
tv.tv_sec = (long)(conv / 1000000);
140-
tv.tv_usec =(long)(conv % 1000000);
145+
tv.tv_sec = (long)(conv / 1000000);
146+
tv.tv_usec = (long)(conv % 1000000);
141147
#else
142-
tv.tv_sec = conv / 1000000;
143-
tv.tv_usec = conv % 1000000;
148+
tv.tv_sec = conv / 1000000;
149+
tv.tv_usec = conv % 1000000;
144150
#endif
151+
tv_pointer = &tv;
152+
}
153+
145154
if (zerrno) {
146155
ZEND_TRY_ASSIGN_REF_LONG(zerrno, 0);
147156
}
@@ -152,7 +161,7 @@ PHP_FUNCTION(stream_socket_client)
152161
stream = php_stream_xport_create(ZSTR_VAL(host), ZSTR_LEN(host), REPORT_ERRORS,
153162
STREAM_XPORT_CLIENT | (flags & PHP_STREAM_CLIENT_CONNECT ? STREAM_XPORT_CONNECT : 0) |
154163
(flags & PHP_STREAM_CLIENT_ASYNC_CONNECT ? STREAM_XPORT_CONNECT_ASYNC : 0),
155-
hashkey, &tv, context, &errstr, &err);
164+
hashkey, tv_pointer, context, &errstr, &err);
156165

157166

158167
if (stream == NULL) {
@@ -275,19 +284,25 @@ PHP_FUNCTION(stream_socket_accept)
275284
php_stream_from_zval(stream, zstream);
276285

277286
/* prepare the timeout value for use */
278-
conv = (php_timeout_ull) (timeout * 1000000.0);
287+
struct timeval *tv_pointer;
288+
if (timeout < 0.0 || timeout >= (double) PHP_TIMEOUT_ULL_MAX / 1000000.0) {
289+
tv_pointer = NULL;
290+
} else {
291+
conv = (php_timeout_ull) (timeout * 1000000.0);
279292
#ifdef PHP_WIN32
280-
tv.tv_sec = (long)(conv / 1000000);
281-
tv.tv_usec = (long)(conv % 1000000);
293+
tv.tv_sec = (long)(conv / 1000000);
294+
tv.tv_usec = (long)(conv % 1000000);
282295
#else
283-
tv.tv_sec = conv / 1000000;
284-
tv.tv_usec = conv % 1000000;
296+
tv.tv_sec = conv / 1000000;
297+
tv.tv_usec = conv % 1000000;
285298
#endif
299+
tv_pointer = &tv;
300+
}
286301

287302
if (0 == php_stream_xport_accept(stream, &clistream,
288303
zpeername ? &peername : NULL,
289304
NULL, NULL,
290-
&tv, &errstr
305+
tv_pointer, &errstr
291306
) && clistream) {
292307

293308
if (peername) {

0 commit comments

Comments
 (0)