mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
uri: Reject ports overflowing zend_long for uri_parser_rfc3986 (#19644)
RFC 3986 technically allows arbitrarily large integers as port numbers, but our implementation is unable to deal with that, since it expects the port to fit `zend_long`, reject those explicitly instead of misinterpreting them.
This commit is contained in:
2
NEWS
2
NEWS
@@ -25,6 +25,8 @@ PHP NEWS
|
||||
(timwolla)
|
||||
. Fixed double-free when assigning to $errors fails when using
|
||||
the Uri\WhatWg\Url parser. (timwolla)
|
||||
. Reject out-of-range ports when using the Uri\Rfc3986\Uri parser.
|
||||
(timwolla)
|
||||
. Clean up naming of internal API. (timwolla)
|
||||
|
||||
28 Aug 2025, PHP 8.5.0beta2
|
||||
|
||||
32
ext/uri/tests/058.phpt
Normal file
32
ext/uri/tests/058.phpt
Normal file
@@ -0,0 +1,32 @@
|
||||
--TEST--
|
||||
Test that integer overflows in the port are rejected
|
||||
--EXTENSIONS--
|
||||
uri
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
if (PHP_INT_SIZE == 8) {
|
||||
$uri = new \Uri\Rfc3986\Uri('https://example.com:9223372036854775807');
|
||||
echo $uri->getPort(), PHP_EOL;
|
||||
echo "2147483647", PHP_EOL;
|
||||
} else {
|
||||
$uri = new \Uri\Rfc3986\Uri('https://example.com:2147483647');
|
||||
echo "9223372036854775807", PHP_EOL;
|
||||
echo $uri->getPort(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
if (PHP_INT_SIZE == 8) {
|
||||
new \Uri\Rfc3986\Uri('https://example.com:9223372036854775808');
|
||||
} else {
|
||||
new \Uri\Rfc3986\Uri('https://example.com:2147483648');
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
echo $e::class, ": ", $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
9223372036854775807
|
||||
2147483647
|
||||
Uri\InvalidUriException: The port is out of range
|
||||
@@ -190,15 +190,22 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_host_read(const
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
ZEND_ATTRIBUTE_NONNULL static size_t str_to_int(const char *str, size_t len)
|
||||
ZEND_ATTRIBUTE_NONNULL static zend_long port_str_to_zend_long_checked(const char *str, size_t len)
|
||||
{
|
||||
size_t result = 0;
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
result = result * 10 + (str[i] - '0');
|
||||
if (len > MAX_LENGTH_OF_LONG) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
char buf[MAX_LENGTH_OF_LONG + 1];
|
||||
*(char*)zend_mempcpy(buf, str, len) = 0;
|
||||
|
||||
zend_ulong result = ZEND_STRTOUL(buf, NULL, 10);
|
||||
|
||||
if (result > ZEND_LONG_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (zend_long)result;
|
||||
}
|
||||
|
||||
ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_port_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
|
||||
@@ -206,7 +213,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_port_read(const
|
||||
const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode);
|
||||
|
||||
if (has_text_range(&uriparser_uri->portText)) {
|
||||
ZVAL_LONG(retval, str_to_int(uriparser_uri->portText.first, get_text_range_length(&uriparser_uri->portText)));
|
||||
ZVAL_LONG(retval, port_str_to_zend_long_checked(uriparser_uri->portText.first, get_text_range_length(&uriparser_uri->portText)));
|
||||
} else {
|
||||
ZVAL_NULL(retval);
|
||||
}
|
||||
@@ -319,6 +326,17 @@ php_uri_parser_rfc3986_uris *php_uri_parser_rfc3986_parse_ex(const char *uri_str
|
||||
/* Make the resulting URI independent of the 'uri_str'. */
|
||||
uriMakeOwnerMmA(&uri, mm);
|
||||
|
||||
if (
|
||||
has_text_range(&uri.portText)
|
||||
&& port_str_to_zend_long_checked(uri.portText.first, get_text_range_length(&uri.portText)) == -1
|
||||
) {
|
||||
if (!silent) {
|
||||
zend_throw_exception(uri_invalid_uri_exception_ce, "The port is out of range", 0);
|
||||
}
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
php_uri_parser_rfc3986_uris *uriparser_uris = uriparser_create_uris();
|
||||
uriparser_uris->uri = uri;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user