From 4ba39a639dedc179f1396f5f6e05d72586f7f30c Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 24 Oct 2026 03:36:10 +0100 Subject: [PATCH] ext/dom: fix UAF on namespace axis results with foreign-doc XPath callback nodes Follow-up to https://github.com/php/php-src/pull/24570#issuecomment-6375965729 The namespace node branch of php_xpath_eval() still created the parent element with the DOMXPath's own dom, so with a foreign-doc callback node the parent proxy referenced the wrong document. Use dom_xpath_intern_for_doc() there too. --- ...p_function_foreign_doc_namespace_axis.phpt | 36 +++++++++++++++++++ ext/dom/xpath.c | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 ext/dom/tests/xpath_php_function_foreign_doc_namespace_axis.phpt diff --git a/ext/dom/tests/xpath_php_function_foreign_doc_namespace_axis.phpt b/ext/dom/tests/xpath_php_function_foreign_doc_namespace_axis.phpt new file mode 100644 index 000000000000..ad77a052d454 --- /dev/null +++ b/ext/dom/tests/xpath_php_function_foreign_doc_namespace_axis.phpt @@ -0,0 +1,36 @@ +--TEST-- +DOMXPath: namespace axis result on a node from a document created inside an XPath callback +--EXTENSIONS-- +dom +--FILE-- +loadXML(''); + +$xp = new DOMXPath($doc); +$xp->registerNamespace('my', 'my.ns'); +$xp->registerPHPFunctionNS('my.ns', 'include', function () { + $d = new DOMDocument; + $d->loadXML(''); + return $d->documentElement; +}); + +$result = $xp->query('my:include()/uaf/namespace::*'); +var_dump($result->length); +unset($xp); + +foreach ($result as $ns) { + var_dump($ns->nodeName, $ns->parentNode->nodeName); +} + +echo "Done\n"; + +?> +--EXPECT-- +int(2) +string(9) "xmlns:xml" +string(3) "uaf" +string(7) "xmlns:a" +string(3) "uaf" +Done diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c index a9832f4c3e22..af5d7eacc2ed 100644 --- a/ext/dom/xpath.c +++ b/ext/dom/xpath.c @@ -411,7 +411,7 @@ static void php_xpath_eval(INTERNAL_FUNCTION_PARAMETERS, int type, bool modern) /* Make sure parent dom object exists, so we can take an extra reference. */ zval parent_zval; /* don't destroy me, my lifetime is transfered to the fake namespace decl */ - php_dom_create_object(nsparent, &parent_zval, &intern->dom); + php_dom_create_object(nsparent, &parent_zval, dom_xpath_intern_for_doc(intern, nsparent->doc)); dom_object *parent_intern = Z_DOMOBJ_P(&parent_zval); node = php_dom_create_fake_namespace_decl(nsparent, original, &child, parent_intern);