Skip to content

Commit ba909d7

Browse files
committed
Fix GH-14780: p(f)sockopen overflow on timeout argument.
close GH-14785
1 parent 40551dd commit ba909d7

File tree

5 files changed

+63
-7
lines changed

5 files changed

+63
-7
lines changed

NEWS

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ PHP NEWS
3232

3333
- Standard:
3434
. Fix passing non-finite timeout values in stream functions. (nielsdos)
35+
. Fixed GH-14780 p(f)sockopen timeout overflow. (David Carlier)
3536

3637
- Streams:
3738
. Fixed bug GH-15028 (Memory leak in ext/phar/stream.c). (nielsdos)

ext/standard/file.h

+6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ PHPAPI ssize_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, cha
6060
#define PHP_FILE_APPEND (1 << 3)
6161
#define PHP_FILE_NO_DEFAULT_CONTEXT (1 << 4)
6262

63+
#ifndef _WIN32
64+
#define PHP_TIMEOUT_ULL_MAX ULLONG_MAX
65+
#else
66+
#define PHP_TIMEOUT_ULL_MAX UINT64_MAX
67+
#endif
68+
6369
typedef enum _php_meta_tags_token {
6470
TOK_EOF = 0,
6571
TOK_OPENTAG,

ext/standard/fsock.c

+18-5
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,27 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
7373
}
7474

7575
/* prepare the timeout value for use */
76+
if (timeout != -1.0 && !(timeout >= 0.0 && timeout <= (double) PHP_TIMEOUT_ULL_MAX / 1000000.0)) {
77+
if (port > 0) {
78+
efree(hostname);
79+
}
80+
81+
if (hashkey) {
82+
efree(hashkey);
83+
}
84+
85+
zend_argument_value_error(6, "must be -1 or between 0 and " ZEND_ULONG_FMT, (PHP_TIMEOUT_ULL_MAX / 1000000.0));
86+
RETURN_THROWS();
87+
} else {
7688
#ifndef PHP_WIN32
77-
conv = (time_t) (timeout * 1000000.0);
78-
tv.tv_sec = conv / 1000000;
89+
conv = (time_t) (timeout * 1000000.0);
90+
tv.tv_sec = conv / 1000000;
7991
#else
80-
conv = (long) (timeout * 1000000.0);
81-
tv.tv_sec = conv / 1000000;
92+
conv = (long) (timeout * 1000000.0);
93+
tv.tv_sec = conv / 1000000;
8294
#endif
83-
tv.tv_usec = conv % 1000000;
95+
tv.tv_usec = conv % 1000000;
96+
}
8497

8598
stream = php_stream_xport_create(hostname, hostname_len, REPORT_ERRORS,
8699
STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, hashkey, &tv, NULL, &errstr, &err);

ext/standard/streamsfuncs.c

-2
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,11 @@
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
3736
#else
3837
#include "win32/select.h"
3938
#include "win32/sockets.h"
4039
#include "win32/console.h"
4140
typedef unsigned __int64 php_timeout_ull;
42-
#define PHP_TIMEOUT_ULL_MAX UINT64_MAX
4341
#endif
4442

4543
#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)))
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
GH-14780: p(f)sockopen overflow on timeout.
3+
--SKIPIF--
4+
<?php
5+
if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only");
6+
?>
7+
--FILE--
8+
<?php
9+
$code = null;
10+
$err = null;
11+
try {
12+
pfsockopen('udp://127.0.0.1', '63844', $code, $err, (PHP_INT_MAX/100000)+1);
13+
} catch (\ValueError $e) {
14+
echo $e->getMessage() . PHP_EOL;
15+
}
16+
try {
17+
pfsockopen('udp://127.0.0.1', '63844', $code, $err, (PHP_INT_MIN/100000)-1);
18+
} catch (\ValueError $e) {
19+
echo $e->getMessage() . PHP_EOL;
20+
}
21+
var_dump(pfsockopen('udp://127.0.0.1', '63844', $code, $err, -1));
22+
try {
23+
pfsockopen('udp://127.0.0.1', '63844', $code, $err, NAN);
24+
} catch (\ValueError $e) {
25+
echo $e->getMessage() . PHP_EOL;
26+
}
27+
try {
28+
pfsockopen('udp://127.0.0.1', '63844', $code, $err, INF);
29+
} catch (\ValueError $e) {
30+
echo $e->getMessage();
31+
}
32+
?>
33+
--EXPECTF--
34+
pfsockopen(): Argument #6 must be -1 or between 0 and %s
35+
pfsockopen(): Argument #6 must be -1 or between 0 and %s
36+
resource(%d) of type (persistent stream)
37+
pfsockopen(): Argument #6 must be -1 or between 0 and %s
38+
pfsockopen(): Argument #6 must be -1 or between 0 and %s

0 commit comments

Comments
 (0)