1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-01-08 21:17:39 +03:00

Fix use-after-free with validating reader

Just like IDs, IDREF attributes must be removed from the document's
refs table when they're freed by a reader. This bug is often hidden
because xmlAttr structs are reused and strings are stored in a
dictionary unless XML_PARSE_NODICT is specified.

Found by OSS-Fuzz.
This commit is contained in:
Nick Wellnhofer 2020-06-08 12:49:51 +02:00
parent 00ed736eec
commit 2af3c2a8b9

View File

@ -278,6 +278,59 @@ xmlTextReaderRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
return(0);
}
/**
* xmlTextReaderWalkRemoveRef:
* @data: Contents of current link
* @user: Value supplied by the user
*
* Returns 0 to abort the walk or 1 to continue
*/
static int
xmlTextReaderWalkRemoveRef(const void *data, void *user)
{
xmlRefPtr ref = (xmlRefPtr)data;
xmlAttrPtr attr = (xmlAttrPtr)user;
if (ref->attr == attr) { /* Matched: remove and terminate walk */
ref->name = xmlStrdup(attr->name);
ref->attr = NULL;
return 0;
}
return 1;
}
/**
* xmlTextReaderRemoveRef:
* @doc: the document
* @attr: the attribute
*
* Remove the given attribute from the Ref table maintained internally.
*
* Returns -1 if the lookup failed and 0 otherwise
*/
static int
xmlTextReaderRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
xmlListPtr ref_list;
xmlRefTablePtr table;
xmlChar *ID;
if (doc == NULL) return(-1);
if (attr == NULL) return(-1);
table = (xmlRefTablePtr) doc->refs;
if (table == NULL)
return(-1);
ID = xmlNodeListGetString(doc, attr->children, 1);
if (ID == NULL)
return(-1);
ref_list = xmlHashLookup(table, ID);
xmlFree(ID);
if(ref_list == NULL)
return (-1);
xmlListWalk(ref_list, xmlTextReaderWalkRemoveRef, attr);
return(0);
}
/**
* xmlTextReaderFreeProp:
* @reader: the xmlTextReaderPtr used
@ -304,6 +357,8 @@ xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) {
(cur->parent->doc->extSubset != NULL))) {
if (xmlIsID(cur->parent->doc, cur->parent, cur))
xmlTextReaderRemoveID(cur->parent->doc, cur);
if (xmlIsRef(cur->parent->doc, cur->parent, cur))
xmlTextReaderRemoveRef(cur->parent->doc, cur);
}
if (cur->children != NULL)
xmlTextReaderFreeNodeList(reader, cur->children);