[php-src] PHP-8.5: Merge branch 'PHP-8.4' into PHP-8.5

From: Date: Mon, 10 Aug 2026 19:18:20 +0000
Subject: [php-src] PHP-8.5: Merge branch 'PHP-8.4' into PHP-8.5
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-140610@lists.php.net to get a copy of this message
Author: Ilia Alshanetsky (iliaal) Date: 2026-08-10T15:15:26-04:00 Commit: https://github.com/php/php-src/commit/46b40957b172eb7bafcdd9e50d804004e485b2db Raw diff: https://github.com/php/php-src/commit/46b40957b172eb7bafcdd9e50d804004e485b2db.diff Merge branch 'PHP-8.4' into PHP-8.5 * PHP-8.4: Fix use-after-free when __clone() retains the stylesheet copy Changed paths: A ext/xsl/tests/importStylesheet_clone_retained_document.phpt A ext/xsl/tests/importStylesheet_clone_retained_node.phpt M NEWS M ext/xsl/xsltprocessor.c Diff: diff --git a/NEWS b/NEWS index ade754593071..299678d0a008 100644 --- a/NEWS +++ b/NEWS @@ -90,6 +90,10 @@ PHP NEWS . Fixed bug GH-15836 (Use-after-free when a user stream filter accesses $this->stream during the close flush). (iliaal) +- XSL: + . Fixed use-after-free when a DOMDocument subclass __clone() retains the + stylesheet copy made by XSLTProcessor::importStylesheet(). (iliaal) + 30 Jul 2026, PHP 8.5.9 - Core: diff --git a/ext/xsl/tests/importStylesheet_clone_retained_document.phpt b/ext/xsl/tests/importStylesheet_clone_retained_document.phpt new file mode 100644 index 000000000000..481925677d4e --- /dev/null +++ b/ext/xsl/tests/importStylesheet_clone_retained_document.phpt @@ -0,0 +1,47 @@ +--TEST-- +XSLTProcessor::importStylesheet() rejects a stylesheet whose __clone() retains the cloned document +--EXTENSIONS-- +dom +xsl +--FILE-- +<?php +const STYLESHEET = <<<XML +<?xml version="1.0"?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:template match="/"><out/></xsl:template> +</xsl:stylesheet> +XML; + +class Harmless extends DOMDocument { + public function __clone(): void { + } +} + +class RetainsDocument extends DOMDocument { + public function __clone(): void { + $GLOBALS['stash'] = $this; + } +} + +$doc = new Harmless; +$doc->loadXML(STYLESHEET); +$proc = new XSLTProcessor(); +var_dump($proc->importStylesheet($doc)); +unset($proc, $doc); + +$doc = new RetainsDocument; +$doc->loadXML(STYLESHEET); +$proc = new XSLTProcessor(); +try { + var_dump($proc->importStylesheet($doc)); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} +$kept = $GLOBALS['stash']; +unset($GLOBALS['stash'], $proc, $doc); +echo get_class($kept), " is still usable: ", $kept->documentElement->nodeName, PHP_EOL; +?> +--EXPECT-- +bool(true) +ValueError: XSLTProcessor::importStylesheet(): Argument #1 ($stylesheet) must not have its clone retained by __clone() +RetainsDocument is still usable: xsl:stylesheet diff --git a/ext/xsl/tests/importStylesheet_clone_retained_node.phpt b/ext/xsl/tests/importStylesheet_clone_retained_node.phpt new file mode 100644 index 000000000000..72c47b73b002 --- /dev/null +++ b/ext/xsl/tests/importStylesheet_clone_retained_node.phpt @@ -0,0 +1,34 @@ +--TEST-- +XSLTProcessor::importStylesheet() rejects a stylesheet whose __clone() retains a node of the cloned document +--EXTENSIONS-- +dom +xsl +--FILE-- +<?php +class RetainsElement extends DOMDocument { + public function __clone(): void { + $GLOBALS['stash'] = $this->documentElement; + } +} + +$doc = new RetainsElement; +$doc->loadXML(<<<XML +<?xml version="1.0"?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:template match="/"><out/></xsl:template> +</xsl:stylesheet> +XML); + +$proc = new XSLTProcessor(); +try { + var_dump($proc->importStylesheet($doc)); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} +$kept = $GLOBALS['stash']; +unset($GLOBALS['stash'], $proc, $doc); +echo get_class($kept), " is still usable: ", $kept->nodeName, PHP_EOL; +?> +--EXPECT-- +ValueError: XSLTProcessor::importStylesheet(): Argument #1 ($stylesheet) must not have its clone retained by __clone() +DOMElement is still usable: xsl:stylesheet diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index f7cffb2ed4ff..68ff9eb76ab6 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -227,6 +227,12 @@ PHP_METHOD(XSLTProcessor, importStylesheet) php_libxml_node_object *clone_lxml_obj = Z_LIBXML_NODE_P(&clone_zv); + if (GC_REFCOUNT(clone) > 1 || clone_lxml_obj->document->refcount > 1) { + OBJ_RELEASE(clone); + zend_argument_value_error(1, "must not have its clone retained by __clone()"); + RETURN_THROWS(); + } + PHP_LIBXML_SANITIZE_GLOBALS(parse); ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations") xmlSubstituteEntitiesDefault(1);

« previous php.cvs (#140610) next »