1
0
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:
Tim Düsterhus
2025-08-31 14:45:31 +02:00
committed by GitHub
parent a544fe107e
commit 5e9080ff1b
3 changed files with 59 additions and 7 deletions

2
NEWS
View File

@@ -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
View 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

View File

@@ -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;