1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

uri: Fix lexbor memory management in uri_parser_whatwg.c (#19591)

Calling `lexbor_mraw_clean()` after a specific number of parses will destroy
the data for any live `Uri\WhatWg\Url` objects, effectively resulting in a
use-after-free.

Fix the issue by removing the periodic `lexbor_mraw_clean()` call.  Instead we
implement `php_uri_parser_whatwg_free()`. This also requires to move the
destruction of the lexbor structures from RSHUTDOWN to POST_ZEND_DEACTIVATE to
prevent a use-after-free in `php_uri_parser_whatwg_free()` since otherwise the
mraw would already have been destroyed.
This commit is contained in:
Tim Düsterhus
2025-08-26 23:17:21 +02:00
committed by GitHub
parent 90822f7692
commit 423960aad3
4 changed files with 35 additions and 23 deletions

View File

@@ -1089,9 +1089,9 @@ PHP_RINIT_FUNCTION(uri)
return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(uri)
ZEND_MODULE_POST_ZEND_DEACTIVATE_D(uri)
{
if (PHP_RSHUTDOWN(uri_parser_whatwg)(INIT_FUNC_ARGS_PASSTHRU) == FAILURE) {
if (ZEND_MODULE_POST_ZEND_DEACTIVATE_N(uri_parser_whatwg)() == FAILURE) {
return FAILURE;
}
@@ -1106,8 +1106,10 @@ zend_module_entry uri_module_entry = {
PHP_MINIT(uri), /* PHP_MINIT - Module initialization */
PHP_MSHUTDOWN(uri), /* PHP_MSHUTDOWN - Module shutdown */
PHP_RINIT(uri), /* PHP_RINIT - Request initialization */
PHP_RSHUTDOWN(uri), /* PHP_RSHUTDOWN - Request shutdown */
NULL, /* PHP_RSHUTDOWN - Request shutdown */
PHP_MINFO(uri), /* PHP_MINFO - Module info */
PHP_VERSION, /* Version */
STANDARD_MODULE_PROPERTIES
NO_MODULE_GLOBALS,
ZEND_MODULE_POST_ZEND_DEACTIVATE_N(uri),
STANDARD_MODULE_PROPERTIES_EX
};

23
ext/uri/tests/056.phpt Normal file
View File

@@ -0,0 +1,23 @@
--TEST--
Test Lexbor memory management
--EXTENSIONS--
uri
--FILE--
<?php
$urls = [];
for ($i = 0; $i < 1000; $i++) {
$urls[] = Uri\WhatWg\Url::parse("https://example.com/{$i}/");
}
for ($i = 0; $i < 1000; $i++) {
if ($urls[$i]->toAsciiString() !== "https://example.com/{$i}/") {
die("FAIL");
}
}
?>
==DONE==
--EXPECT--
==DONE==

View File

@@ -27,9 +27,7 @@
ZEND_TLS lexbor_mraw_t lexbor_mraw = {0};
ZEND_TLS lxb_url_parser_t lexbor_parser = {0};
ZEND_TLS lxb_unicode_idna_t lexbor_idna = {0};
ZEND_TLS unsigned short int parsed_urls;
static const unsigned short int maximum_parses_before_cleanup = 500;
static const size_t lexbor_mraw_byte_size = 8192;
static zend_always_inline void zval_string_or_null_to_lexbor_str(zval *value, lexbor_str_t *lexbor_str)
@@ -530,8 +528,6 @@ PHP_RINIT_FUNCTION(uri_parser_whatwg)
goto fail;
}
parsed_urls = 0;
return SUCCESS;
fail:
@@ -548,7 +544,7 @@ PHP_RINIT_FUNCTION(uri_parser_whatwg)
return FAILURE;
}
PHP_RSHUTDOWN_FUNCTION(uri_parser_whatwg)
ZEND_MODULE_POST_ZEND_DEACTIVATE_D(uri_parser_whatwg)
{
lxb_unicode_idna_destroy(&lexbor_idna, false);
memset(&lexbor_idna, 0, sizeof(lexbor_idna));
@@ -557,24 +553,12 @@ PHP_RSHUTDOWN_FUNCTION(uri_parser_whatwg)
lexbor_mraw_destroy(&lexbor_mraw, false);
memset(&lexbor_mraw, 0, sizeof(lexbor_mraw));
parsed_urls = 0;
return SUCCESS;
}
static void reset_parser_state(void)
{
if (++parsed_urls % maximum_parses_before_cleanup == 0) {
lexbor_mraw_clean(lexbor_parser.mraw);
parsed_urls = 0;
}
lxb_url_parser_clean(&lexbor_parser);
}
lxb_url_t *php_uri_parser_whatwg_parse_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent)
{
reset_parser_state();
lxb_url_parser_clean(&lexbor_parser);
lxb_url_t *url = lxb_url_parse(&lexbor_parser, lexbor_base_url, (unsigned char *) uri_str, uri_str_len);
const char *reason = fill_errors(errors);
@@ -624,6 +608,9 @@ static zend_string *php_uri_parser_whatwg_to_string(void *uri, uri_recomposition
static void php_uri_parser_whatwg_free(void *uri)
{
lxb_url_t *lexbor_uri = uri;
lxb_url_destroy(lexbor_uri);
}
const uri_parser_t php_uri_parser_whatwg = {

View File

@@ -25,6 +25,6 @@ extern const uri_parser_t php_uri_parser_whatwg;
lxb_url_t *php_uri_parser_whatwg_parse_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent);
PHP_RINIT_FUNCTION(uri_parser_whatwg);
PHP_RSHUTDOWN_FUNCTION(uri_parser_whatwg);
ZEND_MODULE_POST_ZEND_DEACTIVATE_D(uri_parser_whatwg);
#endif