• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1From 08f9d319ebe99f41f71336ea01767b9c652ef34f Mon Sep 17 00:00:00 2001
2From: Nick Wellnhofer <wellnhofer@aevum.de>
3Date: Thu, 16 Mar 2023 17:01:05 +0100
4Subject: [PATCH] valid: Make xmlValidateElement non-recursive
5
6Fixes call stack overflows when validating deeply nested documents.
7
8Found by OSS-Fuzz.
9
10Reference:https://github.com/GNOME/libxml2/commit/08f9d319ebe99f41f71336ea01767b9c652ef34f
11Conflict:NA
12
13---
14 valid.c | 86 ++++++++++++++++++++++++++++-----------------------------
15 1 file changed, 43 insertions(+), 43 deletions(-)
16
17diff --git a/valid.c b/valid.c
18index 9a2c708..3c0a869 100644
19--- a/valid.c
20+++ b/valid.c
21@@ -6480,60 +6480,60 @@ name_ok:
22  */
23
24 int
25-xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
26-    xmlNodePtr child;
27+xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr root) {
28+    xmlNodePtr elem;
29     xmlAttrPtr attr;
30     xmlNsPtr ns;
31     const xmlChar *value;
32     int ret = 1;
33
34-    if (elem == NULL) return(0);
35-
36-    /*
37-     * XInclude elements were added after parsing in the infoset,
38-     * they don't really mean anything validation wise.
39-     */
40-    if ((elem->type == XML_XINCLUDE_START) ||
41-	(elem->type == XML_XINCLUDE_END) ||
42-	(elem->type == XML_NAMESPACE_DECL))
43-	return(1);
44+    if (root == NULL) return(0);
45
46     CHECK_DTD;
47
48-    /*
49-     * Entities references have to be handled separately
50-     */
51-    if (elem->type == XML_ENTITY_REF_NODE) {
52-	return(1);
53-    }
54+    elem = root;
55+    while (1) {
56+        ret &= xmlValidateOneElement(ctxt, doc, elem);
57+
58+        if (elem->type == XML_ELEMENT_NODE) {
59+            attr = elem->properties;
60+            while (attr != NULL) {
61+                value = xmlNodeListGetString(doc, attr->children, 0);
62+                ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
63+                if (value != NULL)
64+                    xmlFree((char *)value);
65+                attr= attr->next;
66+            }
67
68-    ret &= xmlValidateOneElement(ctxt, doc, elem);
69-    if (elem->type == XML_ELEMENT_NODE) {
70-	attr = elem->properties;
71-	while (attr != NULL) {
72-	    value = xmlNodeListGetString(doc, attr->children, 0);
73-	    ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
74-	    if (value != NULL)
75-		xmlFree((char *)value);
76-	    attr= attr->next;
77-	}
78-	ns = elem->nsDef;
79-	while (ns != NULL) {
80-	    if (elem->ns == NULL)
81-		ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
82-					       ns, ns->href);
83-	    else
84-		ret &= xmlValidateOneNamespace(ctxt, doc, elem,
85-		                               elem->ns->prefix, ns, ns->href);
86-	    ns = ns->next;
87-	}
88-    }
89-    child = elem->children;
90-    while (child != NULL) {
91-        ret &= xmlValidateElement(ctxt, doc, child);
92-        child = child->next;
93+            ns = elem->nsDef;
94+            while (ns != NULL) {
95+                if (elem->ns == NULL)
96+                    ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
97+                                                   ns, ns->href);
98+                else
99+                    ret &= xmlValidateOneNamespace(ctxt, doc, elem,
100+                                                   elem->ns->prefix, ns,
101+                                                   ns->href);
102+                ns = ns->next;
103+            }
104+
105+            if (elem->children != NULL) {
106+                elem = elem->children;
107+                continue;
108+            }
109+        }
110+
111+        while (1) {
112+            if (elem == root)
113+                goto done;
114+            if (elem->next != NULL)
115+                break;
116+            elem = elem->parent;
117+        }
118+        elem = elem->next;
119     }
120
121+done:
122     return(ret);
123 }
124
125--
1262.27.0
127
128