[php-src] master: Merge branch 'PHP-8.5'
Ilia Alshanetsky <[email protected]>
| Newsgroups | gmane.comp.php.cvs.general |
|---|---|
| Message-ID | <[email protected]> |
Author: Ilia Alshanetsky (iliaal)
Date: 2026-08-18T14:48:17-04:00
Commit: https://github.com/php/php-src/commit/5210969d096de4f0db2717eb4b03da1802dd9302
Raw diff: https://github.com/php/php-src/commit/5210969d096de4f0db2717eb4b03da1802dd9302.diff
Merge branch 'PHP-8.5'
* PHP-8.5:
Fix UAF when setAttributeNS() frees a wrapped attribute child
Changed paths:
A ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt
M NEWS
M ext/dom/element.c
Diff:
diff --git a/NEWS b/NEWS
index ea09c13c2b1c..91406b2905c6 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,8 @@ PHP NEWS
and a later callback returns a node from another document. (iliaal)
. Fixed bug GH-23331 (UAF when node_list_unlink() skips attribute children
that still have a live wrapper). (iliaal)
+ . Fixed a use-after-free when Dom\Element::setAttributeNS() replaces the
+ value of an attribute whose child still has a live wrapper. (iliaal)
- PDO_PGSQL:
. Fixed several lazy fetch (PDO::ATTR_PREFETCH => 0) defects: an infinite
diff --git a/ext/dom/element.c b/ext/dom/element.c
index 2a0aa3a4d0e7..354466623ca4 100644
--- a/ext/dom/element.c
+++ b/ext/dom/element.c
@@ -1057,6 +1057,10 @@ static void dom_set_attribute_ns_modern(dom_object *intern, xmlNodePtr elemp, ze
if (errorcode == 0) {
php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(intern);
xmlNsPtr ns = php_dom_libxml_ns_mapper_get_ns_raw_prefix_string(ns_mapper, prefix, xmlStrlen(prefix), uri);
+ xmlNodePtr existing = (xmlNodePtr) xmlHasNsProp(elemp, localname, ns == NULL ? NULL : ns->href);
+ if (existing != NULL && existing->type != XML_ATTRIBUTE_DECL) {
+ node_list_unlink(existing->children);
+ }
xmlAttrPtr attr = xmlSetNsProp(elemp, ns, localname, BAD_CAST value);
if (UNEXPECTED(attr == NULL)) {
php_dom_throw_error(INVALID_STATE_ERR, /* strict */ true);
diff --git a/ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt b/ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt
new file mode 100644
index 000000000000..22475c33cf88
--- /dev/null
+++ b/ext/dom/tests/modern/common/Element_setAttributeNS_live_child.phpt
@@ -0,0 +1,37 @@
+--TEST--
+setAttributeNS() keeps an attribute child that still has a live wrapper
+--EXTENSIONS--
+dom
+--FILE--
+<?php
+
+$doc = Dom\XMLDocument::createFromString('<root xmlns:p="urn:x" p:attr="old"/>');
+$el = $doc->documentElement;
+$text = $el->getAttributeNodeNS('urn:x', 'attr')->firstChild;
+$el->setAttributeNS('urn:x', 'p:attr', 'new');
+echo "prefixed, detached: ";
+var_dump($text->parentNode === null);
+echo "prefixed, text: ";
+var_dump($text->textContent);
+echo "prefixed, new value: ";
+var_dump($el->getAttributeNS('urn:x', 'attr'));
+
+$doc = Dom\XMLDocument::createFromString('<root attr="old"/>');
+$el = $doc->documentElement;
+$text = $el->getAttributeNode('attr')->firstChild;
+$el->setAttributeNS(null, 'attr', 'new');
+echo "no namespace, detached: ";
+var_dump($text->parentNode === null);
+echo "no namespace, text: ";
+var_dump($text->textContent);
+echo "no namespace, new value: ";
+var_dump($el->getAttribute('attr'));
+
+?>
+--EXPECT--
+prefixed, detached: bool(true)
+prefixed, text: string(3) "old"
+prefixed, new value: string(3) "new"
+no namespace, detached: bool(true)
+no namespace, text: string(3) "old"
+no namespace, new value: string(3) "new"