diff --git a/ext/standard/file.h b/ext/standard/file.h index 2b2307cab7278..0f3ccd7c27ab3 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -60,6 +60,12 @@ PHPAPI ssize_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, cha #define PHP_FILE_APPEND (1 << 3) #define PHP_FILE_NO_DEFAULT_CONTEXT (1 << 4) +#ifndef _WIN32 +#define PHP_TIMEOUT_ULL_MAX ULLONG_MAX +#else +#define PHP_TIMEOUT_ULL_MAX UINT64_MAX +#endif + typedef enum _php_meta_tags_token { TOK_EOF = 0, TOK_OPENTAG, diff --git a/ext/standard/fsock.c b/ext/standard/fsock.c index 9e1a53c0ec2a0..0ad0735906ebc 100644 --- a/ext/standard/fsock.c +++ b/ext/standard/fsock.c @@ -73,14 +73,27 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) } /* prepare the timeout value for use */ + if (timeout != -1.0 && !(timeout >= 0.0 && timeout <= (double) PHP_TIMEOUT_ULL_MAX / 1000000.0)) { + if (port > 0) { + efree(hostname); + } + + if (hashkey) { + efree(hashkey); + } + + zend_argument_value_error(6, "must be -1 or between 0 and " ZEND_ULONG_FMT, (PHP_TIMEOUT_ULL_MAX / 1000000.0)); + RETURN_THROWS(); + } else { #ifndef PHP_WIN32 - conv = (time_t) (timeout * 1000000.0); - tv.tv_sec = conv / 1000000; + conv = (time_t) (timeout * 1000000.0); + tv.tv_sec = conv / 1000000; #else - conv = (long) (timeout * 1000000.0); - tv.tv_sec = conv / 1000000; + conv = (long) (timeout * 1000000.0); + tv.tv_sec = conv / 1000000; #endif - tv.tv_usec = conv % 1000000; + tv.tv_usec = conv % 1000000; + } stream = php_stream_xport_create(hostname, hostname_len, REPORT_ERRORS, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, hashkey, &tv, NULL, &errstr, &err); diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 53fa8d33dad6b..7a0e82c7eb5a3 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -33,13 +33,11 @@ #ifndef PHP_WIN32 #define php_select(m, r, w, e, t) select(m, r, w, e, t) typedef unsigned long long php_timeout_ull; -#define PHP_TIMEOUT_ULL_MAX ULLONG_MAX #else #include "win32/select.h" #include "win32/sockets.h" #include "win32/console.h" typedef unsigned __int64 php_timeout_ull; -#define PHP_TIMEOUT_ULL_MAX UINT64_MAX #endif #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))) diff --git a/ext/standard/tests/streams/gh14780.phpt b/ext/standard/tests/streams/gh14780.phpt new file mode 100644 index 0000000000000..064e496b17538 --- /dev/null +++ b/ext/standard/tests/streams/gh14780.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-14780: p(f)sockopen overflow on timeout. +--SKIPIF-- + +--FILE-- +getMessage() . PHP_EOL; +} +try { + pfsockopen('udp://127.0.0.1', '63844', $code, $err, (PHP_INT_MIN/100000)-1); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +var_dump(pfsockopen('udp://127.0.0.1', '63844', $code, $err, -1)); +try { + pfsockopen('udp://127.0.0.1', '63844', $code, $err, NAN); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + pfsockopen('udp://127.0.0.1', '63844', $code, $err, INF); +} catch (\ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +pfsockopen(): Argument #6 must be -1 or between 0 and %s +pfsockopen(): Argument #6 must be -1 or between 0 and %s +resource(%d) of type (persistent stream) +pfsockopen(): Argument #6 must be -1 or between 0 and %s +pfsockopen(): Argument #6 must be -1 or between 0 and %s