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:
@@ -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
23
ext/uri/tests/056.phpt
Normal 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==
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user