[libxml2] Fix use-after-free when XIncluding text from Reader



commit 847a3a1181d59dc49c1b446d646d344d0543af3e
Author: Nick Wellnhofer <wellnhofer aevum de>
Date:   Mon Sep 28 12:28:29 2020 +0200

    Fix use-after-free when XIncluding text from Reader
    
    The XML Reader can free text nodes coming from the XInclude engine
    before parsing has finished. Cache a copy of the text string, not the
    included node to avoid use after free.
    
    Found by OSS-Fuzz.

 xinclude.c | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)
---
diff --git a/xinclude.c b/xinclude.c
index f48e0af58..1636caff4 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -72,7 +72,7 @@ struct _xmlXIncludeCtxt {
 
     int                 txtNr; /* number of unparsed documents */
     int                txtMax; /* size of unparsed documents tab */
-    xmlNodePtr        *txtTab; /* array of unparsed text nodes */
+    xmlChar *         *txtTab; /* array of unparsed text strings */
     xmlURL         *txturlTab; /* array of unparsed text URLs */
 
     xmlChar *             url; /* the current URL processed */
@@ -393,18 +393,22 @@ xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
        if (ctxt->incTab[i] != NULL)
            xmlXIncludeFreeRef(ctxt->incTab[i]);
     }
+    if (ctxt->incTab != NULL)
+       xmlFree(ctxt->incTab);
+    if (ctxt->txtTab != NULL) {
+       for (i = 0;i < ctxt->txtNr;i++) {
+           if (ctxt->txtTab[i] != NULL)
+               xmlFree(ctxt->txtTab[i]);
+       }
+       xmlFree(ctxt->txtTab);
+    }
     if (ctxt->txturlTab != NULL) {
        for (i = 0;i < ctxt->txtNr;i++) {
            if (ctxt->txturlTab[i] != NULL)
                xmlFree(ctxt->txturlTab[i]);
        }
-    }
-    if (ctxt->incTab != NULL)
-       xmlFree(ctxt->incTab);
-    if (ctxt->txtTab != NULL)
-       xmlFree(ctxt->txtTab);
-    if (ctxt->txturlTab != NULL)
        xmlFree(ctxt->txturlTab);
+    }
     if (ctxt->base != NULL) {
         xmlFree(ctxt->base);
     }
@@ -764,13 +768,14 @@ xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
  * Add a new text node to the list
  */
 static void
-xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
+xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *txt,
+                  const xmlURL url) {
 #ifdef DEBUG_XINCLUDE
     xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
 #endif
     if (ctxt->txtMax == 0) {
        ctxt->txtMax = 4;
-        ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
+        ctxt->txtTab = (xmlChar **) xmlMalloc(ctxt->txtMax *
                                          sizeof(ctxt->txtTab[0]));
         if (ctxt->txtTab == NULL) {
            xmlXIncludeErrMemory(ctxt, NULL, "processing text");
@@ -785,7 +790,7 @@ xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
     }
     if (ctxt->txtNr >= ctxt->txtMax) {
        ctxt->txtMax *= 2;
-        ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
+        ctxt->txtTab = (xmlChar **) xmlRealloc(ctxt->txtTab,
                     ctxt->txtMax * sizeof(ctxt->txtTab[0]));
         if (ctxt->txtTab == NULL) {
            xmlXIncludeErrMemory(ctxt, NULL, "processing text");
@@ -798,7 +803,7 @@ xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
            return;
        }
     }
-    ctxt->txtTab[ctxt->txtNr] = txt;
+    ctxt->txtTab[ctxt->txtNr] = xmlStrdup(txt);
     ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
     ctxt->txtNr++;
 }
@@ -1845,7 +1850,7 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
      */
     for (i = 0; i < ctxt->txtNr; i++) {
        if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
-           node = xmlCopyNode(ctxt->txtTab[i], 1);
+            node = xmlNewText(ctxt->txtTab[i]);
            goto loaded;
        }
     }
@@ -1935,7 +1940,7 @@ xinclude_multibyte_fallback:
        xmlBufShrink(buf->buffer, len);
     }
     xmlFreeParserCtxt(pctxt);
-    xmlXIncludeAddTxt(ctxt, node, URL);
+    xmlXIncludeAddTxt(ctxt, node->content, URL);
     xmlFreeInputStream(inputStream);
 
 loaded:


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