From: Simon Lees <sflees@suse.de>
Date: Fri, Mar 1 10:42:13
Subject: CVE-2023-52425 Additional parser fixes

In order for the backport of CVE-2023-52425 to pass the testsuite
some additional changes needed to be backported to xmlparse.c

===

Index: expat-2.4.4/lib/xmlparse.c
===================================================================
--- expat-2.4.4.orig/lib/xmlparse.c
+++ expat-2.4.4/lib/xmlparse.c
@@ -30,6 +30,10 @@
 #include <expat_config.h>
 #endif /* ndef COMPILED_FROM_DSP */
 
+#if ! defined(XML_CONTEXT_BYTES) || (1 - XML_CONTEXT_BYTES - 1 == 2)           \
+    || (XML_CONTEXT_BYTES + 0 < 0)
+#  error XML_CONTEXT_BYTES must be defined, non-empty and >=0 (0 to disable, >=1 to enable; 1024 is a common default)
+#endif
 #include "ascii.h"
 #include "expat.h"
 
@@ -2617,9 +2621,6 @@ doContent(XML_Parser parser, int startTa
         int len;
         const char *rawName;
         TAG *tag = tagStack;
-        tagStack = tag->parent;
-        tag->parent = freeTagList;
-        freeTagList = tag;
         rawName = s + enc->minBytesPerChar*2;
         len = XmlNameLength(enc, rawName);
         if (len != tag->rawNameLength
@@ -2627,6 +2628,9 @@ doContent(XML_Parser parser, int startTa
           *eventPP = rawName;
           return XML_ERROR_TAG_MISMATCH;
         }
+        tagStack = tag->parent;
+        tag->parent = freeTagList;
+        freeTagList = tag;
         --tagLevel;
         if (endElementHandler) {
           const XML_Char *localPart;
@@ -4016,9 +4020,9 @@ entityValueInitProcessor(XML_Parser pars
        then, when this routine is entered the next time, XmlPrologTok will
        return XML_TOK_INVALID, since the BOM is still in the buffer
     */
-    else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) {
+    else if (tok == XML_TOK_BOM) {
       *nextPtr = next;
-      return XML_ERROR_NONE;
+      s = next;
     }
     /* If we get this token, we have the start of what might be a
        normal tag, but not a declaration (i.e. it doesn't begin with
@@ -4494,10 +4498,10 @@ doProlog(XML_Parser parser, const ENCODI
           attlistDeclHandler(handlerArg, declElementType->name,
                              declAttributeId->name, declAttributeType,
                              0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
-          poolClear(&tempPool);
           handleDefault = XML_FALSE;
         }
       }
+      poolClear(&tempPool);
       break;
     case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
     case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
@@ -4487,6 +4491,9 @@ doProlog(XML_Parser parser, const ENCODI
       break;
     case XML_ROLE_ENTITY_VALUE:
       if (dtd->keepProcessing) {
+#ifdef XML_DTD
+        // This will store the given replacement text in
+        // parser->m_declEntity->textPtr.
         enum XML_Error result = storeEntityValue(parser, enc,
                                             s + enc->minBytesPerChar,
                                             next - enc->minBytesPerChar);
@@ -4554,6 +4561,25 @@ doProlog(XML_Parser parser, const ENCODI
           poolDiscard(&dtd->entityValuePool);
         if (result != XML_ERROR_NONE)
           return result;
+#else
+        // This will store "&amp;entity123;" in parser->m_declEntity->textPtr
+        // to end up as "&entity123;" in the handler.
+        if (parser->m_declEntity != NULL) {
+          const enum XML_Error result
+              = storeSelfEntityValue(parser, parser->m_declEntity);
+          if (result != XML_ERROR_NONE)
+            return result;
+
+          if (parser->m_entityDeclHandler) {
+            *eventEndPP = s;
+            parser->m_entityDeclHandler(
+                parser->m_handlerArg, parser->m_declEntity->name,
+                parser->m_declEntity->is_param, parser->m_declEntity->textPtr,
+                parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0);
+            handleDefault = XML_FALSE;
+          }
+        }
+#endif
       }
       break;
     case XML_ROLE_DOCTYPE_SYSTEM_ID:
@@ -4611,6 +4637,16 @@ doProlog(XML_Parser parser, const ENCODI
       }
       break;
     case XML_ROLE_ENTITY_COMPLETE:
+#ifndef XML_DTD
+      // This will store "&amp;entity123;" in entity->textPtr
+      // to end up as "&entity123;" in the handler.
+      if (parser->m_declEntity != NULL) {
+        const enum XML_Error result
+            = storeSelfEntityValue(parser, parser->m_declEntity);
+        if (result != XML_ERROR_NONE)
+          return result;
+      }
+#endif
       if (dtd->keepProcessing && declEntity && entityDeclHandler) {
         *eventEndPP = s;
         entityDeclHandler(handlerArg,
@@ -5304,6 +5340,14 @@ internalEntityProcessor(XML_Parser parse
     /* put openEntity back in list of free instances */
     openEntity->next = freeInternalEntities;
     freeInternalEntities = openEntity;
+
+  }
+  // If there are more open entities we want to stop right here and have the
+  // upcoming call to XML_ResumeParser continue with entity content, or it would
+  // be ignored altogether.
+  if (parser->m_openInternalEntities != NULL
+      && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
+    return XML_ERROR_NONE;
   }
 
 #ifdef XML_DTD
@@ -6000,6 +6043,10 @@ getContext(XML_Parser parser) {
 static XML_Bool
 setContext(XML_Parser parser, const XML_Char *context)
 {
+  if (context == NULL) {
+    return XML_FALSE;
+  }
+
   DTD * const dtd = _dtd;  /* save one level of indirection */
   const XML_Char *s = context;
 
