Blame SOURCES/libxml2-2.9.7-CVE-2022-23308.patch

9a491d
From 7f70302bfa9faeac9c9f7be8adf96d32c16acb72 Mon Sep 17 00:00:00 2001
9a491d
From: Nick Wellnhofer <wellnhofer@aevum.de>
9a491d
Date: Tue, 8 Feb 2022 03:29:24 +0100
9a491d
Subject: [PATCH] [CVE-2022-23308] Use-after-free of ID and IDREF attributes
9a491d
9a491d
If a document is parsed with XML_PARSE_DTDVALID and without
9a491d
XML_PARSE_NOENT, the value of ID attributes has to be normalized after
9a491d
potentially expanding entities in xmlRemoveID. Otherwise, later calls
9a491d
to xmlGetID can return a pointer to previously freed memory.
9a491d
9a491d
ID attributes which are empty or contain only whitespace after
9a491d
entity expansion are affected in a similar way. This is fixed by
9a491d
not storing such attributes in the ID table.
9a491d
9a491d
The test to detect streaming mode when validating against a DTD was
9a491d
broken. In connection with the defects above, this could result in a
9a491d
use-after-free when using the xmlReader interface with validation.
9a491d
Fix detection of streaming mode to avoid similar issues. (This changes
9a491d
the expected result of a test case. But as far as I can tell, using the
9a491d
XML reader with XIncludes referencing the root document never worked
9a491d
properly, anyway.)
9a491d
9a491d
All of these issues can result in denial of service. Using xmlReader
9a491d
with validation could result in disclosure of memory via the error
9a491d
channel, typically stderr. The security impact of xmlGetID returning
9a491d
a pointer to freed memory depends on the application. The typical use
9a491d
case of calling xmlGetID on an unmodified document is not affected.
9a491d
---
9a491d
 valid.c | 88 +++++++++++++++++++++++++++++++++++----------------------
9a491d
 1 file changed, 55 insertions(+), 33 deletions(-)
9a491d
9a491d
diff --git a/valid.c b/valid.c
9a491d
index a64b96be..5b81059f 100644
9a491d
--- a/valid.c
9a491d
+++ b/valid.c
9a491d
@@ -479,6 +479,35 @@ nodeVPop(xmlValidCtxtPtr ctxt)
9a491d
     return (ret);
9a491d
 }
9a491d
 
9a491d
+/**
9a491d
+ * xmlValidNormalizeString:
9a491d
+ * @str: a string
9a491d
+ *
9a491d
+ * Normalize a string in-place.
9a491d
+ */
9a491d
+static void
9a491d
+xmlValidNormalizeString(xmlChar *str) {
9a491d
+    xmlChar *dst;
9a491d
+    const xmlChar *src;
9a491d
+
9a491d
+    if (str == NULL)
9a491d
+        return;
9a491d
+    src = str;
9a491d
+    dst = str;
9a491d
+
9a491d
+    while (*src == 0x20) src++;
9a491d
+    while (*src != 0) {
9a491d
+	if (*src == 0x20) {
9a491d
+	    while (*src == 0x20) src++;
9a491d
+	    if (*src != 0)
9a491d
+		*dst++ = 0x20;
9a491d
+	} else {
9a491d
+	    *dst++ = *src++;
9a491d
+	}
9a491d
+    }
9a491d
+    *dst = 0;
9a491d
+}
9a491d
+
9a491d
 #ifdef DEBUG_VALID_ALGO
9a491d
 static void
9a491d
 xmlValidPrintNode(xmlNodePtr cur) {
9a491d
@@ -2546,6 +2575,24 @@ xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
9a491d
 	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
9a491d
 	    xmlFree((char *)(str));
9a491d
 
9a491d
+static int
9a491d
+xmlIsStreaming(xmlValidCtxtPtr ctxt) {
9a491d
+    xmlParserCtxtPtr pctxt;
9a491d
+
9a491d
+    if (ctxt == NULL)
9a491d
+        return(0);
9a491d
+    /*
9a491d
+     * These magic values are also abused to detect whether we're validating
9a491d
+     * while parsing a document. In this case, userData points to the parser
9a491d
+     * context.
9a491d
+     */
9a491d
+    if ((ctxt->finishDtd != XML_CTXT_FINISH_DTD_0) &&
9a491d
+        (ctxt->finishDtd != XML_CTXT_FINISH_DTD_1))
9a491d
+        return(0);
9a491d
+    pctxt = ctxt->userData;
9a491d
+    return(pctxt->parseMode == XML_PARSE_READER);
9a491d
+}
9a491d
+
9a491d
 /**
9a491d
  * xmlFreeID:
9a491d
  * @not:  A id
9a491d
@@ -2589,7 +2636,7 @@ xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
9a491d
     if (doc == NULL) {
9a491d
 	return(NULL);
9a491d
     }
9a491d
-    if (value == NULL) {
9a491d
+    if ((value == NULL) || (value[0] == 0)) {
9a491d
 	return(NULL);
9a491d
     }
9a491d
     if (attr == NULL) {
9a491d
@@ -2620,7 +2667,7 @@ xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
9a491d
      */
9a491d
     ret->value = xmlStrdup(value);
9a491d
     ret->doc = doc;
9a491d
-    if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
9a491d
+    if (xmlIsStreaming(ctxt)) {
9a491d
 	/*
9a491d
 	 * Operating in streaming mode, attr is gonna disapear
9a491d
 	 */
9a491d
@@ -2754,6 +2801,7 @@ xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
9a491d
     ID = xmlNodeListGetString(doc, attr->children, 1);
9a491d
     if (ID == NULL)
9a491d
         return(-1);
9a491d
+    xmlValidNormalizeString(ID);
9a491d
 
9a491d
     id = xmlHashLookup(table, ID);
9a491d
     if (id == NULL || id->attr != attr) {
9a491d
@@ -2942,7 +2990,7 @@ xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
9a491d
      * fill the structure.
9a491d
      */
9a491d
     ret->value = xmlStrdup(value);
9a491d
-    if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
9a491d
+    if (xmlIsStreaming(ctxt)) {
9a491d
 	/*
9a491d
 	 * Operating in streaming mode, attr is gonna disapear
9a491d
 	 */
9a491d
@@ -3962,8 +4010,7 @@ xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
9a491d
 xmlChar *
9a491d
 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
9a491d
 	     xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
9a491d
-    xmlChar *ret, *dst;
9a491d
-    const xmlChar *src;
9a491d
+    xmlChar *ret;
9a491d
     xmlAttributePtr attrDecl = NULL;
9a491d
     int extsubset = 0;
9a491d
 
9a491d
@@ -4004,19 +4051,7 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
9a491d
     ret = xmlStrdup(value);
9a491d
     if (ret == NULL)
9a491d
 	return(NULL);
9a491d
-    src = value;
9a491d
-    dst = ret;
9a491d
-    while (*src == 0x20) src++;
9a491d
-    while (*src != 0) {
9a491d
-	if (*src == 0x20) {
9a491d
-	    while (*src == 0x20) src++;
9a491d
-	    if (*src != 0)
9a491d
-		*dst++ = 0x20;
9a491d
-	} else {
9a491d
-	    *dst++ = *src++;
9a491d
-	}
9a491d
-    }
9a491d
-    *dst = 0;
9a491d
+    xmlValidNormalizeString(ret);
9a491d
     if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
9a491d
 	xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
9a491d
 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
9a491d
@@ -4048,8 +4083,7 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
9a491d
 xmlChar *
9a491d
 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
9a491d
 			        const xmlChar *name, const xmlChar *value) {
9a491d
-    xmlChar *ret, *dst;
9a491d
-    const xmlChar *src;
9a491d
+    xmlChar *ret;
9a491d
     xmlAttributePtr attrDecl = NULL;
9a491d
 
9a491d
     if (doc == NULL) return(NULL);
9a491d
@@ -4079,19 +4113,7 @@ xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
9a491d
     ret = xmlStrdup(value);
9a491d
     if (ret == NULL)
9a491d
 	return(NULL);
9a491d
-    src = value;
9a491d
-    dst = ret;
9a491d
-    while (*src == 0x20) src++;
9a491d
-    while (*src != 0) {
9a491d
-	if (*src == 0x20) {
9a491d
-	    while (*src == 0x20) src++;
9a491d
-	    if (*src != 0)
9a491d
-		*dst++ = 0x20;
9a491d
-	} else {
9a491d
-	    *dst++ = *src++;
9a491d
-	}
9a491d
-    }
9a491d
-    *dst = 0;
9a491d
+    xmlValidNormalizeString(ret);
9a491d
     return(ret);
9a491d
 }
9a491d
 
9a491d
-- 
9a491d
2.35.1
9a491d