1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2024-12-25 23:21:26 +03:00

valid: Make xmlValidateElement non-recursive

Fixes call stack overflows when validating deeply nested documents.

Found by OSS-Fuzz.
This commit is contained in:
Nick Wellnhofer 2023-03-16 17:01:05 +01:00
parent ca2bfecea9
commit 08f9d319eb

88
valid.c
View File

@ -6467,60 +6467,60 @@ name_ok:
*/
int
xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
xmlNodePtr child;
xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr root) {
xmlNodePtr elem;
xmlAttrPtr attr;
xmlNsPtr ns;
const xmlChar *value;
int ret = 1;
if (elem == NULL) return(0);
/*
* XInclude elements were added after parsing in the infoset,
* they don't really mean anything validation wise.
*/
if ((elem->type == XML_XINCLUDE_START) ||
(elem->type == XML_XINCLUDE_END) ||
(elem->type == XML_NAMESPACE_DECL))
return(1);
if (root == NULL) return(0);
CHECK_DTD;
/*
* Entities references have to be handled separately
*/
if (elem->type == XML_ENTITY_REF_NODE) {
return(1);
}
ret &= xmlValidateOneElement(ctxt, doc, elem);
if (elem->type == XML_ELEMENT_NODE) {
attr = elem->properties;
while (attr != NULL) {
value = xmlNodeListGetString(doc, attr->children, 0);
ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
if (value != NULL)
xmlFree((char *)value);
attr= attr->next;
}
ns = elem->nsDef;
while (ns != NULL) {
if (elem->ns == NULL)
ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
ns, ns->href);
else
ret &= xmlValidateOneNamespace(ctxt, doc, elem,
elem->ns->prefix, ns, ns->href);
ns = ns->next;
}
}
child = elem->children;
while (child != NULL) {
ret &= xmlValidateElement(ctxt, doc, child);
child = child->next;
elem = root;
while (1) {
ret &= xmlValidateOneElement(ctxt, doc, elem);
if (elem->type == XML_ELEMENT_NODE) {
attr = elem->properties;
while (attr != NULL) {
value = xmlNodeListGetString(doc, attr->children, 0);
ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
if (value != NULL)
xmlFree((char *)value);
attr= attr->next;
}
ns = elem->nsDef;
while (ns != NULL) {
if (elem->ns == NULL)
ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
ns, ns->href);
else
ret &= xmlValidateOneNamespace(ctxt, doc, elem,
elem->ns->prefix, ns,
ns->href);
ns = ns->next;
}
if (elem->children != NULL) {
elem = elem->children;
continue;
}
}
while (1) {
if (elem == root)
goto done;
if (elem->next != NULL)
break;
elem = elem->parent;
}
elem = elem->next;
}
done:
return(ret);
}