diff --git a/expat-2.5.0-CVE-2026-50219.patch b/expat-2.5.0-CVE-2026-50219.patch new file mode 100644 index 0000000..8bb888a --- /dev/null +++ b/expat-2.5.0-CVE-2026-50219.patch @@ -0,0 +1,1473 @@ +From a9fad8a0b77939c4f511481bfbd65dc59556616f Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 15:15:10 +0200 +Subject: [PATCH 01/34] lib: Introduce handler call depth tracking + +--- + expat/lib/xmlparse.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index d7d815e8..fdbb1697 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -744,6 +744,7 @@ struct XML_ParserStruct { + ENTITY_STATS m_entity_stats; + #endif + XML_Bool m_reenter; ++ unsigned m_handlerCallDepth; + }; + + # define MALLOC(parser, s) (expat_malloc((parser), (s), __LINE__)) +@@ -1185,6 +1186,23 @@ get_hash_secret_salt(XML_Parser parser) { + return parser->m_hash_secret_salt; + } + ++static void ++beforeHandler(XML_Parser parser) { ++ assert(parser->m_handlerCallDepth < UINT_MAX); ++ parser->m_handlerCallDepth++; ++} ++ ++static void ++afterHandler(XML_Parser parser) { ++ assert(parser->m_handlerCallDepth > 0); ++ parser->m_handlerCallDepth--; ++} ++ ++static bool ++isCalledFromInsideHandler(XML_Parser parser) { ++ return parser->m_handlerCallDepth > 0; ++} ++ + static enum XML_Error + callProcessor(XML_Parser parser, const char *start, const char *end, + const char **endPtr) { +@@ -1520,6 +1538,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) { + parser->m_parsingStatus.parsing = XML_INITIALIZED; + // Reentry can only be triggered inside m_processor calls + parser->m_reenter = XML_FALSE; ++ parser->m_handlerCallDepth = 0; + #ifdef XML_DTD + parser->m_isParamEntity = XML_FALSE; + parser->m_useForeignDTD = XML_FALSE; + +From 6b860f034d1ba3bedca60e912d8f2699c17633ac Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:33:26 +0200 +Subject: [PATCH 02/34] lib: Prepare `m_notStandaloneHandler` calls for + upcoming wrapping + +--- + expat/lib/xmlparse.c | 34 ++++++++++++++++++++++------------ + 1 file changed, 22 insertions(+), 12 deletions(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index fdbb1697..b70fbca5 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -5356,9 +5356,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + entity->systemId, entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { +- if (! dtd->standalone && parser->m_notStandaloneHandler +- && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) +- return XML_ERROR_NOT_STANDALONE; ++ if (! dtd->standalone && parser->m_notStandaloneHandler) { ++ const int handlerStatus ++ = parser->m_notStandaloneHandler(parser->m_handlerArg); ++ if (! handlerStatus) ++ return XML_ERROR_NOT_STANDALONE; ++ } + } + /* if we didn't read the foreign DTD then this means that there + is no external subset and we must reset dtd->hasParamEntityRefs +@@ -5396,9 +5399,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + entity->systemId, entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { +- if (! dtd->standalone && parser->m_notStandaloneHandler +- && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) +- return XML_ERROR_NOT_STANDALONE; ++ if (! dtd->standalone && parser->m_notStandaloneHandler) { ++ const int handlerStatus ++ = parser->m_notStandaloneHandler(parser->m_handlerArg); ++ if (! handlerStatus) ++ return XML_ERROR_NOT_STANDALONE; ++ } + } + /* if we didn't read the foreign DTD then this means that there + is no external subset and we must reset dtd->hasParamEntityRefs +@@ -5586,9 +5592,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + #ifdef XML_DTD + && ! parser->m_paramEntityParsing + #endif /* XML_DTD */ +- && parser->m_notStandaloneHandler +- && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) +- return XML_ERROR_NOT_STANDALONE; ++ && parser->m_notStandaloneHandler) { ++ const int status = parser->m_notStandaloneHandler(parser->m_handlerArg); ++ if (! status) ++ return XML_ERROR_NOT_STANDALONE; ++ } + #ifndef XML_DTD + break; + #else /* XML_DTD */ +@@ -5968,9 +5976,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + } + } + #endif /* XML_DTD */ +- if (! dtd->standalone && parser->m_notStandaloneHandler +- && ! parser->m_notStandaloneHandler(parser->m_handlerArg)) +- return XML_ERROR_NOT_STANDALONE; ++ if (! dtd->standalone && parser->m_notStandaloneHandler) { ++ const int status = parser->m_notStandaloneHandler(parser->m_handlerArg); ++ if (! status) ++ return XML_ERROR_NOT_STANDALONE; ++ } + break; + + /* Element declaration stuff */ + +From e2eecbe2903594b7c7730dd0b6b32a37754e7168 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Sat, 30 May 2026 00:45:34 +0200 +Subject: [PATCH 03/34] lib: Prepare `m_externalEntityRefHandler` calls for + upcoming wrapping + +--- + expat/lib/xmlparse.c | 35 ++++++++++++++++++++--------------- + 1 file changed, 20 insertions(+), 15 deletions(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index b70fbca5..6bbc0b5f 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -3381,9 +3381,10 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + entity->open = XML_FALSE; + if (! context) + return XML_ERROR_NO_MEMORY; +- if (! parser->m_externalEntityRefHandler( +- parser->m_externalEntityRefHandlerArg, context, entity->base, +- entity->systemId, entity->publicId)) ++ const int status = parser->m_externalEntityRefHandler( ++ parser->m_externalEntityRefHandlerArg, context, entity->base, ++ entity->systemId, entity->publicId); ++ if (! status) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + poolDiscard(&parser->m_tempPool); + } else if (parser->m_defaultHandler) +@@ -5351,9 +5352,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + if (parser->m_useForeignDTD) + entity->base = parser->m_curBase; + dtd->paramEntityRead = XML_FALSE; +- if (! parser->m_externalEntityRefHandler( +- parser->m_externalEntityRefHandlerArg, 0, entity->base, +- entity->systemId, entity->publicId)) ++ const int status = parser->m_externalEntityRefHandler( ++ parser->m_externalEntityRefHandlerArg, 0, entity->base, ++ entity->systemId, entity->publicId); ++ if (! status) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (! dtd->standalone && parser->m_notStandaloneHandler) { +@@ -5394,9 +5396,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + return XML_ERROR_NO_MEMORY; + entity->base = parser->m_curBase; + dtd->paramEntityRead = XML_FALSE; +- if (! parser->m_externalEntityRefHandler( +- parser->m_externalEntityRefHandlerArg, 0, entity->base, +- entity->systemId, entity->publicId)) ++ const int status = parser->m_externalEntityRefHandler( ++ parser->m_externalEntityRefHandlerArg, 0, entity->base, ++ entity->systemId, entity->publicId); ++ if (! status) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (! dtd->standalone && parser->m_notStandaloneHandler) { +@@ -5956,9 +5959,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + entityTrackingOnOpen(parser, entity, __LINE__); +- if (! parser->m_externalEntityRefHandler( +- parser->m_externalEntityRefHandlerArg, 0, entity->base, +- entity->systemId, entity->publicId)) { ++ const int status = parser->m_externalEntityRefHandler( ++ parser->m_externalEntityRefHandlerArg, 0, entity->base, ++ entity->systemId, entity->publicId); ++ if (! status) { + entityTrackingOnClose(parser, entity, __LINE__); + entity->open = XML_FALSE; + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; +@@ -6735,9 +6739,10 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc, + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + entityTrackingOnOpen(parser, entity, __LINE__); +- if (! parser->m_externalEntityRefHandler( +- parser->m_externalEntityRefHandlerArg, 0, entity->base, +- entity->systemId, entity->publicId)) { ++ const int status = parser->m_externalEntityRefHandler( ++ parser->m_externalEntityRefHandlerArg, 0, entity->base, ++ entity->systemId, entity->publicId); ++ if (! status) { + entityTrackingOnClose(parser, entity, __LINE__); + entity->open = XML_FALSE; + result = XML_ERROR_EXTERNAL_ENTITY_HANDLING; + +From d878614f8046af712ce7d4f6920b62db7ac44489 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Sat, 30 May 2026 00:46:36 +0200 +Subject: [PATCH 04/34] lib: Prepare `m_unknownEncodingHandler` calls for + upcoming wrapping + +--- + expat/lib/xmlparse.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 6bbc0b5f..1085c47d 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -4887,8 +4887,9 @@ handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) { + info.convert = NULL; + info.data = NULL; + info.release = NULL; +- if (parser->m_unknownEncodingHandler(parser->m_unknownEncodingHandlerData, +- encodingName, &info)) { ++ const int status = parser->m_unknownEncodingHandler( ++ parser->m_unknownEncodingHandlerData, encodingName, &info); ++ if (status) { + ENCODING *enc; + parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding()); + if (! parser->m_unknownEncodingMem) { + +From d23a32d7f261829ea206717ae52ddd527bab46ff Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:05:19 +0200 +Subject: [PATCH 05/34] lib: Register `m_attlistDeclHandler` with handler call + depth tracking + +--- + expat/lib/xmlparse.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 1085c47d..b72d5199 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -5501,10 +5501,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + poolFinish(&parser->m_tempPool); + } + *eventEndPP = s; ++ beforeHandler(parser); + parser->m_attlistDeclHandler( + parser->m_handlerArg, parser->m_declElementType->name, + parser->m_declAttributeId->name, parser->m_declAttributeType, 0, + role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); ++ afterHandler(parser); + handleDefault = XML_FALSE; + } + } +@@ -5539,10 +5541,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + poolFinish(&parser->m_tempPool); + } + *eventEndPP = s; ++ beforeHandler(parser); + parser->m_attlistDeclHandler( + parser->m_handlerArg, parser->m_declElementType->name, + parser->m_declAttributeId->name, parser->m_declAttributeType, + attVal, role == XML_ROLE_FIXED_ATTRIBUTE_VALUE); ++ afterHandler(parser); + poolClear(&parser->m_tempPool); + handleDefault = XML_FALSE; + } + +From 867fa3c0051189168c30c920b756bd44865ebfae Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:08:02 +0200 +Subject: [PATCH 06/34] lib: Register `m_characterDataHandler` with handler + call depth tracking + +--- + expat/lib/xmlparse.c | 44 ++++++++++++++++++++++++++++++++++---------- + 1 file changed, 34 insertions(+), 10 deletions(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index b72d5199..1b5890af 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -3276,7 +3276,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + *eventEndPP = end; + if (parser->m_characterDataHandler) { + XML_Char c = 0xA; ++ beforeHandler(parser); + parser->m_characterDataHandler(parser->m_handlerArg, &c, 1); ++ afterHandler(parser); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, end); + /* We are at the end of the final buffer, should we check for +@@ -3329,9 +3331,11 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + ((char *)&ch) + sizeof(XML_Char), __LINE__, + XML_ACCOUNT_ENTITY_EXPANSION); + #endif /* XML_DTD */ +- if (parser->m_characterDataHandler) ++ if (parser->m_characterDataHandler) { ++ beforeHandler(parser); + parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1); +- else if (parser->m_defaultHandler) ++ afterHandler(parser); ++ } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + } +@@ -3576,8 +3580,10 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + return XML_ERROR_BAD_CHAR_REF; + if (parser->m_characterDataHandler) { + XML_Char buf[XML_ENCODE_MAX]; ++ beforeHandler(parser); + parser->m_characterDataHandler(parser->m_handlerArg, buf, + XmlEncode(n, (ICHAR *)buf)); ++ afterHandler(parser); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + } break; +@@ -3586,7 +3592,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + case XML_TOK_DATA_NEWLINE: + if (parser->m_characterDataHandler) { + XML_Char c = 0xA; ++ beforeHandler(parser); + parser->m_characterDataHandler(parser->m_handlerArg, &c, 1); ++ afterHandler(parser); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; +@@ -3607,11 +3615,13 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + However, now we have a start/endCdataSectionHandler, so it seems + easier to let the user deal with this. + */ +- else if (0 && parser->m_characterDataHandler) ++ else if (0 && parser->m_characterDataHandler) { ++ beforeHandler(parser); + parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, + 0); +- /* END disabled code */ +- else if (parser->m_defaultHandler) ++ afterHandler(parser); ++ /* END disabled code */ ++ } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + result + = doCdataSection(parser, enc, &next, end, nextPtr, haveMore, account); +@@ -3631,13 +3641,18 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + if (MUST_CONVERT(enc, s)) { + ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd); ++ beforeHandler(parser); + parser->m_characterDataHandler( + parser->m_handlerArg, parser->m_dataBuf, + (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); +- } else ++ afterHandler(parser); ++ } else { ++ beforeHandler(parser); + parser->m_characterDataHandler( + parser->m_handlerArg, (XML_Char *)s, + (int)((XML_Char *)end - (XML_Char *)s)); ++ afterHandler(parser); ++ } + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, end); + /* We are at the end of the final buffer, should we check for +@@ -3662,16 +3677,21 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + const enum XML_Convert_Result convert_res = XmlConvert( + enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd); + *eventEndPP = s; ++ beforeHandler(parser); + charDataHandler(parser->m_handlerArg, parser->m_dataBuf, + (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); ++ afterHandler(parser); + if ((convert_res == XML_CONVERT_COMPLETED) + || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) + break; + *eventPP = s; + } +- } else ++ } else { ++ beforeHandler(parser); + charDataHandler(parser->m_handlerArg, (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); ++ afterHandler(parser); ++ } + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + } break; +@@ -4560,11 +4580,13 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, + parser->m_endCdataSectionHandler(parser->m_handlerArg); + /* BEGIN disabled code */ + /* see comment under XML_TOK_CDATA_SECT_OPEN */ +- else if (0 && parser->m_characterDataHandler) ++ else if (0 && parser->m_characterDataHandler) { ++ beforeHandler(parser); + parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, + 0); +- /* END disabled code */ +- else if (parser->m_defaultHandler) ++ afterHandler(parser); ++ /* END disabled code */ ++ } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + *nextPtr = next; +@@ -4575,7 +4597,9 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, + case XML_TOK_DATA_NEWLINE: + if (parser->m_characterDataHandler) { + XML_Char c = 0xA; ++ beforeHandler(parser); + parser->m_characterDataHandler(parser->m_handlerArg, &c, 1); ++ afterHandler(parser); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + +From e65e6876eacdae4568e291a4fe92f1bd677f7e33 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:08:40 +0200 +Subject: [PATCH 07/34] lib: Register `m_commentHandler` with handler call + depth tracking + +--- + expat/lib/xmlparse.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 1b5890af..a1c27efe 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -7014,7 +7014,9 @@ reportComment(XML_Parser parser, const ENCODING *enc, const char *start, + if (! data) + return 0; + normalizeLines(data); ++ beforeHandler(parser); + parser->m_commentHandler(parser->m_handlerArg, data); ++ afterHandler(parser); + poolClear(&parser->m_tempPool); + return 1; + } + +From 9a8c64cee8ef9541fdcad3d42f8cf075f0555059 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:14:10 +0200 +Subject: [PATCH 08/34] lib: Register `m_defaultHandler` with handler call + depth tracking + +--- + expat/lib/xmlparse.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index a1c27efe..39ec06b4 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -7057,14 +7057,19 @@ reportDefault(XML_Parser parser, const ENCODING *enc, const char *s, + convert_res + = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd); + *eventEndPP = s; ++ beforeHandler(parser); + parser->m_defaultHandler(parser->m_handlerArg, parser->m_dataBuf, + (int)(dataPtr - (ICHAR *)parser->m_dataBuf)); ++ afterHandler(parser); + *eventPP = s; + } while ((convert_res != XML_CONVERT_COMPLETED) + && (convert_res != XML_CONVERT_INPUT_INCOMPLETE)); +- } else ++ } else { ++ beforeHandler(parser); + parser->m_defaultHandler(parser->m_handlerArg, (XML_Char *)s, + (int)((XML_Char *)end - (XML_Char *)s)); ++ afterHandler(parser); ++ } + } + + static int + +From c32e8c40625aa476e737b1a523738a16ca4602ab Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:15:01 +0200 +Subject: [PATCH 09/34] lib: Register `m_elementDeclHandler` with handler call + depth tracking + +--- + expat/lib/xmlparse.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 39ec06b4..c8a24f00 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -6049,8 +6049,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + content->type = ((role == XML_ROLE_CONTENT_ANY) ? XML_CTYPE_ANY + : XML_CTYPE_EMPTY); + *eventEndPP = s; ++ beforeHandler(parser); + parser->m_elementDeclHandler( + parser->m_handlerArg, parser->m_declElementType->name, content); ++ afterHandler(parser); + handleDefault = XML_FALSE; + } + dtd->in_eldecl = XML_FALSE; +@@ -6132,8 +6134,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + if (! model) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; ++ beforeHandler(parser); + parser->m_elementDeclHandler( + parser->m_handlerArg, parser->m_declElementType->name, model); ++ afterHandler(parser); + } + dtd->in_eldecl = XML_FALSE; + dtd->contentStringLen = 0; + +From 95759bb17258d4d459f6eba13ecbd4cadaa74175 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:15:40 +0200 +Subject: [PATCH 10/34] lib: Register `m_endCdataSectionHandler` with handler + call depth tracking + +--- + expat/lib/xmlparse.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index c8a24f00..9efcaba2 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -4576,8 +4576,11 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, + *eventEndPP = next; + switch (tok) { + case XML_TOK_CDATA_SECT_CLOSE: +- if (parser->m_endCdataSectionHandler) ++ if (parser->m_endCdataSectionHandler) { ++ beforeHandler(parser); + parser->m_endCdataSectionHandler(parser->m_handlerArg); ++ afterHandler(parser); ++ } + /* BEGIN disabled code */ + /* see comment under XML_TOK_CDATA_SECT_OPEN */ + else if (0 && parser->m_characterDataHandler) { + +From eb678b99fed380222fe4d0c15efb57e83b58a060 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:16:13 +0200 +Subject: [PATCH 11/34] lib: Register `m_endDoctypeDeclHandler` with handler + call depth tracking + +--- + expat/lib/xmlparse.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 9efcaba2..b40f79e8 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -5404,7 +5404,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + } + #endif /* XML_DTD */ + if (parser->m_endDoctypeDeclHandler) { ++ beforeHandler(parser); + parser->m_endDoctypeDeclHandler(parser->m_handlerArg); ++ afterHandler(parser); + handleDefault = XML_FALSE; + } + break; + +From 26c0f39b8ae4589f542adba0e404354730547b7b Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:17:10 +0200 +Subject: [PATCH 12/34] lib: Register `m_endElementHandler` with handler call + depth tracking + +--- + expat/lib/xmlparse.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index b40f79e8..f8d5b470 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -3492,7 +3492,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + if (parser->m_endElementHandler) { + if (parser->m_startElementHandler) + *eventPP = *eventEndPP; ++ beforeHandler(parser); + parser->m_endElementHandler(parser->m_handlerArg, name.str); ++ afterHandler(parser); + noElmHandlers = XML_FALSE; + } + if (noElmHandlers && parser->m_defaultHandler) +@@ -3550,7 +3552,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + } + *uri = XML_T('\0'); + } ++ beforeHandler(parser); + parser->m_endElementHandler(parser->m_handlerArg, tag->name.str); ++ afterHandler(parser); + } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + while (tag->bindings) { + +From a480cd03cc7194f1de83750473974fff67f131c2 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:23:59 +0200 +Subject: [PATCH 13/34] lib: Register `m_endNamespaceDeclHandler` with handler + call depth tracking + +--- + expat/lib/xmlparse.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index f8d5b470..8251521d 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -3559,9 +3559,12 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + reportDefault(parser, enc, s, next); + while (tag->bindings) { + BINDING *b = tag->bindings; +- if (parser->m_endNamespaceDeclHandler) ++ if (parser->m_endNamespaceDeclHandler) { ++ beforeHandler(parser); + parser->m_endNamespaceDeclHandler(parser->m_handlerArg, + b->prefix->name); ++ afterHandler(parser); ++ } + tag->bindings = tag->bindings->nextTagBinding; + b->nextTagBinding = parser->m_freeBindingList; + parser->m_freeBindingList = b; +@@ -3753,8 +3756,11 @@ freeBindings(XML_Parser parser, BINDING *bindings) { + /* m_startNamespaceDeclHandler will have been called for this + * binding in addBindings(), so call the end handler now. + */ +- if (parser->m_endNamespaceDeclHandler) ++ if (parser->m_endNamespaceDeclHandler) { ++ beforeHandler(parser); + parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name); ++ afterHandler(parser); ++ } + + bindings = bindings->nextTagBinding; + b->nextTagBinding = parser->m_freeBindingList; + +From 3ab790b34d84fe5ab37a30b045a0c7a4aadeb9f5 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:25:42 +0200 +Subject: [PATCH 14/34] lib: Register `m_entityDeclHandler` with handler call + depth tracking + +--- + expat/lib/xmlparse.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 8251521d..991b388d 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -5603,10 +5603,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + poolFinish(&dtd->entityValuePool); + if (parser->m_entityDeclHandler) { + *eventEndPP = s; ++ beforeHandler(parser); + 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); ++ afterHandler(parser); + handleDefault = XML_FALSE; + } + } else +@@ -5676,10 +5678,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + if (dtd->keepProcessing && parser->m_declEntity + && parser->m_entityDeclHandler) { + *eventEndPP = s; ++ beforeHandler(parser); + parser->m_entityDeclHandler( + parser->m_handlerArg, parser->m_declEntity->name, + parser->m_declEntity->is_param, 0, 0, parser->m_declEntity->base, + parser->m_declEntity->systemId, parser->m_declEntity->publicId, 0); ++ afterHandler(parser); + handleDefault = XML_FALSE; + } + break; +@@ -5699,10 +5703,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + handleDefault = XML_FALSE; + } else if (parser->m_entityDeclHandler) { + *eventEndPP = s; ++ beforeHandler(parser); + parser->m_entityDeclHandler( + parser->m_handlerArg, parser->m_declEntity->name, 0, 0, 0, + parser->m_declEntity->base, parser->m_declEntity->systemId, + parser->m_declEntity->publicId, parser->m_declEntity->notation); ++ afterHandler(parser); + handleDefault = XML_FALSE; + } + } + +From 4041bdfb1099f83adfe099dfd8923ab0a087a3f3 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Sat, 30 May 2026 00:45:50 +0200 +Subject: [PATCH 15/34] lib: Register `m_externalEntityRefHandler` with handler + call depth tracking + +--- + expat/lib/xmlparse.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 991b388d..3703556e 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -3385,9 +3385,11 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + entity->open = XML_FALSE; + if (! context) + return XML_ERROR_NO_MEMORY; ++ beforeHandler(parser); + const int status = parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, context, entity->base, + entity->systemId, entity->publicId); ++ afterHandler(parser); + if (! status) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + poolDiscard(&parser->m_tempPool); +@@ -5390,9 +5392,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + if (parser->m_useForeignDTD) + entity->base = parser->m_curBase; + dtd->paramEntityRead = XML_FALSE; ++ beforeHandler(parser); + const int status = parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId); ++ afterHandler(parser); + if (! status) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { +@@ -5436,9 +5440,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + return XML_ERROR_NO_MEMORY; + entity->base = parser->m_curBase; + dtd->paramEntityRead = XML_FALSE; ++ beforeHandler(parser); + const int status = parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId); ++ afterHandler(parser); + if (! status) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { +@@ -6009,9 +6015,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + entityTrackingOnOpen(parser, entity, __LINE__); ++ beforeHandler(parser); + const int status = parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId); ++ afterHandler(parser); + if (! status) { + entityTrackingOnClose(parser, entity, __LINE__); + entity->open = XML_FALSE; +@@ -6793,9 +6801,11 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc, + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + entityTrackingOnOpen(parser, entity, __LINE__); ++ beforeHandler(parser); + const int status = parser->m_externalEntityRefHandler( + parser->m_externalEntityRefHandlerArg, 0, entity->base, + entity->systemId, entity->publicId); ++ afterHandler(parser); + if (! status) { + entityTrackingOnClose(parser, entity, __LINE__); + entity->open = XML_FALSE; + +From 83356c65aaf9095a653fb14361b6c4864916f0bd Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:27:13 +0200 +Subject: [PATCH 16/34] lib: Register `m_notationDeclHandler` with handler call + depth tracking + +--- + expat/lib/xmlparse.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 3703556e..a4cd8892 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -5821,9 +5821,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + if (! systemId) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; ++ beforeHandler(parser); + parser->m_notationDeclHandler( + parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase, + systemId, parser->m_declNotationPublicId); ++ afterHandler(parser); + handleDefault = XML_FALSE; + } + poolClear(&parser->m_tempPool); +@@ -5831,9 +5833,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + case XML_ROLE_NOTATION_NO_SYSTEM_ID: + if (parser->m_declNotationPublicId && parser->m_notationDeclHandler) { + *eventEndPP = s; ++ beforeHandler(parser); + parser->m_notationDeclHandler( + parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase, + 0, parser->m_declNotationPublicId); ++ afterHandler(parser); + handleDefault = XML_FALSE; + } + poolClear(&parser->m_tempPool); + +From 6b0b17a32c0906b98b9fd71ab9dbb4cea5c51f41 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:34:29 +0200 +Subject: [PATCH 17/34] lib: Register `m_notStandaloneHandler` with handler + call depth tracking + +--- + expat/lib/xmlparse.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index a4cd8892..5cad434b 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -5401,8 +5401,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (! dtd->standalone && parser->m_notStandaloneHandler) { ++ beforeHandler(parser); + const int handlerStatus + = parser->m_notStandaloneHandler(parser->m_handlerArg); ++ afterHandler(parser); + if (! handlerStatus) + return XML_ERROR_NOT_STANDALONE; + } +@@ -5449,8 +5451,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (! dtd->standalone && parser->m_notStandaloneHandler) { ++ beforeHandler(parser); + const int handlerStatus + = parser->m_notStandaloneHandler(parser->m_handlerArg); ++ afterHandler(parser); + if (! handlerStatus) + return XML_ERROR_NOT_STANDALONE; + } +@@ -5648,7 +5652,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + && ! parser->m_paramEntityParsing + #endif /* XML_DTD */ + && parser->m_notStandaloneHandler) { ++ beforeHandler(parser); + const int status = parser->m_notStandaloneHandler(parser->m_handlerArg); ++ afterHandler(parser); + if (! status) + return XML_ERROR_NOT_STANDALONE; + } +@@ -6043,7 +6049,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + } + #endif /* XML_DTD */ + if (! dtd->standalone && parser->m_notStandaloneHandler) { ++ beforeHandler(parser); + const int status = parser->m_notStandaloneHandler(parser->m_handlerArg); ++ afterHandler(parser); + if (! status) + return XML_ERROR_NOT_STANDALONE; + } + +From 5111c342e651fbff8d92b3bda808c75d55d60d0e Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:35:08 +0200 +Subject: [PATCH 18/34] lib: Register `m_processingInstructionHandler` with + handler call depth tracking + +--- + expat/lib/xmlparse.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 5cad434b..8eb61a76 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -7041,7 +7041,9 @@ reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, + if (! data) + return 0; + normalizeLines(data); ++ beforeHandler(parser); + parser->m_processingInstructionHandler(parser->m_handlerArg, target, data); ++ afterHandler(parser); + poolClear(&parser->m_tempPool); + return 1; + } + +From 54e808b36b9c330c268cf8a5aa5edfc09697b772 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:36:39 +0200 +Subject: [PATCH 19/34] lib: Register `m_skippedEntityHandler` with handler + call depth tracking + +--- + expat/lib/xmlparse.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 8eb61a76..8aa60978 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -3355,9 +3355,11 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + else if (! entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } else if (! entity) { +- if (parser->m_skippedEntityHandler) ++ if (parser->m_skippedEntityHandler) { ++ beforeHandler(parser); + parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0); +- else if (parser->m_defaultHandler) ++ afterHandler(parser); ++ } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + } +@@ -3368,10 +3370,12 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + if (entity->textPtr) { + enum XML_Error result; + if (! parser->m_defaultExpandInternalEntities) { +- if (parser->m_skippedEntityHandler) ++ if (parser->m_skippedEntityHandler) { ++ beforeHandler(parser); + parser->m_skippedEntityHandler(parser->m_handlerArg, entity->name, + 0); +- else if (parser->m_defaultHandler) ++ afterHandler(parser); ++ } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + break; + } +@@ -6004,7 +6008,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + /* cannot report skipped entities in declarations */ + if ((role == XML_ROLE_PARAM_ENTITY_REF) + && parser->m_skippedEntityHandler) { ++ beforeHandler(parser); + parser->m_skippedEntityHandler(parser->m_handlerArg, name, 1); ++ afterHandler(parser); + handleDefault = XML_FALSE; + } + break; +@@ -6668,8 +6674,11 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, + } else if (! entity) { + /* Cannot report skipped entity here - see comments on + parser->m_skippedEntityHandler. +- if (parser->m_skippedEntityHandler) ++ if (parser->m_skippedEntityHandler) { ++ beforeHandler(parser); + parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0); ++ afterHandler(parser); ++ } + */ + /* Cannot call the default handler because this would be + out of sync with the call to the startElementHandler. +@@ -6796,8 +6805,11 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc, + /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ + /* cannot report skipped entity here - see comments on + parser->m_skippedEntityHandler +- if (parser->m_skippedEntityHandler) ++ if (parser->m_skippedEntityHandler) { ++ beforeHandler(parser); + parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0); ++ afterHandler(parser); ++ } + */ + dtd->keepProcessing = dtd->standalone; + goto endEntityValue; + +From ae26c59e586875d5bec988ca16228e54e71e1cf9 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:37:49 +0200 +Subject: [PATCH 20/34] lib: Register `m_startCdataSectionHandler` with handler + call depth tracking + +--- + expat/lib/xmlparse.c | 32 +++++++++++++++++--------------- + 1 file changed, 17 insertions(+), 15 deletions(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 8aa60978..06a8d313 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -3613,22 +3613,24 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + break; + case XML_TOK_CDATA_SECT_OPEN: { + enum XML_Error result; +- if (parser->m_startCdataSectionHandler) ++ if (parser->m_startCdataSectionHandler) { ++ beforeHandler(parser); + parser->m_startCdataSectionHandler(parser->m_handlerArg); +- /* BEGIN disabled code */ +- /* Suppose you doing a transformation on a document that involves +- changing only the character data. You set up a defaultHandler +- and a characterDataHandler. The defaultHandler simply copies +- characters through. The characterDataHandler does the +- transformation and writes the characters out escaping them as +- necessary. This case will fail to work if we leave out the +- following two lines (because & and < inside CDATA sections will +- be incorrectly escaped). +- +- However, now we have a start/endCdataSectionHandler, so it seems +- easier to let the user deal with this. +- */ +- else if (0 && parser->m_characterDataHandler) { ++ afterHandler(parser); ++ /* BEGIN disabled code */ ++ /* Suppose you doing a transformation on a document that involves ++ changing only the character data. You set up a defaultHandler ++ and a characterDataHandler. The defaultHandler simply copies ++ characters through. The characterDataHandler does the ++ transformation and writes the characters out escaping them as ++ necessary. This case will fail to work if we leave out the ++ following two lines (because & and < inside CDATA sections will ++ be incorrectly escaped). ++ ++ However, now we have a start/endCdataSectionHandler, so it seems ++ easier to let the user deal with this. ++ */ ++ } else if (0 && parser->m_characterDataHandler) { + beforeHandler(parser); + parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, + 0); + +From d4f44b716d47d50be28509084627d88e6c260064 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:38:47 +0200 +Subject: [PATCH 21/34] lib: Register `m_startDoctypeDeclHandler` with handler + call depth tracking + +--- + expat/lib/xmlparse.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 06a8d313..97151708 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -5300,9 +5300,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + break; + case XML_ROLE_DOCTYPE_INTERNAL_SUBSET: + if (parser->m_startDoctypeDeclHandler) { ++ beforeHandler(parser); + parser->m_startDoctypeDeclHandler( + parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid, + parser->m_doctypePubid, 1); ++ afterHandler(parser); + parser->m_doctypeName = NULL; + poolClear(&parser->m_tempPool); + handleDefault = XML_FALSE; +@@ -5369,9 +5371,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + } + + if (parser->m_doctypeName) { ++ beforeHandler(parser); + parser->m_startDoctypeDeclHandler( + parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid, + parser->m_doctypePubid, 0); ++ afterHandler(parser); + poolClear(&parser->m_tempPool); + handleDefault = XML_FALSE; + } + +From b8fb947b326f6f813d8d465fe2718a094768cd85 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:39:38 +0200 +Subject: [PATCH 22/34] lib: Register `m_startElementHandler` with handler call + depth tracking + +--- + expat/lib/xmlparse.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 97151708..29a80434 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -3462,10 +3462,12 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account); + if (result) + return result; +- if (parser->m_startElementHandler) ++ if (parser->m_startElementHandler) { ++ beforeHandler(parser); + parser->m_startElementHandler(parser->m_handlerArg, tag->name.str, + (const XML_Char **)parser->m_atts); +- else if (parser->m_defaultHandler) ++ afterHandler(parser); ++ } else if (parser->m_defaultHandler) + reportDefault(parser, enc, s, next); + poolClear(&parser->m_tempPool); + break; +@@ -3491,8 +3493,10 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + } + poolFinish(&parser->m_tempPool); + if (parser->m_startElementHandler) { ++ beforeHandler(parser); + parser->m_startElementHandler(parser->m_handlerArg, name.str, + (const XML_Char **)parser->m_atts); ++ afterHandler(parser); + noElmHandlers = XML_FALSE; + } + if (parser->m_endElementHandler) { + +From 94ee80336d782d049356c9524f07b126fb436d50 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:40:13 +0200 +Subject: [PATCH 23/34] lib: Register `m_startNamespaceDeclHandler` with + handler call depth tracking + +--- + expat/lib/xmlparse.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 29a80434..3ee9f4cf 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -4534,9 +4534,12 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, + b->nextTagBinding = *bindingsPtr; + *bindingsPtr = b; + /* if attId == NULL then we are not starting a namespace scope */ +- if (attId && parser->m_startNamespaceDeclHandler) ++ if (attId && parser->m_startNamespaceDeclHandler) { ++ beforeHandler(parser); + parser->m_startNamespaceDeclHandler(parser->m_handlerArg, prefix->name, + prefix->binding ? uri : 0); ++ afterHandler(parser); ++ } + return XML_ERROR_NONE; + } + + +From c82bcdfdbb8d0ed86f876903de7411a8e8206f11 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Sat, 30 May 2026 00:46:47 +0200 +Subject: [PATCH 24/34] lib: Register `m_unknownEncodingHandler` with handler + call depth tracking + +--- + expat/lib/xmlparse.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 3ee9f4cf..fec53451 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -4939,8 +4939,10 @@ handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) { + info.convert = NULL; + info.data = NULL; + info.release = NULL; ++ beforeHandler(parser); + const int status = parser->m_unknownEncodingHandler( + parser->m_unknownEncodingHandlerData, encodingName, &info); ++ afterHandler(parser); + if (status) { + ENCODING *enc; + parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding()); + +From e46260545ef147c3304ed9a31935c0f8548427d2 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:41:00 +0200 +Subject: [PATCH 25/34] lib: Register `m_unparsedEntityDeclHandler` with + handler call depth tracking + +--- + expat/lib/xmlparse.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index fec53451..a2c03ccf 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -5727,10 +5727,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, + poolFinish(&dtd->pool); + if (parser->m_unparsedEntityDeclHandler) { + *eventEndPP = s; ++ beforeHandler(parser); + parser->m_unparsedEntityDeclHandler( + parser->m_handlerArg, parser->m_declEntity->name, + parser->m_declEntity->base, parser->m_declEntity->systemId, + parser->m_declEntity->publicId, parser->m_declEntity->notation); ++ afterHandler(parser); + handleDefault = XML_FALSE; + } else if (parser->m_entityDeclHandler) { + *eventEndPP = s; + +From 00b92635b52e169e5478bf464fefc5eb03112e37 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 21:41:38 +0200 +Subject: [PATCH 26/34] lib: Register `m_xmlDeclHandler` with handler call + depth tracking + +--- + expat/lib/xmlparse.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index a2c03ccf..70cb7ee7 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -4888,8 +4888,10 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s, + if (! storedversion) + return XML_ERROR_NO_MEMORY; + } ++ beforeHandler(parser); + parser->m_xmlDeclHandler(parser->m_handlerArg, storedversion, storedEncName, + standalone); ++ afterHandler(parser); + } else if (parser->m_defaultHandler) + reportDefault(parser, parser->m_encoding, s, next); + if (parser->m_protocolEncodingName == NULL) { + +From 9227c02d05735b91cef311fc2a44ad11d9c4f675 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 15:35:27 +0200 +Subject: [PATCH 27/34] lib: Protect `XML_GetBuffer` from being called from a + handler + +--- + expat/lib/xmlparse.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 70cb7ee7..4a54bc07 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -2450,7 +2450,7 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) { + + void *XMLCALL + XML_GetBuffer(XML_Parser parser, int len) { +- if (parser == NULL) ++ if ((parser == NULL) || isCalledFromInsideHandler(parser)) + return NULL; + if (len < 0) { + parser->m_errorCode = XML_ERROR_NO_MEMORY; + +From 9df6a98a3043e02c36be0dddb34e0027a83e1ed8 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 15:32:38 +0200 +Subject: [PATCH 28/34] lib: Protect `XML_Parse` from being called from a + handler + +--- + expat/lib/xmlparse.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 4a54bc07..7e31a522 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -2273,6 +2273,8 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { + parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT; + return XML_STATUS_ERROR; + } ++ if (isCalledFromInsideHandler(parser)) ++ return XML_STATUS_ERROR; + switch (parser->m_parsingStatus.parsing) { + case XML_SUSPENDED: + parser->m_errorCode = XML_ERROR_SUSPENDED; + +From 5a2dd01deafd94f3b40f7dcf73bfad188a0db398 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 15:33:44 +0200 +Subject: [PATCH 29/34] lib: Protect `XML_ParseBuffer` from being called from a + handler + +--- + expat/lib/xmlparse.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 7e31a522..83e7472d 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -2384,7 +2384,7 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) { + const char *start; + enum XML_Status result = XML_STATUS_OK; + +- if (parser == NULL) ++ if ((parser == NULL) || isCalledFromInsideHandler(parser)) + return XML_STATUS_ERROR; + + if (len < 0) { + +From 91b901826ed981bc3076af99ce84a55250c44140 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 15:21:28 +0200 +Subject: [PATCH 30/34] lib: Protect `XML_ParserFree` from being called from a + handler + +--- + expat/lib/xmlparse.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 83e7472d..54887fc3 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -1856,7 +1856,7 @@ void XMLCALL + XML_ParserFree(XML_Parser parser) { + TAG *tagList; + OPEN_INTERNAL_ENTITY *entityList; +- if (parser == NULL) ++ if ((parser == NULL) || isCalledFromInsideHandler(parser)) + return; + /* free m_tagStack and m_freeTagList */ + tagList = parser->m_tagStack; + +From 4c208a02a4328b75165ed9dc4913554db5880856 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 15:22:41 +0200 +Subject: [PATCH 31/34] lib: Protect `XML_ParserReset` from being called from a + handler + +--- + expat/lib/xmlparse.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c +index 54887fc3..bffb65fe 100644 +--- a/expat/lib/xmlparse.c ++++ b/expat/lib/xmlparse.c +@@ -1575,7 +1575,7 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) { + TAG *tStk; + OPEN_INTERNAL_ENTITY *openEntityList; + +- if (parser == NULL) ++ if ((parser == NULL) || isCalledFromInsideHandler(parser)) + return XML_FALSE; + + if (parser->m_parentParser) + +From 990c66dda20708d94965646961a8fe843b5ef2a4 Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Sun, 31 May 2026 13:37:01 +0200 +Subject: [PATCH 32/34] tests: Cover calls forbidden from handlers + +--- + expat/tests/runtests.c | 39 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c +index 659ed030..052dac58 100644 +--- a/expat/tests/runtests.c ++++ b/expat/tests/runtests.c +@@ -9421,6 +9421,44 @@ START_TEST(test_misc_expected_event_ptr_issue_980) { + } + END_TEST + ++static void XMLCALL ++forbidden_calls_character_handler(void *userData, const XML_Char *s, int len) { ++ UNUSED_P(s); ++ UNUSED_P(len); ++ XML_Parser parser = userData; ++ ++ assert_true(parser != NULL); // self-test ++ ++ assert_true(XML_GetBuffer(parser, 123) == NULL); // i.e. rejected ++ ++ assert_true(XML_Parse(parser, "", 0, /*isFinal=*/XML_FALSE) ++ == XML_STATUS_ERROR); // i.e. rejected ++ ++ assert_true(XML_ParseBuffer(parser, 0, /*isFinal=*/XML_FALSE) ++ == XML_STATUS_ERROR); // i.e. rejected ++ ++ XML_ParserFree(parser); // rejected ++ ++ assert_true(XML_ParserReset(parser, /*encodingName=*/NULL) ++ == XML_FALSE); // i.e. rejected ++ ++ assert_true(XML_GetErrorCode(parser) == XML_ERROR_NONE); ++} ++ ++START_TEST(test_misc_calls_forbidden_from_handlers) { ++ const char *const doc = "Hello world!"; ++ ++ XML_Parser parser = XML_ParserCreate(NULL); ++ XML_UseParserAsHandlerArg(parser); ++ XML_SetCharacterDataHandler(parser, forbidden_calls_character_handler); ++ ++ assert_true(XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_TRUE) ++ == XML_STATUS_OK); ++ ++ XML_ParserFree(parser); ++} ++END_TEST ++ + static void + alloc_setup(void) { + XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free}; +@@ -14132,6 +14170,7 @@ make_suite(void) { + tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser); + tcase_add_test__ifdef_xml_dtd(tc_misc, test_renter_loop_finite_content); + tcase_add_test(tc_misc, test_misc_expected_event_ptr_issue_980); ++ tcase_add_test(tc_misc, test_misc_calls_forbidden_from_handlers); + + suite_add_tcase(s, tc_alloc); + tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown); + +From c141e4649451ed04cf28360d3504c408a24937db Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 26 May 2026 15:41:46 +0200 +Subject: [PATCH 33/34] doc: Document that `XML_ParserFree` and + `XML_ParserReset` must not + +.. be called from within handlers for the same parser instance +--- + expat/doc/reference.html | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/expat/doc/reference.html b/expat/doc/reference.html +index 3358ecc8..6e04428b 100644 +--- a/expat/doc/reference.html ++++ b/expat/doc/reference.html +@@ -1064,7 +1064,9 @@ dealing with any memory associated with user data. +

To state the obvious: the three parsing functions XML_Parse, + XML_ParseBuffer and +-XML_GetBuffer must not be called from within a handler ++XML_GetBuffer as well as the two cleanup functions ++XML_ParserFree and XML_ParserReset must not be called from within a handler + unless they operate on a separate parser instance, that is, one that + did not call the handler. For example, it is OK to call the parsing + functions from within an XML_ExternalEntityRefHandler, + +From 3f1680101b73b850aac60ff61c9bcbdd7b13067e Mon Sep 17 00:00:00 2001 +From: RHEL Packaging Agent +Date: Fri, 31 Jul 2026 11:16:10 +0000 +Subject: [PATCH 34/34] tests: Add explicit cast for C++ compatibility in + forbidden_calls_character_handler + +The void* to XML_Parser assignment needs an explicit cast when compiled as +C++ (via runtestspp.cpp including runtests.c). C allows implicit void* to +pointer conversion but C++ does not. +--- + expat/tests/runtests.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c +index 052dac58..037b13ed 100644 +--- a/expat/tests/runtests.c ++++ b/expat/tests/runtests.c +@@ -9425,7 +9425,7 @@ static void XMLCALL + forbidden_calls_character_handler(void *userData, const XML_Char *s, int len) { + UNUSED_P(s); + UNUSED_P(len); +- XML_Parser parser = userData; ++ XML_Parser parser = (XML_Parser)userData; + + assert_true(parser != NULL); // self-test + diff --git a/expat.spec b/expat.spec index ce209c2..a66e8e1 100644 --- a/expat.spec +++ b/expat.spec @@ -3,7 +3,7 @@ Summary: An XML parser library Name: expat Version: %(echo %{unversion} | sed 's/_/./g') -Release: 2%{?dist} +Release: 2%{?dist}.1 Source: https://github.com/libexpat/libexpat/archive/R_%{unversion}.tar.gz#/expat-%{version}.tar.gz URL: https://libexpat.github.io/ License: MIT @@ -28,6 +28,9 @@ Patch7: expat-2.5.0-CVE-2025-59375.patch # https://issues.redhat.com/browse/RHEL-177979 # https://github.com/libexpat/libexpat/pull/1216 Patch8: expat-2.5.0-CVE-2026-45186.patch +# https://issues.redhat.com/browse/RHEL-220979 +# https://github.com/libexpat/libexpat/pull/1246 +Patch9: expat-2.5.0-CVE-2026-50219.patch %description This is expat, the C library for parsing XML, written by James Clark. Expat @@ -65,6 +68,7 @@ pushd .. %patch6 -p1 -b .CVE-2024-8176 %patch7 -p1 -b .CVE-2025-59375 %patch8 -p1 -b .CVE-2026-45186 +%patch9 -p1 -b .CVE-2026-50219 popd sed -i 's/install-data-hook/do-nothing-please/' lib/Makefile.am @@ -114,6 +118,10 @@ make check %{_libdir}/lib*.a %changelog +* Fri Jul 31 2026 RHEL Packaging Agent - 2.5.0-2.1 +- Fix CVE-2026-50219 +- Resolves: RHEL-220979 + * Thu May 28 2026 RHEL Packaging Agent - 2.5.0-2 - Fix CVE-2026-45186 - Resolves: RHEL-177979