1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Merge branch 'PHP-8.3' into PHP-8.4

* PHP-8.3:
  Fix GH-19612: Mitigate libxml2 tree dictionary bug
This commit is contained in:
Niels Dossche
2025-09-03 21:53:56 +02:00
3 changed files with 64 additions and 15 deletions

3
NEWS
View File

@@ -15,6 +15,9 @@ PHP NEWS
. Fixed date_sunrise() and date_sunset() with partial-hour UTC offset.
(ilutov)
- DOM:
. Fixed bug GH-19612 (Mitigate libxml2 tree dictionary bug). (nielsdos)
- FPM:
. Fixed failed debug assertion when php_admin_value setting fails. (ilutov)

View File

@@ -1104,8 +1104,9 @@ static void php_dom_transfer_document_ref(xmlNodePtr node, php_libxml_ref_obj *n
}
}
/* Workaround for bug that was fixed in https://github.com/GNOME/libxml2/commit/4bc3ebf3eaba352fbbce2ef70ad00a3c7752478a */
#if LIBXML_VERSION < 21000
/* Workaround for bug that was fixed in https://github.com/GNOME/libxml2/commit/4bc3ebf3eaba352fbbce2ef70ad00a3c7752478a
* and https://github.com/GNOME/libxml2/commit/bc7ab5a2e61e4b36accf6803c5b0e245c11154b1 */
#if LIBXML_VERSION < 21300
static xmlChar *libxml_copy_dicted_string(xmlDictPtr src_dict, xmlDictPtr dst_dict, xmlChar *str)
{
if (str == NULL) {
@@ -1122,30 +1123,43 @@ static xmlChar *libxml_copy_dicted_string(xmlDictPtr src_dict, xmlDictPtr dst_di
static void libxml_fixup_name_and_content(xmlDocPtr src_doc, xmlDocPtr dst_doc, xmlNodePtr node)
{
if (src_doc != NULL && dst_doc != src_doc && src_doc->dict != NULL) {
if (node->type == XML_ENTITY_REF_NODE) {
node->children = NULL; /* Break link with original document. */
}
if (src_doc != NULL && src_doc->dict != NULL) {
ZEND_ASSERT(dst_doc != src_doc);
node->name = libxml_copy_dicted_string(src_doc->dict, dst_doc->dict, BAD_CAST node->name);
node->content = libxml_copy_dicted_string(src_doc->dict, NULL, node->content);
}
}
static void libxml_fixup_name_and_content_element(xmlDocPtr src_doc, xmlDocPtr dst_doc, xmlNodePtr node)
static void libxml_fixup_name_and_content_outer(xmlDocPtr src_doc, xmlDocPtr dst_doc, xmlNodePtr node)
{
libxml_fixup_name_and_content(src_doc, dst_doc, node);
for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) {
libxml_fixup_name_and_content(src_doc, dst_doc, (xmlNodePtr) attr);
if (node->type == XML_ELEMENT_NODE) {
for (xmlAttrPtr attr = node->properties; attr != NULL; attr = attr->next) {
libxml_fixup_name_and_content(src_doc, dst_doc, (xmlNodePtr) attr);
for (xmlNodePtr attr_child = attr->children; attr_child != NULL; attr_child = attr_child->next) {
libxml_fixup_name_and_content(src_doc, dst_doc, attr_child);
}
}
}
for (xmlNodePtr child = node->children; child != NULL; child = child->next) {
libxml_fixup_name_and_content_element(src_doc, dst_doc, child);
if (node->type == XML_ELEMENT_NODE || node->type == XML_ATTRIBUTE_NODE) {
for (xmlNodePtr child = node->children; child != NULL; child = child->next) {
libxml_fixup_name_and_content_outer(src_doc, dst_doc, child);
}
}
}
#endif
bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, xmlDocPtr new_document)
{
xmlDocPtr original_document = nodep->doc;
php_libxml_invalidate_node_list_cache_from_doc(original_document);
if (nodep->doc != new_document) {
xmlDocPtr old_doc = nodep->doc;
php_libxml_invalidate_node_list_cache_from_doc(old_doc);
if (old_doc != new_document) {
php_libxml_invalidate_node_list_cache(dom_object_new_document->document);
/* Note for ATTRIBUTE_NODE: specified is always true in ext/dom,
@@ -1155,16 +1169,18 @@ bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, x
xmlSetTreeDoc(nodep, new_document);
php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(dom_object_new_document);
php_dom_libxml_reconcile_modern(ns_mapper, nodep);
#if LIBXML_VERSION < 21000
libxml_fixup_name_and_content_element(original_document, new_document, nodep);
#endif
} else {
int ret = xmlDOMWrapAdoptNode(NULL, original_document, nodep, new_document, NULL, /* options, unused */ 0);
int ret = xmlDOMWrapAdoptNode(NULL, old_doc, nodep, new_document, NULL, /* options, unused */ 0);
if (UNEXPECTED(ret != 0)) {
return false;
}
}
#if LIBXML_VERSION < 21300
/* Must be first before transferring the ref to ensure the old document dictionary stays alive. */
libxml_fixup_name_and_content_outer(old_doc, new_document, nodep);
#endif
php_dom_transfer_document_ref(nodep, dom_object_new_document->document);
} else {
xmlUnlinkNode(nodep);

View File

@@ -0,0 +1,30 @@
--TEST--
GH-19612 (Mitigate libxml2 tree dictionary bug)
--EXTENSIONS--
dom
--FILE--
<?php
$xml = new DOMDocument;
$xml->loadXML(<<<XML
<!DOCTYPE root [
<!ENTITY foo "foo">
]>
<root><el x="&foo;"/></root>
XML);
$html = new DOMDocument;
$html->loadHTML('<p>foo</p>', LIBXML_NOERROR);
$p = $html->documentElement->firstChild->firstChild;
$p->appendChild($html->adoptNode($xml->documentElement->firstElementChild->cloneNode(true)));
echo $html->saveXML();
echo $xml->saveXML();
?>
--EXPECT--
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p>foo<el x="&foo;"/></p></body></html>
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY foo "foo">
]>
<root><el x="&foo;"/></root>