[php-src] master: Merge branch 'PHP-8.5'

From: Date: Mon, 10 Aug 2026 19:18:23 +0000
Subject: [php-src] master: Merge branch 'PHP-8.5'
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-140609@lists.php.net to get a copy of this message
Author: Ilia Alshanetsky (iliaal) Date: 2026-08-10T15:15:51-04:00 Commit: https://github.com/php/php-src/commit/c8682fb61af207c09c71bcded7fe5ba7b17d4a5e Raw diff: https://github.com/php/php-src/commit/c8682fb61af207c09c71bcded7fe5ba7b17d4a5e.diff Merge branch 'PHP-8.5' * PHP-8.5: 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 7bbc50fcccfe..4ed01591ea4c 100644 --- a/NEWS +++ b/NEWS @@ -108,6 +108,10 @@ PHP NEWS . Io\Poll\Context::wait() now takes a Time\Duration object as a timeout. (timwolla) +- XSL: + . Fixed use-after-free when a DOMDocument subclass __clone() retains the + stylesheet copy made by XSLTProcessor::importStylesheet(). (iliaal) + 30 Jul 2026, PHP 8.6.0alpha3 - 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 230c7bd39cc2..5d24ab1ec873 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -216,6 +216,12 @@ PHP_METHOD(XSLTProcessor, importStylesheet) newdoc = nodep->doc; 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 (#140609) next »