[libxml2/fix-ownership-of-xmlAttrPtr-name-in-xmlSetTreeDoc] Fix ownership of xmlAttrPtr->name in xmlSetTreeDoc()




commit d3bdd9d73e10fab39e9643d60211a6720a73eb1d
Author: David Kilzer <ddkilzer apple com>
Date:   Sat Mar 19 17:17:40 2022 -0700

    Fix ownership of xmlAttrPtr->name in xmlSetTreeDoc()
    
    When changing `doc` on an xmlAttrPtr, the `name` field must
    either be a free-standing string, or it must be owned by
    `doc->dict` for the xmlAttrPtr.  The code to make this change
    was simply missing from xmlSetTreeDoc(), so the crash happened
    when an xmlAttrPtr was being torn down after `doc` changed from
    non-NULL to NULL, but the `name` field was not copied.  This is
    scenario 1 below.
    
    This change covers all cases of dictionary changes:
    1. Owned by old dictionary -> NULL new dictionary
       - Create free-standing copy of string.
    2. Owned by old dictionary -> Non-NULL new dictionary
       - Get string from new dictionary pool.
    3. Not owned by old dictionary -> Non-NULL new dictionary
       - Get string from new dictionary pool & free old copy.
    4. Not owned by old dictionary -> NULL new dictionary
       - No action necessary (already a free-standing string).
    
    Found by OSS-Fuzz Issue 45132.

 tree.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
---
diff --git a/tree.c b/tree.c
index 689a6b66..12aa2e9a 100644
--- a/tree.c
+++ b/tree.c
@@ -2833,7 +2833,19 @@ xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
                     xmlRemoveID(tree->doc, prop);
                 }
 
-               prop->doc = doc;
+                if (prop->doc != doc) {
+                    /* Update ownership of prop->name if prop->doc changes. */
+                    int oldPropDictOwnsName = (prop->doc != NULL) && (xmlDictOwns(prop->doc->dict, 
prop->name) == 1);
+                    const xmlChar *oldName = prop->name;
+                    if ((doc != NULL) && (doc->dict != NULL)) {
+                        prop->name = xmlDictLookup(doc->dict, oldName, -1);
+                        if (!oldPropDictOwnsName)
+                            xmlFree((void *)oldName);
+                    } else if (oldPropDictOwnsName)
+                        prop->name = xmlStrdup(oldName);
+
+                    prop->doc = doc;
+                }
                xmlSetListDoc(prop->children, doc);
 
                 /*


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]