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

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