diff --git a/NEWS b/NEWS index 1dc9004d47f..a4e00693b90 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,9 @@ PHP NEWS - Core: . Fix GH-14978 (The xmlreader extension phpize build). (Peter Kokot) +- DOM: + . Fix trampoline leak in xpath callables. (nielsdos) + - OpenSSL: . Bumped minimum required OpenSSL version to 1.1.0. (cmb) @@ -16,6 +19,9 @@ PHP NEWS - Standard: . Fix references in request_parse_body() options array. (nielsdos) +- XSL: + . Fix trampoline leak in xpath callables. (nielsdos) + 18 Jul 2024, PHP 8.4.0alpha2 - Core: diff --git a/ext/dom/tests/registerPhpFunctionNS_errors.phpt b/ext/dom/tests/registerPhpFunctionNS_errors.phpt index 985376daee9..5098d8f7a84 100644 --- a/ext/dom/tests/registerPhpFunctionNS_errors.phpt +++ b/ext/dom/tests/registerPhpFunctionNS_errors.phpt @@ -5,6 +5,11 @@ dom --FILE-- loadHTML('hello'); @@ -16,6 +21,18 @@ try { echo $e->getMessage(), "\n"; } +try { + $xpath->registerPhpFunctionNS('http://php.net/xpath', 'test', [new TrampolineClass, 'test']); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +try { + $xpath->registerPhpFunctionNS('urn:foo', '$$$', [new TrampolineClass, 'test']); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + try { $xpath->registerPhpFunctionNS('urn:foo', 'x:a', strtolower(...)); } catch (ValueError $e) { @@ -37,6 +54,8 @@ try { ?> --EXPECT-- DOMXPath::registerPhpFunctionNS(): Argument #1 ($namespaceURI) must not be "http://php.net/xpath" because it is reserved by PHP +DOMXPath::registerPhpFunctionNS(): Argument #1 ($namespaceURI) must not be "http://php.net/xpath" because it is reserved by PHP +DOMXPath::registerPhpFunctionNS(): Argument #2 ($name) must be a valid callback name DOMXPath::registerPhpFunctionNS(): Argument #2 ($name) must be a valid callback name DOMXPath::registerPhpFunctionNS(): Argument #2 ($name) must not contain any null bytes DOMXPath::registerPhpFunctionNS(): Argument #1 ($namespaceURI) must not contain any null bytes diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c index f971a4193e0..33df515376d 100644 --- a/ext/dom/xpath.c +++ b/ext/dom/xpath.c @@ -462,11 +462,12 @@ PHP_METHOD(DOMXPath, registerPhpFunctionNS) ZEND_PARSE_PARAMETERS_END(); if (zend_string_equals_literal(namespace, "http://php.net/xpath")) { + zend_release_fcall_info_cache(&fcc); zend_argument_value_error(1, "must not be \"http://php.net/xpath\" because it is reserved by PHP"); RETURN_THROWS(); } - php_dom_xpath_callbacks_update_single_method_handler( + if (php_dom_xpath_callbacks_update_single_method_handler( &intern->xpath_callbacks, intern->dom.ptr, namespace, @@ -474,7 +475,9 @@ PHP_METHOD(DOMXPath, registerPhpFunctionNS) &fcc, PHP_DOM_XPATH_CALLBACK_NAME_VALIDATE_NCNAME, dom_xpath_register_func_in_ctx - ); + ) != SUCCESS) { + zend_release_fcall_info_cache(&fcc); + } } /* {{{ */ diff --git a/ext/xsl/tests/registerPHPFunctionNS_errors.phpt b/ext/xsl/tests/registerPHPFunctionNS_errors.phpt index 272e6d00adb..d8ccd52f5b3 100644 --- a/ext/xsl/tests/registerPHPFunctionNS_errors.phpt +++ b/ext/xsl/tests/registerPHPFunctionNS_errors.phpt @@ -5,6 +5,11 @@ xsl --FILE-- getMessage(), "\n"; } +try { + createProcessor([])->registerPhpFunctionNS('http://php.net/xsl', 'test', [new TrampolineClass, 'test']); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +try { + createProcessor([])->registerPhpFunctionNS('urn:foo', '$$$', [new TrampolineClass, 'test']); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + try { createProcessor([])->registerPhpFunctionNS('urn:foo', 'x:a', strtolower(...)); } catch (ValueError $e) { @@ -34,6 +51,8 @@ try { ?> --EXPECT-- XSLTProcessor::registerPHPFunctionNS(): Argument #1 ($namespaceURI) must not be "http://php.net/xsl" because it is reserved by PHP +XSLTProcessor::registerPHPFunctionNS(): Argument #1 ($namespaceURI) must not be "http://php.net/xsl" because it is reserved by PHP +XSLTProcessor::registerPHPFunctionNS(): Argument #2 ($name) must be a valid callback name XSLTProcessor::registerPHPFunctionNS(): Argument #2 ($name) must be a valid callback name XSLTProcessor::registerPHPFunctionNS(): Argument #2 ($name) must not contain any null bytes XSLTProcessor::registerPHPFunctionNS(): Argument #1 ($namespaceURI) must not contain any null bytes diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index 3ad528aa538..3dbb1ad16c9 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -707,11 +707,12 @@ PHP_METHOD(XSLTProcessor, registerPHPFunctionNS) ZEND_PARSE_PARAMETERS_END(); if (zend_string_equals_literal(namespace, "http://php.net/xsl")) { + zend_release_fcall_info_cache(&fcc); zend_argument_value_error(1, "must not be \"http://php.net/xsl\" because it is reserved by PHP"); RETURN_THROWS(); } - php_dom_xpath_callbacks_update_single_method_handler( + if (php_dom_xpath_callbacks_update_single_method_handler( &intern->xpath_callbacks, NULL, namespace, @@ -719,7 +720,9 @@ PHP_METHOD(XSLTProcessor, registerPHPFunctionNS) &fcc, PHP_DOM_XPATH_CALLBACK_NAME_VALIDATE_NCNAME, NULL - ); + ) != SUCCESS) { + zend_release_fcall_info_cache(&fcc); + } } /* {{{ */