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