From d39f78069dff496ec865c73aa44d7110e429bce9 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 23 Aug 2023 20:24:24 +0200
Subject: [PATCH] tree: Fix copying of DTDs

- Don't create multiple DTD nodes.
- Fix UAF if malloc fails.
- Skip DTD nodes if tree module is disabled.

Fixes #583.

CVE: CVE-2023-45322
Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxml2/-/commit/d39f78069dff496ec865c73aa44d7110e429bce9]

Signed-off-by: Peter Marko <peter.marko@siemens.com>
---
 tree.c | 31 ++++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/tree.c b/tree.c
index 6c8a875b9..02c1b5791 100644
--- a/tree.c
+++ b/tree.c
@@ -4471,29 +4471,28 @@ xmlNodePtr
 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
     xmlNodePtr ret = NULL;
     xmlNodePtr p = NULL,q;
+    xmlDtdPtr newSubset = NULL;
 
     while (node != NULL) {
-#ifdef LIBXML_TREE_ENABLED
 	if (node->type == XML_DTD_NODE ) {
-	    if (doc == NULL) {
+#ifdef LIBXML_TREE_ENABLED
+	    if ((doc == NULL) || (doc->intSubset != NULL)) {
 		node = node->next;
 		continue;
 	    }
-	    if (doc->intSubset == NULL) {
-		q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
-		if (q == NULL) goto error;
-		q->doc = doc;
-		q->parent = parent;
-		doc->intSubset = (xmlDtdPtr) q;
-		xmlAddChild(parent, q);
-	    } else {
-		q = (xmlNodePtr) doc->intSubset;
-		xmlAddChild(parent, q);
-	    }
-	} else
+            q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
+            if (q == NULL) goto error;
+            q->doc = doc;
+            q->parent = parent;
+            newSubset = (xmlDtdPtr) q;
+#else
+            node = node->next;
+            continue;
 #endif /* LIBXML_TREE_ENABLED */
+	} else {
 	    q = xmlStaticCopyNode(node, doc, parent, 1);
-	if (q == NULL) goto error;
+	    if (q == NULL) goto error;
+        }
 	if (ret == NULL) {
 	    q->prev = NULL;
 	    ret = p = q;
@@ -4505,6 +4504,8 @@ xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
 	}
 	node = node->next;
     }
+    if (newSubset != NULL)
+        doc->intSubset = newSubset;
     return(ret);
 error:
     xmlFreeNodeList(ret);
-- 
GitLab

