diff --git a/SPECS/expat/CVE-2024-8176.patch b/SPECS/expat/CVE-2024-8176.patch
deleted file mode 100644
index 47f38ef6dd7..00000000000
--- a/SPECS/expat/CVE-2024-8176.patch
+++ /dev/null
@@ -1,1398 +0,0 @@
-From 35a1dea4c07cb0f13f0736d3a8821a696c27f8b1 Mon Sep 17 00:00:00 2001
-From: Kshitiz Godara
Sets a handler for element declarations in a DTD. The handler gets
- called with the name of the element in the declaration and a pointer
- to a structure that contains the element model. It's the user code's
--responsibility to free model when finished with it. See
-+responsibility to free model when finished with via a call to
- XML_FreeContentModel.
- There is no need to free the model from the handler, it can be kept
- around and freed at a later stage.
-+/* Added in Expat 2.7.2. */ -+XML_Bool -+XML_SetAllocTrackerMaximumAmplification(XML_Parser p, -+ float maximumAmplificationFactor); -+-+
-+ Sets the maximum tolerated amplification factor
-+ between direct input and bytes of dynamic memory allocated
-+ (default: 100.0)
-+ of parser p to maximumAmplificationFactor, and
-+ returns XML_TRUE upon success and XML_FALSE upon error.
-+
-+ Note: -+ There are three types of allocations that intentionally bypass tracking and limiting: -+
-+XML_MemMalloc
-+ and
-+ XML_MemRealloc
-+ —
-+ healthy use of these two functions continues to be a responsibility
-+ of the application using Expat
-+ —,
-+ XML_GetBuffer
-+ and
-+ XML_ParseBuffer
-+ (and thus also by plain
-+ XML_Parse), and
-+ XML_FreeContentModel).
-+ The amplification factor is calculated as ..
-+amplification := allocated / direct-+
-+ .. while parsing, whereas
-+ direct is the number of bytes read from the primary document in parsing and
-+ allocated is the number of bytes of dynamic memory allocated in the parser hierarchy.
-+
For a call to XML_SetAllocTrackerMaximumAmplification to succeed:
p must be a non-NULL root parser (without any parent parsers) andmaximumAmplificationFactor must be non-NaN and greater than or equal to 1.0.-+ Note: -+ If you ever need to increase this value for non-attack payload, -+ please file a bug report. -+
-+ -+-+ Note: -+ Amplifications factors greater than 100 can been observed near the start of parsing -+ even with benign files in practice. -+ -+ So if you do reduce the maximum allowed amplification, -+ please make sure that the activation threshold is still big enough -+ to not end up with undesired false positives (i.e. benign files being rejected). -+
-+-+/* Added in Expat 2.7.2. */ -+XML_Bool -+XML_SetAllocTrackerActivationThreshold(XML_Parser p, -+ unsigned long long activationThresholdBytes); -+-+
-+ Sets number of allocated bytes of dynamic memory
-+ needed to activate protection against disproportionate use of RAM
-+ (default: 64 MiB)
-+ of parser p to activationThresholdBytes, and
-+ returns XML_TRUE upon success and XML_FALSE upon error.
-+
-+ Note:
-+ For types of allocations that intentionally bypass tracking and limiting, please see
-+ XML_SetAllocTrackerMaximumAmplification
-+ above.
-+
For a call to XML_SetAllocTrackerActivationThreshold to succeed:
p must be a non-NULL root parser (without any parent parsers).-+ Note: -+ If you ever need to increase this value for non-attack payload, -+ please file a bug report. -+
-+- /* Added in Expat 2.6.0. */ -diff --git a/doc/xmlwf.1 b/doc/xmlwf.1 -index 61b3025..5f50ba9 100644 ---- a/doc/xmlwf.1 -+++ b/doc/xmlwf.1 -@@ -5,7 +5,7 @@ - \\$2 \(la\\$1\(ra\\$3 - .. - .if \n(.g .mso www.tmac --.TH XMLWF 1 "November 6, 2024" "" "" -+.TH XMLWF 1 "September 16, 2025" "" "" - .SH NAME - xmlwf \- Determines if an XML document is well-formed - .SH SYNOPSIS -@@ -88,7 +88,11 @@ supports both. - .TP - \*(T<\fB\-a\fR\*(T> \fIfactor\fR - Sets the maximum tolerated amplification factor --for protection against billion laughs attacks (default: 100.0). -+for protection against amplification attacks -+like the billion laughs attack -+(default: 100.0 -+for the sum of direct and indirect output and also -+for allocations of dynamic memory). - The amplification factor is calculated as .. - - .nf -@@ -97,12 +101,22 @@ The amplification factor is calculated as .. - - .fi - --\&.. while parsing, whereas -+\&.. with regard to use of entities and .. -+ -+.nf -+ -+ amplification := allocated / direct -+ -+.fi -+ -+\&.. with regard to dynamic memory while parsing. -is the number of bytes read --from the primary document in parsing and -+from the primary document in parsing, - is the number of bytes - added by expanding entities and reading of external DTD files, --combined. -+combined, and -+ is the total number of bytes of dynamic memory -+allocated (and not freed) per hierarchy of parsers. - - \fINOTE\fR: - If you ever need to increase this value for non-attack payload, -@@ -110,8 +124,10 @@ please file a bug report. - .TP - \*(T<\fB\-b\fR\*(T> \fIbytes\fR - Sets the number of output bytes (including amplification) --needed to activate protection against billion laughs attacks --(default: 8 MiB). -+needed to activate protection against amplification attacks -+like billion laughs -+(default: 8 MiB for the sum of direct and indirect output, -+and 64 MiB for allocations of dynamic memory). - This can be thought of as an "activation threshold". - - \fINOTE\fR: -diff --git a/doc/xmlwf.xml b/doc/xmlwf.xml -index cf6d984..d152e6f 100644 ---- a/doc/xmlwf.xml -+++ b/doc/xmlwf.xml -@@ -158,19 +158,31 @@ supports both. - - - Sets the maximum tolerated amplification factor -- for protection against billion laughs attacks (default: 100.0). -+ for protection against amplification attacks -+ like the billion laughs attack -+ (default: 100.0 -+ for the sum of direct and indirect output and also -+ for allocations of dynamic memory). - The amplification factor is calculated as .. - -- amplification := (direct + indirect) / direct - --- .. while parsing, whereas -+ .. with regard to use of entities and .. -+ -+-+ amplification := allocated / direct -+ -+-+ .. with regard to dynamic memory while parsing. - <direct> is the number of bytes read -- from the primary document in parsing and -+ from the primary document in parsing, - <indirect> is the number of bytes - added by expanding entities and reading of external DTD files, -- combined. -+ combined, and -+ <allocated> is the total number of bytes of dynamic memory -+ allocated (and not freed) per hierarchy of parsers. - -- NOTE : -@@ -185,8 +197,10 @@ supports both. -- - Sets the number of output bytes (including amplification) -- needed to activate protection against billion laughs attacks -- (default: 8 MiB). -+ needed to activate protection against amplification attacks -+ like billion laughs -+ (default: 8 MiB for the sum of direct and indirect output, -+ and 64 MiB for allocations of dynamic memory). - This can be thought of as an "activation threshold". - --diff --git a/fuzz/xml_parse_fuzzer.c b/fuzz/xml_parse_fuzzer.c -index a7e8414..677fe59 100644 ---- a/fuzz/xml_parse_fuzzer.c -+++ b/fuzz/xml_parse_fuzzer.c -@@ -89,15 +89,17 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - - XML_Parser externalEntityParser - = XML_ExternalEntityParserCreate(parentParser, "e1", NULL); -- assert(externalEntityParser); -- ParseOneInput(externalEntityParser, data, size); -- XML_ParserFree(externalEntityParser); -+ if (externalEntityParser != NULL) { -+ ParseOneInput(externalEntityParser, data, size); -+ XML_ParserFree(externalEntityParser); -+ } - - XML_Parser externalDtdParser - = XML_ExternalEntityParserCreate(parentParser, NULL, NULL); -- assert(externalDtdParser); -- ParseOneInput(externalDtdParser, data, size); -- XML_ParserFree(externalDtdParser); -+ if (externalDtdParser != NULL) { -+ ParseOneInput(externalDtdParser, data, size); -+ XML_ParserFree(externalDtdParser); -+ } - - // finally frees this parser which served as parent - XML_ParserFree(parentParser); -diff --git a/fuzz/xml_parsebuffer_fuzzer.c b/fuzz/xml_parsebuffer_fuzzer.c -index 0327aa9..7939f20 100644 ---- a/fuzz/xml_parsebuffer_fuzzer.c -+++ b/fuzz/xml_parsebuffer_fuzzer.c -@@ -101,15 +101,17 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - - XML_Parser externalEntityParser - = XML_ExternalEntityParserCreate(parentParser, "e1", NULL); -- assert(externalEntityParser); -- ParseOneInput(externalEntityParser, data, size); -- XML_ParserFree(externalEntityParser); -+ if (externalEntityParser != NULL) { -+ ParseOneInput(externalEntityParser, data, size); -+ XML_ParserFree(externalEntityParser); -+ } - - XML_Parser externalDtdParser - = XML_ExternalEntityParserCreate(parentParser, NULL, NULL); -- assert(externalDtdParser); -- ParseOneInput(externalDtdParser, data, size); -- XML_ParserFree(externalDtdParser); -+ if (externalDtdParser != NULL) { -+ ParseOneInput(externalDtdParser, data, size); -+ XML_ParserFree(externalDtdParser); -+ } - - // finally frees this parser which served as parent - XML_ParserFree(parentParser); -diff --git a/lib/expat.h b/lib/expat.h -index 523b37d..df207e9 100644 ---- a/lib/expat.h -+++ b/lib/expat.h -@@ -1032,7 +1032,10 @@ enum XML_FeatureEnum { - XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT, - XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT, - /* Added in Expat 2.6.0. */ -- XML_FEATURE_GE -+ XML_FEATURE_GE, -+ /* Added in Expat 2.7.2. */ -+ XML_FEATURE_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT, -+ XML_FEATURE_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT, - /* Additional features must be added to the end of this enum. */ - }; - -@@ -1057,6 +1060,16 @@ XML_SetBillionLaughsAttackProtectionMaximumAmplification( - XMLPARSEAPI(XML_Bool) - XML_SetBillionLaughsAttackProtectionActivationThreshold( - XML_Parser parser, unsigned long long activationThresholdBytes); -+ -+/* Added in Expat 2.7.2. */ -+XMLPARSEAPI(XML_Bool) -+XML_SetAllocTrackerMaximumAmplification(XML_Parser parser, -+ float maximumAmplificationFactor); -+ -+/* Added in Expat 2.7.2. */ -+XMLPARSEAPI(XML_Bool) -+XML_SetAllocTrackerActivationThreshold( -+ XML_Parser parser, unsigned long long activationThresholdBytes); - #endif - - /* Added in Expat 2.6.0. */ -diff --git a/lib/internal.h b/lib/internal.h -index 167ec36..1b763ff 100644 ---- a/lib/internal.h -+++ b/lib/internal.h -@@ -145,6 +145,11 @@ - 100.0f - #define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT \ - 8388608 // 8 MiB, 2^23 -+ -+#define EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT 100.0f -+#define EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT \ -+ 67108864 // 64 MiB, 2^26 -+ - /* NOTE END */ - - #include "expat.h" // so we can use type XML_Parser below -@@ -168,6 +173,9 @@ extern - #endif - XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c - #if defined(XML_TESTING) -+void *expat_malloc(XML_Parser parser, size_t size, int sourceLine); -+void expat_free(XML_Parser parser, void *ptr, int sourceLine); -+void *expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine); - extern unsigned int g_bytesScanned; // used for testing only - #endif - -diff --git a/lib/libexpat.def.cmake b/lib/libexpat.def.cmake -index 10ee9cd..7a3a7ec 100644 ---- a/lib/libexpat.def.cmake -+++ b/lib/libexpat.def.cmake -@@ -79,3 +79,6 @@ EXPORTS - @_EXPAT_COMMENT_DTD_OR_GE@ XML_SetBillionLaughsAttackProtectionMaximumAmplification @70 - ; added with version 2.6.0 - XML_SetReparseDeferralEnabled @71 -+; added with version 2.7.2 -+@_EXPAT_COMMENT_DTD_OR_GE@ XML_SetAllocTrackerMaximumAmplification @72 -+@_EXPAT_COMMENT_DTD_OR_GE@ XML_SetAllocTrackerActivationThreshold @73 -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index 473c791..e2847b1 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -234,7 +234,7 @@ typedef struct { - unsigned char power; - size_t size; - size_t used; -- const XML_Memory_Handling_Suite *mem; -+ XML_Parser parser; - } HASH_TABLE; - - static size_t keylen(KEY s); -@@ -357,7 +357,7 @@ typedef struct { - const XML_Char *end; - XML_Char *ptr; - XML_Char *start; -- const XML_Memory_Handling_Suite *mem; -+ XML_Parser parser; - } STRING_POOL; - - /* The XML_Char before the name is used to determine whether -@@ -452,6 +452,14 @@ typedef struct accounting { - unsigned long long activationThresholdBytes; - } ACCOUNTING; - -+typedef struct MALLOC_TRACKER { -+ XmlBigCount bytesAllocated; -+ XmlBigCount peakBytesAllocated; // updated live only for debug level >=2 -+ unsigned long debugLevel; -+ float maximumAmplificationFactor; // >=1.0 -+ XmlBigCount activationThresholdBytes; -+} MALLOC_TRACKER; -+ - typedef struct entity_stats { - unsigned int countEverOpened; - unsigned int currentDepth; -@@ -555,27 +563,24 @@ static XML_Bool setContext(XML_Parser parser, const XML_Char *context); - - static void FASTCALL normalizePublicId(XML_Char *s); - --static DTD *dtdCreate(const XML_Memory_Handling_Suite *ms); -+static DTD *dtdCreate(XML_Parser parser); - /* do not call if m_parentParser != NULL */ --static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms); --static void dtdDestroy(DTD *p, XML_Bool isDocEntity, -- const XML_Memory_Handling_Suite *ms); -+static void dtdReset(DTD *p, XML_Parser parser); -+static void dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser); - static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, -- const XML_Memory_Handling_Suite *ms); -+ XML_Parser parser); - static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable, - STRING_POOL *newPool, const HASH_TABLE *oldTable); - static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name, - size_t createSize); --static void FASTCALL hashTableInit(HASH_TABLE *table, -- const XML_Memory_Handling_Suite *ms); -+static void FASTCALL hashTableInit(HASH_TABLE *table, XML_Parser parser); - static void FASTCALL hashTableClear(HASH_TABLE *table); - static void FASTCALL hashTableDestroy(HASH_TABLE *table); - static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *iter, - const HASH_TABLE *table); - static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *iter); - --static void FASTCALL poolInit(STRING_POOL *pool, -- const XML_Memory_Handling_Suite *ms); -+static void FASTCALL poolInit(STRING_POOL *pool, XML_Parser parser); - static void FASTCALL poolClear(STRING_POOL *pool); - static void FASTCALL poolDestroy(STRING_POOL *pool); - static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, -@@ -595,15 +600,15 @@ static XML_Content *build_model(XML_Parser parser); - static ELEMENT_TYPE *getElementType(XML_Parser parser, const ENCODING *enc, - const char *ptr, const char *end); - --static XML_Char *copyString(const XML_Char *s, -- const XML_Memory_Handling_Suite *memsuite); -+static XML_Char *copyString(const XML_Char *s, XML_Parser parser); - - static unsigned long generate_hash_secret_salt(XML_Parser parser); - static XML_Bool startParsing(XML_Parser parser); - - static XML_Parser parserCreate(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, -- const XML_Char *nameSep, DTD *dtd); -+ const XML_Char *nameSep, DTD *dtd, -+ XML_Parser parentParser); - - static void parserInit(XML_Parser parser, const XML_Char *encodingName); - -@@ -773,14 +778,232 @@ struct XML_ParserStruct { - unsigned long m_hash_secret_salt; - #if XML_GE == 1 - ACCOUNTING m_accounting; -+ MALLOC_TRACKER m_alloc_tracker; - ENTITY_STATS m_entity_stats; - #endif - XML_Bool m_reenter; - }; - --#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s))) --#define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p), (s))) --#define FREE(parser, p) (parser->m_mem.free_fcn((p))) -+#if XML_GE == 1 -+# define MALLOC(parser, s) (expat_malloc((parser), (s), __LINE__)) -+# define REALLOC(parser, p, s) (expat_realloc((parser), (p), (s), __LINE__)) -+# define FREE(parser, p) (expat_free((parser), (p), __LINE__)) -+#else -+# define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s))) -+# define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p), (s))) -+# define FREE(parser, p) (parser->m_mem.free_fcn((p))) -+#endif -+ -+#if XML_GE == 1 -+static void -+expat_heap_stat(XML_Parser rootParser, char operator, XmlBigCount absDiff, -+ XmlBigCount newTotal, XmlBigCount peakTotal, int sourceLine) { -+ // NOTE: This can be +infinity or -nan -+ const float amplification -+ = (float)newTotal / (float)rootParser->m_accounting.countBytesDirect; -+ fprintf( -+ stderr, -+ "expat: Allocations(%p): Direct " EXPAT_FMT_ULL("10") ", allocated %c" EXPAT_FMT_ULL( -+ "10") " to " EXPAT_FMT_ULL("10") " (" EXPAT_FMT_ULL("10") " peak), amplification %8.2f (xmlparse.c:%d)\n", -+ (void *)rootParser, rootParser->m_accounting.countBytesDirect, operator, -+ absDiff, newTotal, peakTotal, (double)amplification, sourceLine); -+} -+ -+static bool -+expat_heap_increase_tolerable(XML_Parser rootParser, XmlBigCount increase, -+ int sourceLine) { -+ assert(rootParser != NULL); -+ assert(increase > 0); -+ -+ XmlBigCount newTotal = 0; -+ bool tolerable = true; -+ -+ // Detect integer overflow -+ if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated < increase) { -+ tolerable = false; -+ } else { -+ newTotal = rootParser->m_alloc_tracker.bytesAllocated + increase; -+ -+ if (newTotal >= rootParser->m_alloc_tracker.activationThresholdBytes) { -+ assert(newTotal > 0); -+ // NOTE: This can be +infinity when dividing by zero but not -nan -+ const float amplification -+ = (float)newTotal / (float)rootParser->m_accounting.countBytesDirect; -+ if (amplification -+ > rootParser->m_alloc_tracker.maximumAmplificationFactor) { -+ tolerable = false; -+ } -+ } -+ } -+ -+ if (! tolerable && (rootParser->m_alloc_tracker.debugLevel >= 1)) { -+ expat_heap_stat(rootParser, '+', increase, newTotal, newTotal, sourceLine); -+ } -+ -+ return tolerable; -+} -+ -+# if defined(XML_TESTING) -+void * -+# else -+static void * -+# endif -+expat_malloc(XML_Parser parser, size_t size, int sourceLine) { -+ // Detect integer overflow -+ if (SIZE_MAX - size < sizeof(size_t)) { -+ return NULL; -+ } -+ -+ const XML_Parser rootParser = getRootParserOf(parser, NULL); -+ assert(rootParser->m_parentParser == NULL); -+ -+ const size_t bytesToAllocate = sizeof(size_t) + size; -+ -+ if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated -+ < bytesToAllocate) { -+ return NULL; // i.e. signal integer overflow as out-of-memory -+ } -+ -+ if (! expat_heap_increase_tolerable(rootParser, bytesToAllocate, -+ sourceLine)) { -+ return NULL; // i.e. signal violation as out-of-memory -+ } -+ -+ // Actually allocate -+ void *const mallocedPtr = parser->m_mem.malloc_fcn(bytesToAllocate); -+ -+ if (mallocedPtr == NULL) { -+ return NULL; -+ } -+ -+ // Update in-block recorded size -+ *(size_t *)mallocedPtr = size; -+ -+ // Update accounting -+ rootParser->m_alloc_tracker.bytesAllocated += bytesToAllocate; -+ -+ // Report as needed -+ if (rootParser->m_alloc_tracker.debugLevel >= 2) { -+ if (rootParser->m_alloc_tracker.bytesAllocated -+ > rootParser->m_alloc_tracker.peakBytesAllocated) { -+ rootParser->m_alloc_tracker.peakBytesAllocated -+ = rootParser->m_alloc_tracker.bytesAllocated; -+ } -+ expat_heap_stat(rootParser, '+', bytesToAllocate, -+ rootParser->m_alloc_tracker.bytesAllocated, -+ rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); -+ } -+ -+ return (char *)mallocedPtr + sizeof(size_t); -+} -+ -+# if defined(XML_TESTING) -+void -+# else -+static void -+# endif -+expat_free(XML_Parser parser, void *ptr, int sourceLine) { -+ assert(parser != NULL); -+ -+ if (ptr == NULL) { -+ return; -+ } -+ -+ const XML_Parser rootParser = getRootParserOf(parser, NULL); -+ assert(rootParser->m_parentParser == NULL); -+ -+ // Extract size (to the eyes of malloc_fcn/realloc_fcn) and -+ // the original pointer returned by malloc/realloc -+ void *const mallocedPtr = (char *)ptr - sizeof(size_t); -+ const size_t bytesAllocated = sizeof(size_t) + *(size_t *)mallocedPtr; -+ -+ // Update accounting -+ assert(rootParser->m_alloc_tracker.bytesAllocated >= bytesAllocated); -+ rootParser->m_alloc_tracker.bytesAllocated -= bytesAllocated; -+ -+ // Report as needed -+ if (rootParser->m_alloc_tracker.debugLevel >= 2) { -+ expat_heap_stat(rootParser, '-', bytesAllocated, -+ rootParser->m_alloc_tracker.bytesAllocated, -+ rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); -+ } -+ -+ // NOTE: This may be freeing rootParser, so freeing has to come last -+ parser->m_mem.free_fcn(mallocedPtr); -+} -+ -+# if defined(XML_TESTING) -+void * -+# else -+static void * -+# endif -+expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { -+ assert(parser != NULL); -+ -+ if (ptr == NULL) { -+ return expat_malloc(parser, size, sourceLine); -+ } -+ -+ if (size == 0) { -+ expat_free(parser, ptr, sourceLine); -+ return NULL; -+ } -+ -+ const XML_Parser rootParser = getRootParserOf(parser, NULL); -+ assert(rootParser->m_parentParser == NULL); -+ -+ // Extract original size (to the eyes of the caller) and the original -+ // pointer returned by malloc/realloc -+ void *mallocedPtr = (char *)ptr - sizeof(size_t); -+ const size_t prevSize = *(size_t *)mallocedPtr; -+ -+ // Classify upcoming change -+ const bool isIncrease = (size > prevSize); -+ const size_t absDiff -+ = (size > prevSize) ? (size - prevSize) : (prevSize - size); -+ -+ // Ask for permission from accounting -+ if (isIncrease) { -+ if (! expat_heap_increase_tolerable(rootParser, absDiff, sourceLine)) { -+ return NULL; // i.e. signal violation as out-of-memory -+ } -+ } -+ -+ // Actually allocate -+ mallocedPtr = parser->m_mem.realloc_fcn(mallocedPtr, sizeof(size_t) + size); -+ -+ if (mallocedPtr == NULL) { -+ return NULL; -+ } -+ -+ // Update accounting -+ if (isIncrease) { -+ assert((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated -+ >= absDiff); -+ rootParser->m_alloc_tracker.bytesAllocated += absDiff; -+ } else { // i.e. decrease -+ assert(rootParser->m_alloc_tracker.bytesAllocated >= absDiff); -+ rootParser->m_alloc_tracker.bytesAllocated -= absDiff; -+ } -+ -+ // Report as needed -+ if (rootParser->m_alloc_tracker.debugLevel >= 2) { -+ if (rootParser->m_alloc_tracker.bytesAllocated -+ > rootParser->m_alloc_tracker.peakBytesAllocated) { -+ rootParser->m_alloc_tracker.peakBytesAllocated -+ = rootParser->m_alloc_tracker.bytesAllocated; -+ } -+ expat_heap_stat(rootParser, isIncrease ? '+' : '-', absDiff, -+ rootParser->m_alloc_tracker.bytesAllocated, -+ rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); -+ } -+ -+ // Update in-block recorded size -+ *(size_t *)mallocedPtr = size; -+ -+ return (char *)mallocedPtr + sizeof(size_t); -+} -+#endif // XML_GE == 1 - - XML_Parser XMLCALL - XML_ParserCreate(const XML_Char *encodingName) { -@@ -1100,19 +1323,40 @@ XML_Parser XMLCALL - XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) { -- return parserCreate(encodingName, memsuite, nameSep, NULL); -+ return parserCreate(encodingName, memsuite, nameSep, NULL, NULL); - } - - static XML_Parser - parserCreate(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, const XML_Char *nameSep, -- DTD *dtd) { -- XML_Parser parser; -+ DTD *dtd, XML_Parser parentParser) { -+ XML_Parser parser = NULL; -+ -+#if XML_GE == 1 -+ const size_t increase = sizeof(size_t) + sizeof(struct XML_ParserStruct); -+ -+ if (parentParser != NULL) { -+ const XML_Parser rootParser = getRootParserOf(parentParser, NULL); -+ if (! expat_heap_increase_tolerable(rootParser, increase, __LINE__)) { -+ return NULL; -+ } -+ } -+#else -+ UNUSED_P(parentParser); -+#endif - - if (memsuite) { - XML_Memory_Handling_Suite *mtemp; -+#if XML_GE == 1 -+ void *const sizeAndParser = memsuite->malloc_fcn( -+ sizeof(size_t) + sizeof(struct XML_ParserStruct)); -+ if (sizeAndParser != NULL) { -+ *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); -+ parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)); -+#else - parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); - if (parser != NULL) { -+#endif - mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); - mtemp->malloc_fcn = memsuite->malloc_fcn; - mtemp->realloc_fcn = memsuite->realloc_fcn; -@@ -1120,18 +1364,67 @@ parserCreate(const XML_Char *encodingName, - } - } else { - XML_Memory_Handling_Suite *mtemp; -+#if XML_GE == 1 -+ void *const sizeAndParser -+ = (XML_Parser)malloc(sizeof(size_t) + sizeof(struct XML_ParserStruct)); -+ if (sizeAndParser != NULL) { -+ *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); -+ parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)); -+#else - parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct)); - if (parser != NULL) { -+#endif - mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); - mtemp->malloc_fcn = malloc; - mtemp->realloc_fcn = realloc; - mtemp->free_fcn = free; - } -- } -+ } // cppcheck-suppress[memleak symbolName=sizeAndParser] // Cppcheck >=2.18.0 - - if (! parser) - return parser; - -+#if XML_GE == 1 -+ // Initialize .m_alloc_tracker -+ memset(&parser->m_alloc_tracker, 0, sizeof(MALLOC_TRACKER)); -+ if (parentParser == NULL) { -+ parser->m_alloc_tracker.debugLevel -+ = getDebugLevel("EXPAT_MALLOC_DEBUG", 0u); -+ parser->m_alloc_tracker.maximumAmplificationFactor -+ = EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT; -+ parser->m_alloc_tracker.activationThresholdBytes -+ = EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT; -+ -+ // NOTE: This initialization needs to come this early because these fields -+ // are read by allocation tracking code -+ parser->m_parentParser = NULL; -+ parser->m_accounting.countBytesDirect = 0; -+ } else { -+ parser->m_parentParser = parentParser; -+ } -+ -+ // Record XML_ParserStruct allocation we did a few lines up before -+ const XML_Parser rootParser = getRootParserOf(parser, NULL); -+ assert(rootParser->m_parentParser == NULL); -+ assert(SIZE_MAX - rootParser->m_alloc_tracker.bytesAllocated >= increase); -+ rootParser->m_alloc_tracker.bytesAllocated += increase; -+ -+ // Report on allocation -+ if (rootParser->m_alloc_tracker.debugLevel >= 2) { -+ if (rootParser->m_alloc_tracker.bytesAllocated -+ > rootParser->m_alloc_tracker.peakBytesAllocated) { -+ rootParser->m_alloc_tracker.peakBytesAllocated -+ = rootParser->m_alloc_tracker.bytesAllocated; -+ } -+ -+ expat_heap_stat(rootParser, '+', increase, -+ rootParser->m_alloc_tracker.bytesAllocated, -+ rootParser->m_alloc_tracker.peakBytesAllocated, __LINE__); -+ } -+#else -+ parser->m_parentParser = NULL; -+#endif // XML_GE == 1 -+ - parser->m_buffer = NULL; - parser->m_bufferLim = NULL; - -@@ -1166,7 +1459,7 @@ parserCreate(const XML_Char *encodingName, - if (dtd) - parser->m_dtd = dtd; - else { -- parser->m_dtd = dtdCreate(&parser->m_mem); -+ parser->m_dtd = dtdCreate(parser); - if (parser->m_dtd == NULL) { - FREE(parser, parser->m_dataBuf); - FREE(parser, parser->m_atts); -@@ -1200,8 +1493,8 @@ parserCreate(const XML_Char *encodingName, - - parser->m_protocolEncodingName = NULL; - -- poolInit(&parser->m_tempPool, &(parser->m_mem)); -- poolInit(&parser->m_temp2Pool, &(parser->m_mem)); -+ poolInit(&parser->m_tempPool, parser); -+ poolInit(&parser->m_temp2Pool, parser); - parserInit(parser, encodingName); - - if (encodingName && ! parser->m_protocolEncodingName) { -@@ -1233,7 +1526,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) { - parser->m_processor = prologInitProcessor; - XmlPrologStateInit(&parser->m_prologState); - if (encodingName != NULL) { -- parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem)); -+ parser->m_protocolEncodingName = copyString(encodingName, parser); - } - parser->m_curBase = NULL; - XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0); -@@ -1295,7 +1588,6 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) { - parser->m_unknownEncodingMem = NULL; - parser->m_unknownEncodingRelease = NULL; - parser->m_unknownEncodingData = NULL; -- parser->m_parentParser = NULL; - parser->m_parsingStatus.parsing = XML_INITIALIZED; - // Reentry can only be triggered inside m_processor calls - parser->m_reenter = XML_FALSE; -@@ -1385,7 +1677,7 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) { - FREE(parser, (void *)parser->m_protocolEncodingName); - parser->m_protocolEncodingName = NULL; - parserInit(parser, encodingName); -- dtdReset(parser->m_dtd, &parser->m_mem); -+ dtdReset(parser->m_dtd, parser); - return XML_TRUE; - } - -@@ -1421,7 +1713,7 @@ XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) { - parser->m_protocolEncodingName = NULL; - else { - /* Copy the new encoding name into allocated memory */ -- parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem)); -+ parser->m_protocolEncodingName = copyString(encodingName, parser); - if (! parser->m_protocolEncodingName) - return XML_STATUS_ERROR; - } -@@ -1530,9 +1822,10 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, - */ - if (parser->m_ns) { - XML_Char tmp[2] = {parser->m_namespaceSeparator, 0}; -- parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); -+ parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd, oldParser); - } else { -- parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); -+ parser -+ = parserCreate(encodingName, &parser->m_mem, NULL, newDtd, oldParser); - } - - if (! parser) -@@ -1576,7 +1869,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, - parser->m_prologState.inEntityValue = oldInEntityValue; - if (context) { - #endif /* XML_DTD */ -- if (! dtdCopy(oldParser, parser->m_dtd, oldDtd, &parser->m_mem) -+ if (! dtdCopy(oldParser, parser->m_dtd, oldDtd, parser) - || ! setContext(parser, context)) { - XML_ParserFree(parser); - return NULL; -@@ -1688,14 +1981,16 @@ XML_ParserFree(XML_Parser parser) { - #else - if (parser->m_dtd) - #endif /* XML_DTD */ -- dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser, -- &parser->m_mem); -+ dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser, parser); - FREE(parser, (void *)parser->m_atts); - #ifdef XML_ATTR_INFO - FREE(parser, (void *)parser->m_attInfo); - #endif - FREE(parser, parser->m_groupConnector); -- FREE(parser, parser->m_buffer); -+ // NOTE: We are avoiding FREE(..) here because parser->m_buffer -+ // is not being allocated with MALLOC(..) but with plain -+ // .malloc_fcn(..). -+ parser->m_mem.free_fcn(parser->m_buffer); - FREE(parser, parser->m_dataBuf); - FREE(parser, parser->m_nsAtts); - FREE(parser, parser->m_unknownEncodingMem); -@@ -2287,7 +2582,9 @@ XML_GetBuffer(XML_Parser parser, int len) { - parser->m_errorCode = XML_ERROR_NO_MEMORY; - return NULL; - } -- newBuf = (char *)MALLOC(parser, bufferSize); -+ // NOTE: We are avoiding MALLOC(..) here to leave limiting -+ // the input size to the application using Expat. -+ newBuf = (char *)parser->m_mem.malloc_fcn(bufferSize); - if (newBuf == 0) { - parser->m_errorCode = XML_ERROR_NO_MEMORY; - return NULL; -@@ -2298,7 +2595,10 @@ XML_GetBuffer(XML_Parser parser, int len) { - memcpy(newBuf, &parser->m_bufferPtr[-keep], - EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) - + keep); -- FREE(parser, parser->m_buffer); -+ // NOTE: We are avoiding FREE(..) here because parser->m_buffer -+ // is not being allocated with MALLOC(..) but with plain -+ // .malloc_fcn(..). -+ parser->m_mem.free_fcn(parser->m_buffer); - parser->m_buffer = newBuf; - parser->m_bufferEnd - = parser->m_buffer -@@ -2314,7 +2614,10 @@ XML_GetBuffer(XML_Parser parser, int len) { - if (parser->m_bufferPtr) { - memcpy(newBuf, parser->m_bufferPtr, - EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)); -- FREE(parser, parser->m_buffer); -+ // NOTE: We are avoiding FREE(..) here because parser->m_buffer -+ // is not being allocated with MALLOC(..) but with plain -+ // .malloc_fcn(..). -+ parser->m_mem.free_fcn(parser->m_buffer); - parser->m_bufferEnd - = newBuf - + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr); -@@ -2492,28 +2795,43 @@ XML_GetCurrentColumnNumber(XML_Parser parser) { - - void XMLCALL - XML_FreeContentModel(XML_Parser parser, XML_Content *model) { -- if (parser != NULL) -- FREE(parser, model); -+ if (parser == NULL) -+ return; -+ -+ // NOTE: We are avoiding FREE(..) here because the content model -+ // has been created using plain .malloc_fcn(..) rather than MALLOC(..). -+ parser->m_mem.free_fcn(model); - } - - void *XMLCALL - XML_MemMalloc(XML_Parser parser, size_t size) { - if (parser == NULL) - return NULL; -- return MALLOC(parser, size); -+ -+ // NOTE: We are avoiding MALLOC(..) here to not include -+ // user allocations with allocation tracking and limiting. -+ return parser->m_mem.malloc_fcn(size); - } - - void *XMLCALL - XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) { - if (parser == NULL) - return NULL; -- return REALLOC(parser, ptr, size); -+ -+ // NOTE: We are avoiding REALLOC(..) here to not include -+ // user allocations with allocation tracking and limiting. -+ return parser->m_mem.realloc_fcn(ptr, size); - } - - void XMLCALL - XML_MemFree(XML_Parser parser, void *ptr) { -- if (parser != NULL) -- FREE(parser, ptr); -+ if (parser == NULL) -+ return; -+ -+ // NOTE: We are avoiding FREE(..) here because XML_MemMalloc and -+ // XML_MemRealloc are not using MALLOC(..) and REALLOC(..) -+ // but plain .malloc_fcn(..) and .realloc_fcn(..), internally. -+ parser->m_mem.free_fcn(ptr); - } - - void XMLCALL -@@ -2713,6 +3031,13 @@ XML_GetFeatureList(void) { - EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT}, - /* Added in Expat 2.6.0. */ - {XML_FEATURE_GE, XML_L("XML_GE"), 0}, -+ /* Added in Expat 2.7.2. */ -+ {XML_FEATURE_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT, -+ XML_L("XML_AT_MAX_AMP"), -+ (long int)EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT}, -+ {XML_FEATURE_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT, -+ XML_L("XML_AT_ACT_THRES"), -+ (long int)EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT}, - #endif - {XML_FEATURE_END, NULL, 0}}; - -@@ -2741,6 +3066,29 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( - parser->m_accounting.activationThresholdBytes = activationThresholdBytes; - return XML_TRUE; - } -+ -+XML_Bool XMLCALL -+XML_SetAllocTrackerMaximumAmplification(XML_Parser parser, -+ float maximumAmplificationFactor) { -+ if ((parser == NULL) || (parser->m_parentParser != NULL) -+ || isnan(maximumAmplificationFactor) -+ || (maximumAmplificationFactor < 1.0f)) { -+ return XML_FALSE; -+ } -+ parser->m_alloc_tracker.maximumAmplificationFactor -+ = maximumAmplificationFactor; -+ return XML_TRUE; -+} -+ -+XML_Bool XMLCALL -+XML_SetAllocTrackerActivationThreshold( -+ XML_Parser parser, unsigned long long activationThresholdBytes) { -+ if ((parser == NULL) || (parser->m_parentParser != NULL)) { -+ return XML_FALSE; -+ } -+ parser->m_alloc_tracker.activationThresholdBytes = activationThresholdBytes; -+ return XML_TRUE; -+} - #endif /* XML_GE == 1 */ - - XML_Bool XMLCALL -@@ -5726,8 +6074,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, - case XML_ROLE_CONTENT_EMPTY: - if (dtd->in_eldecl) { - if (parser->m_elementDeclHandler) { -+ // NOTE: We are avoiding MALLOC(..) here to so that -+ // applications that are not using XML_FreeContentModel but -+ // plain free(..) or .free_fcn() to free the content model's -+ // memory are safe. - XML_Content *content -- = (XML_Content *)MALLOC(parser, sizeof(XML_Content)); -+ = (XML_Content *)parser->m_mem.malloc_fcn(sizeof(XML_Content)); - if (! content) - return XML_ERROR_NO_MEMORY; - content->quant = XML_CQUANT_NONE; -@@ -7116,19 +7468,19 @@ normalizePublicId(XML_Char *publicId) { - } - - static DTD * --dtdCreate(const XML_Memory_Handling_Suite *ms) { -- DTD *p = ms->malloc_fcn(sizeof(DTD)); -+dtdCreate(XML_Parser parser) { -+ DTD *p = MALLOC(parser, sizeof(DTD)); - if (p == NULL) - return p; -- poolInit(&(p->pool), ms); -- poolInit(&(p->entityValuePool), ms); -- hashTableInit(&(p->generalEntities), ms); -- hashTableInit(&(p->elementTypes), ms); -- hashTableInit(&(p->attributeIds), ms); -- hashTableInit(&(p->prefixes), ms); -+ poolInit(&(p->pool), parser); -+ poolInit(&(p->entityValuePool), parser); -+ hashTableInit(&(p->generalEntities), parser); -+ hashTableInit(&(p->elementTypes), parser); -+ hashTableInit(&(p->attributeIds), parser); -+ hashTableInit(&(p->prefixes), parser); - #ifdef XML_DTD - p->paramEntityRead = XML_FALSE; -- hashTableInit(&(p->paramEntities), ms); -+ hashTableInit(&(p->paramEntities), parser); - #endif /* XML_DTD */ - p->defaultPrefix.name = NULL; - p->defaultPrefix.binding = NULL; -@@ -7148,7 +7500,7 @@ dtdCreate(const XML_Memory_Handling_Suite *ms) { - } - - static void --dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { -+dtdReset(DTD *p, XML_Parser parser) { - HASH_TABLE_ITER iter; - hashTableIterInit(&iter, &(p->elementTypes)); - for (;;) { -@@ -7156,7 +7508,7 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { - if (! e) - break; - if (e->allocDefaultAtts != 0) -- ms->free_fcn(e->defaultAtts); -+ FREE(parser, e->defaultAtts); - } - hashTableClear(&(p->generalEntities)); - #ifdef XML_DTD -@@ -7173,9 +7525,9 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { - - p->in_eldecl = XML_FALSE; - -- ms->free_fcn(p->scaffIndex); -+ FREE(parser, p->scaffIndex); - p->scaffIndex = NULL; -- ms->free_fcn(p->scaffold); -+ FREE(parser, p->scaffold); - p->scaffold = NULL; - - p->scaffLevel = 0; -@@ -7189,7 +7541,7 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { - } - - static void --dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { -+dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser) { - HASH_TABLE_ITER iter; - hashTableIterInit(&iter, &(p->elementTypes)); - for (;;) { -@@ -7197,7 +7549,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { - if (! e) - break; - if (e->allocDefaultAtts != 0) -- ms->free_fcn(e->defaultAtts); -+ FREE(parser, e->defaultAtts); - } - hashTableDestroy(&(p->generalEntities)); - #ifdef XML_DTD -@@ -7209,10 +7561,10 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { - poolDestroy(&(p->pool)); - poolDestroy(&(p->entityValuePool)); - if (isDocEntity) { -- ms->free_fcn(p->scaffIndex); -- ms->free_fcn(p->scaffold); -+ FREE(parser, p->scaffIndex); -+ FREE(parser, p->scaffold); - } -- ms->free_fcn(p); -+ FREE(parser, p); - } - - /* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise. -@@ -7220,7 +7572,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { - */ - static int - dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, -- const XML_Memory_Handling_Suite *ms) { -+ XML_Parser parser) { - HASH_TABLE_ITER iter; - - /* Copy the prefix table. */ -@@ -7301,7 +7653,7 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, - } - #endif - newE->defaultAtts -- = ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); -+ = MALLOC(parser, oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); - if (! newE->defaultAtts) { - return 0; - } -@@ -7463,7 +7815,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { - /* table->size is a power of 2 */ - table->size = (size_t)1 << INIT_POWER; - tsize = table->size * sizeof(NAMED *); -- table->v = table->mem->malloc_fcn(tsize); -+ table->v = MALLOC(table->parser, tsize); - if (! table->v) { - table->size = 0; - return NULL; -@@ -7503,7 +7855,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { - } - - size_t tsize = newSize * sizeof(NAMED *); -- NAMED **newV = table->mem->malloc_fcn(tsize); -+ NAMED **newV = MALLOC(table->parser, tsize); - if (! newV) - return NULL; - memset(newV, 0, tsize); -@@ -7519,7 +7871,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { - } - newV[j] = table->v[i]; - } -- table->mem->free_fcn(table->v); -+ FREE(table->parser, table->v); - table->v = newV; - table->power = newPower; - table->size = newSize; -@@ -7532,7 +7884,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { - } - } - } -- table->v[i] = table->mem->malloc_fcn(createSize); -+ table->v[i] = MALLOC(table->parser, createSize); - if (! table->v[i]) - return NULL; - memset(table->v[i], 0, createSize); -@@ -7545,7 +7897,7 @@ static void FASTCALL - hashTableClear(HASH_TABLE *table) { - size_t i; - for (i = 0; i < table->size; i++) { -- table->mem->free_fcn(table->v[i]); -+ FREE(table->parser, table->v[i]); - table->v[i] = NULL; - } - table->used = 0; -@@ -7555,17 +7907,17 @@ static void FASTCALL - hashTableDestroy(HASH_TABLE *table) { - size_t i; - for (i = 0; i < table->size; i++) -- table->mem->free_fcn(table->v[i]); -- table->mem->free_fcn(table->v); -+ FREE(table->parser, table->v[i]); -+ FREE(table->parser, table->v); - } - - static void FASTCALL --hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) { -+hashTableInit(HASH_TABLE *p, XML_Parser parser) { - p->power = 0; - p->size = 0; - p->used = 0; - p->v = NULL; -- p->mem = ms; -+ p->parser = parser; - } - - static void FASTCALL -@@ -7585,13 +7937,13 @@ hashTableIterNext(HASH_TABLE_ITER *iter) { - } - - static void FASTCALL --poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) { -+poolInit(STRING_POOL *pool, XML_Parser parser) { - pool->blocks = NULL; - pool->freeBlocks = NULL; - pool->start = NULL; - pool->ptr = NULL; - pool->end = NULL; -- pool->mem = ms; -+ pool->parser = parser; - } - - static void FASTCALL -@@ -7618,13 +7970,13 @@ poolDestroy(STRING_POOL *pool) { - BLOCK *p = pool->blocks; - while (p) { - BLOCK *tem = p->next; -- pool->mem->free_fcn(p); -+ FREE(pool->parser, p); - p = tem; - } - p = pool->freeBlocks; - while (p) { - BLOCK *tem = p->next; -- pool->mem->free_fcn(p); -+ FREE(pool->parser, p); - p = tem; - } - } -@@ -7779,8 +8131,8 @@ poolGrow(STRING_POOL *pool) { - if (bytesToAllocate == 0) - return XML_FALSE; - -- temp = (BLOCK *)pool->mem->realloc_fcn(pool->blocks, -- (unsigned)bytesToAllocate); -+ temp = (BLOCK *)REALLOC(pool->parser, pool->blocks, -+ (unsigned)bytesToAllocate); - if (temp == NULL) - return XML_FALSE; - pool->blocks = temp; -@@ -7820,7 +8172,7 @@ poolGrow(STRING_POOL *pool) { - if (bytesToAllocate == 0) - return XML_FALSE; - -- tem = pool->mem->malloc_fcn(bytesToAllocate); -+ tem = MALLOC(pool->parser, bytesToAllocate); - if (! tem) - return XML_FALSE; - tem->size = blockSize; -@@ -7935,7 +8287,10 @@ build_model(XML_Parser parser) { - const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content) - + (dtd->contentStringLen * sizeof(XML_Char))); - -- ret = (XML_Content *)MALLOC(parser, allocsize); -+ // NOTE: We are avoiding MALLOC(..) here to so that -+ // applications that are not using XML_FreeContentModel but plain -+ // free(..) or .free_fcn() to free the content model's memory are safe. -+ ret = (XML_Content *)parser->m_mem.malloc_fcn(allocsize); - if (! ret) - return NULL; - -@@ -8056,7 +8411,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, - } - - static XML_Char * --copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { -+copyString(const XML_Char *s, XML_Parser parser) { - size_t charsRequired = 0; - XML_Char *result; - -@@ -8068,7 +8423,7 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { - charsRequired++; - - /* Now allocate space for the copy */ -- result = memsuite->malloc_fcn(charsRequired * sizeof(XML_Char)); -+ result = MALLOC(parser, charsRequired * sizeof(XML_Char)); - if (result == NULL) - return NULL; - /* Copy the original into place */ -diff --git a/tests/alloc_tests.c b/tests/alloc_tests.c -index 12ea3b2..47004a9 100644 ---- a/tests/alloc_tests.c -+++ b/tests/alloc_tests.c -@@ -46,10 +46,16 @@ - # undef NDEBUG /* because test suite relies on assert(...) at the moment */ - #endif - -+#include /* NAN, INFINITY */ -+#include -+#include /* for SIZE_MAX */ - #include - #include - -+#include "expat_config.h" -+ - #include "expat.h" -+#include "internal.h" - #include "common.h" - #include "minicheck.h" - #include "dummy.h" -@@ -2085,6 +2091,203 @@ START_TEST(test_alloc_reset_after_external_entity_parser_create_fail) { - } - END_TEST - -+START_TEST(test_alloc_tracker_size_recorded) { -+ XML_Memory_Handling_Suite memsuite = {malloc, realloc, free}; -+ -+ bool values[] = {true, false}; -+ for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) { -+ const bool useMemSuite = values[i]; -+ set_subtest("useMemSuite=%d", (int)useMemSuite); -+ XML_Parser parser = useMemSuite -+ ? XML_ParserCreate_MM(NULL, &memsuite, XCS("|")) -+ : XML_ParserCreate(NULL); -+ -+#if XML_GE == 1 -+ void *ptr = expat_malloc(parser, 10, -1); -+ -+ assert_true(ptr != NULL); -+ assert_true(*((size_t *)ptr - 1) == 10); -+ -+ assert_true(expat_realloc(parser, ptr, SIZE_MAX / 2, -1) == NULL); -+ -+ assert_true(*((size_t *)ptr - 1) == 10); // i.e. unchanged -+ -+ ptr = expat_realloc(parser, ptr, 20, -1); -+ -+ assert_true(ptr != NULL); -+ assert_true(*((size_t *)ptr - 1) == 20); -+ -+ expat_free(parser, ptr, -1); -+#endif -+ -+ XML_ParserFree(parser); -+ } -+} -+END_TEST -+ -+START_TEST(test_alloc_tracker_maximum_amplification) { -+ if (g_reparseDeferralEnabledDefault == XML_TRUE) { -+ return; -+ } -+ -+ XML_Parser parser = XML_ParserCreate(NULL); -+ -+ // Get .m_accounting.countBytesDirect from 0 to 3 -+ const char *const chunk = " "; -+ assert_true(_XML_Parse_SINGLE_BYTES(parser, chunk, (int)strlen(chunk), -+ /*isFinal=*/XML_FALSE) -+ == XML_STATUS_OK); -+ -+#if XML_GE == 1 -+ // Stop activation threshold from interfering -+ assert_true(XML_SetAllocTrackerActivationThreshold(parser, 0) == XML_TRUE); -+ -+ // Exceed maximum amplification: should be rejected. -+ assert_true(expat_malloc(parser, 1000, -1) == NULL); -+ -+ // Increase maximum amplification, and try the same amount once more: should -+ // work. -+ assert_true(XML_SetAllocTrackerMaximumAmplification(parser, 3000.0f) -+ == XML_TRUE); -+ -+ void *const ptr = expat_malloc(parser, 1000, -1); -+ assert_true(ptr != NULL); -+ expat_free(parser, ptr, -1); -+#endif -+ -+ XML_ParserFree(parser); -+} -+END_TEST -+ -+START_TEST(test_alloc_tracker_threshold) { -+ XML_Parser parser = XML_ParserCreate(NULL); -+ -+#if XML_GE == 1 -+ // Exceed maximum amplification *before* (default) threshold: should work. -+ void *const ptr = expat_malloc(parser, 1000, -1); -+ assert_true(ptr != NULL); -+ expat_free(parser, ptr, -1); -+ -+ // Exceed maximum amplification *after* threshold: should be rejected. -+ assert_true(XML_SetAllocTrackerActivationThreshold(parser, 999) == XML_TRUE); -+ assert_true(expat_malloc(parser, 1000, -1) == NULL); -+#endif -+ -+ XML_ParserFree(parser); -+} -+END_TEST -+ -+START_TEST(test_alloc_tracker_getbuffer_unlimited) { -+ XML_Parser parser = XML_ParserCreate(NULL); -+ -+#if XML_GE == 1 -+ // Artificially lower threshold -+ assert_true(XML_SetAllocTrackerActivationThreshold(parser, 0) == XML_TRUE); -+ -+ // Self-test: Prove that threshold is as rejecting as expected -+ assert_true(expat_malloc(parser, 1000, -1) == NULL); -+#endif -+ // XML_GetBuffer should be allowed to pass, though -+ assert_true(XML_GetBuffer(parser, 1000) != NULL); -+ -+ XML_ParserFree(parser); -+} -+END_TEST -+ -+START_TEST(test_alloc_tracker_api) { -+ XML_Parser parserWithoutParent = XML_ParserCreate(NULL); -+ XML_Parser parserWithParent = XML_ExternalEntityParserCreate( -+ parserWithoutParent, XCS("entity123"), NULL); -+ if (parserWithoutParent == NULL) -+ fail("parserWithoutParent is NULL"); -+ if (parserWithParent == NULL) -+ fail("parserWithParent is NULL"); -+ -+#if XML_GE == 1 -+ // XML_SetAllocTrackerMaximumAmplification, error cases -+ if (XML_SetAllocTrackerMaximumAmplification(NULL, 123.0f) == XML_TRUE) -+ fail("Call with NULL parser is NOT supposed to succeed"); -+ if (XML_SetAllocTrackerMaximumAmplification(parserWithParent, 123.0f) -+ == XML_TRUE) -+ fail("Call with non-root parser is NOT supposed to succeed"); -+ if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, NAN) -+ == XML_TRUE) -+ fail("Call with NaN limit is NOT supposed to succeed"); -+ if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, -1.0f) -+ == XML_TRUE) -+ fail("Call with negative limit is NOT supposed to succeed"); -+ if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, 0.9f) -+ == XML_TRUE) -+ fail("Call with positive limit <1.0 is NOT supposed to succeed"); -+ -+ // XML_SetAllocTrackerMaximumAmplification, success cases -+ if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, 1.0f) -+ == XML_FALSE) -+ fail("Call with positive limit >=1.0 is supposed to succeed"); -+ if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, 123456.789f) -+ == XML_FALSE) -+ fail("Call with positive limit >=1.0 is supposed to succeed"); -+ if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, INFINITY) -+ == XML_FALSE) -+ fail("Call with positive limit >=1.0 is supposed to succeed"); -+ -+ // XML_SetAllocTrackerActivationThreshold, error cases -+ if (XML_SetAllocTrackerActivationThreshold(NULL, 123) == XML_TRUE) -+ fail("Call with NULL parser is NOT supposed to succeed"); -+ if (XML_SetAllocTrackerActivationThreshold(parserWithParent, 123) == XML_TRUE) -+ fail("Call with non-root parser is NOT supposed to succeed"); -+ -+ // XML_SetAllocTrackerActivationThreshold, success cases -+ if (XML_SetAllocTrackerActivationThreshold(parserWithoutParent, 123) -+ == XML_FALSE) -+ fail("Call with non-NULL parentless parser is supposed to succeed"); -+#endif // XML_GE == 1 -+ -+ XML_ParserFree(parserWithParent); -+ XML_ParserFree(parserWithoutParent); -+} -+END_TEST -+ -+START_TEST(test_mem_api_cycle) { -+ XML_Parser parser = XML_ParserCreate(NULL); -+ -+ void *ptr = XML_MemMalloc(parser, 10); -+ -+ assert_true(ptr != NULL); -+ memset(ptr, 'x', 10); // assert writability, with ASan in mind -+ -+ ptr = XML_MemRealloc(parser, ptr, 20); -+ -+ assert_true(ptr != NULL); -+ memset(ptr, 'y', 20); // assert writability, with ASan in mind -+ -+ XML_MemFree(parser, ptr); -+ -+ XML_ParserFree(parser); -+} -+END_TEST -+ -+START_TEST(test_mem_api_unlimited) { -+ XML_Parser parser = XML_ParserCreate(NULL); -+ -+#if XML_GE == 1 -+ assert_true(XML_SetAllocTrackerActivationThreshold(parser, 0) == XML_TRUE); -+#endif -+ -+ void *ptr = XML_MemMalloc(parser, 1000); -+ -+ assert_true(ptr != NULL); -+ -+ ptr = XML_MemRealloc(parser, ptr, 2000); -+ -+ assert_true(ptr != NULL); -+ -+ XML_MemFree(parser, ptr); -+ -+ XML_ParserFree(parser); -+} -+END_TEST -+ - void - make_alloc_test_case(Suite *s) { - TCase *tc_alloc = tcase_create("allocation tests"); -@@ -2151,4 +2354,15 @@ make_alloc_test_case(Suite *s) { - - tcase_add_test__ifdef_xml_dtd( - tc_alloc, test_alloc_reset_after_external_entity_parser_create_fail); -+ -+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_size_recorded); -+ tcase_add_test__ifdef_xml_dtd(tc_alloc, -+ test_alloc_tracker_maximum_amplification); -+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_threshold); -+ tcase_add_test__ifdef_xml_dtd(tc_alloc, -+ test_alloc_tracker_getbuffer_unlimited); -+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_api); -+ -+ tcase_add_test(tc_alloc, test_mem_api_cycle); -+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_mem_api_unlimited); - } -diff --git a/tests/basic_tests.c b/tests/basic_tests.c -index f0025fc..da5c0d4 100644 ---- a/tests/basic_tests.c -+++ b/tests/basic_tests.c -@@ -3002,6 +3002,10 @@ START_TEST(test_buffer_can_grow_to_max) { - for (int i = 0; i < num_prefixes; ++i) { - set_subtest("\"%s\"", prefixes[i]); - XML_Parser parser = XML_ParserCreate(NULL); -+#if XML_GE == 1 -+ assert_true(XML_SetAllocTrackerActivationThreshold(parser, (size_t)-1) -+ == XML_TRUE); // i.e. deactivate -+#endif - const int prefix_len = (int)strlen(prefixes[i]); - const enum XML_Status s - = _XML_Parse_SINGLE_BYTES(parser, prefixes[i], prefix_len, XML_FALSE); -diff --git a/tests/nsalloc_tests.c b/tests/nsalloc_tests.c -index ec88586..a8f5718 100644 ---- a/tests/nsalloc_tests.c -+++ b/tests/nsalloc_tests.c -@@ -454,10 +454,15 @@ START_TEST(test_nsalloc_realloc_attributes) { - nsalloc_teardown(); - nsalloc_setup(); - } -+#if XML_GE == 1 -+ assert_true( -+ i == 0); // because expat_realloc relies on expat_malloc to some extent -+#else - if (i == 0) - fail("Parsing worked despite failing reallocations"); - else if (i == max_realloc_count) - fail("Parsing failed at max reallocation count"); -+#endif - } - END_TEST - -diff --git a/xmlwf/xmlwf.c b/xmlwf/xmlwf.c -index 7c0a8cd..92adb1a 100644 ---- a/xmlwf/xmlwf.c -+++ b/xmlwf/xmlwf.c -@@ -913,11 +913,11 @@ usage(const XML_Char *prog, int rc) { - T(" -t write no XML output for [t]iming of plain parsing\n") - T(" -N enable adding doctype and [n]otation declarations\n") - T("\n") -- T("billion laughs attack protection:\n") -+ T("amplification attack protection (e.g. billion laughs):\n") - T(" NOTE: If you ever need to increase these values for non-attack payload, please file a bug report.\n") - T("\n") - T(" -a FACTOR set maximum tolerated [a]mplification factor (default: 100.0)\n") -- T(" -b BYTES set number of output [b]ytes needed to activate (default: 8 MiB)\n") -+ T(" -b BYTES set number of output [b]ytes needed to activate (default: 8 MiB/64 MiB)\n") - T("\n") - T("reparse deferral:\n") - T(" -q disable reparse deferral, and allow [q]uadratic parse runtime with large tokens\n") -@@ -926,6 +926,10 @@ usage(const XML_Char *prog, int rc) { - T(" -h, --help show this [h]elp message and exit\n") - T(" -v, --version show program's [v]ersion number and exit\n") - T("\n") -+ T("environment variables:\n") -+ T(" EXPAT_MALLOC_DEBUG=(0|1|2)\n") -+ T(" Control verbosity of allocation tracker (default: 0)\n") -+ T("\n") - T("exit status:\n") - T(" 0 the input files are well-formed and the output (if requested) was written successfully\n") - T(" 1 could not allocate data structures, signals a serious problem with execution environment\n") -@@ -1171,12 +1175,15 @@ tmain(int argc, XML_Char **argv) { - #if XML_GE == 1 - XML_SetBillionLaughsAttackProtectionMaximumAmplification( - parser, attackMaximumAmplification); -+ XML_SetAllocTrackerMaximumAmplification(parser, -+ attackMaximumAmplification); - #endif - } - if (attackThresholdGiven) { - #if XML_GE == 1 - XML_SetBillionLaughsAttackProtectionActivationThreshold( - parser, attackThresholdBytes); -+ XML_SetAllocTrackerActivationThreshold(parser, attackThresholdBytes); - #else - (void)attackThresholdBytes; // silence -Wunused-but-set-variable - #endif -diff --git a/xmlwf/xmlwf_helpgen.py b/xmlwf/xmlwf_helpgen.py -index 3d32f5d..dcae018 100755 ---- a/xmlwf/xmlwf_helpgen.py -+++ b/xmlwf/xmlwf_helpgen.py -@@ -32,6 +32,9 @@ - import argparse - - epilog = """ -+environment variables: -+ EXPAT_MALLOC_DEBUG=(0|1|2) -+ Control verbosity of allocation tracker (default: 0) - exit status: - 0 the input files are well-formed and the output (if requested) was written successfully - 1 could not allocate data structures, signals a serious problem with execution environment --- -2.43.0 - diff --git a/SPECS/expat/CVE-2026-24515.patch b/SPECS/expat/CVE-2026-24515.patch deleted file mode 100644 index f83bc89770a..00000000000 --- a/SPECS/expat/CVE-2026-24515.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 8b3805af3dde1f5424bdd704da688def3a81ff9f Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Sun, 18 Jan 2026 17:53:37 +0100 -Subject: [PATCH 1/3] lib: Make XML_ExternalEntityParserCreate copy unknown - encoding handler user data - -Patch suggested by Artiphishell Inc. ---- - lib/xmlparse.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index e2847b1..d804753 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -1742,6 +1742,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, - XML_ExternalEntityRefHandler oldExternalEntityRefHandler; - XML_SkippedEntityHandler oldSkippedEntityHandler; - XML_UnknownEncodingHandler oldUnknownEncodingHandler; -+ void *oldUnknownEncodingHandlerData; - XML_ElementDeclHandler oldElementDeclHandler; - XML_AttlistDeclHandler oldAttlistDeclHandler; - XML_EntityDeclHandler oldEntityDeclHandler; -@@ -1787,6 +1788,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, - oldExternalEntityRefHandler = parser->m_externalEntityRefHandler; - oldSkippedEntityHandler = parser->m_skippedEntityHandler; - oldUnknownEncodingHandler = parser->m_unknownEncodingHandler; -+ oldUnknownEncodingHandlerData = parser->m_unknownEncodingHandlerData; - oldElementDeclHandler = parser->m_elementDeclHandler; - oldAttlistDeclHandler = parser->m_attlistDeclHandler; - oldEntityDeclHandler = parser->m_entityDeclHandler; -@@ -1847,6 +1849,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, - parser->m_externalEntityRefHandler = oldExternalEntityRefHandler; - parser->m_skippedEntityHandler = oldSkippedEntityHandler; - parser->m_unknownEncodingHandler = oldUnknownEncodingHandler; -+ parser->m_unknownEncodingHandlerData = oldUnknownEncodingHandlerData; - parser->m_elementDeclHandler = oldElementDeclHandler; - parser->m_attlistDeclHandler = oldAttlistDeclHandler; - parser->m_entityDeclHandler = oldEntityDeclHandler; --- -2.45.4 - - -From 0b2599c6eff2f0f9d20ec7423621f2928f989c1a Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Sun, 18 Jan 2026 17:26:31 +0100 -Subject: [PATCH 2/3] tests: Cover effect of XML_SetUnknownEncodingHandler user - data - ---- - tests/basic_tests.c | 42 ++++++++++++++++++++++++++++++++++++++++++ - tests/handlers.c | 10 ++++++++++ - tests/handlers.h | 3 +++ - 3 files changed, 55 insertions(+) - -diff --git a/tests/basic_tests.c b/tests/basic_tests.c -index da5c0d4..2db2a76 100644 ---- a/tests/basic_tests.c -+++ b/tests/basic_tests.c -@@ -4440,6 +4440,46 @@ START_TEST(test_unknown_encoding_invalid_attr_value) { - } - END_TEST - -+START_TEST(test_unknown_encoding_user_data_primary) { -+ // This test is based on ideas contributed by Artiphishell Inc. -+ const char *const text = "\n" -+ " \n"; -+ XML_Parser parser = XML_ParserCreate(NULL); -+ XML_SetUnknownEncodingHandler(parser, -+ user_data_checking_unknown_encoding_handler, -+ (void *)(intptr_t)0xC0FFEE); -+ -+ assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) -+ == XML_STATUS_OK); -+ -+ XML_ParserFree(parser); -+} -+END_TEST -+ -+START_TEST(test_unknown_encoding_user_data_secondary) { -+ // This test is based on ideas contributed by Artiphishell Inc. -+ const char *const text_main = "\n" -+ "]>\n" -+ " &ext; \n"; -+ const char *const text_external = "\n" -+ "data "; -+ ExtTest2 test_data = {text_external, (int)strlen(text_external), NULL, NULL}; -+ XML_Parser parser = XML_ParserCreate(NULL); -+ XML_SetExternalEntityRefHandler(parser, external_entity_loader2); -+ XML_SetUnknownEncodingHandler(parser, -+ user_data_checking_unknown_encoding_handler, -+ (void *)(intptr_t)0xC0FFEE); -+ XML_SetUserData(parser, &test_data); -+ -+ assert_true(_XML_Parse_SINGLE_BYTES(parser, text_main, (int)strlen(text_main), -+ XML_TRUE) -+ == XML_STATUS_OK); -+ -+ XML_ParserFree(parser); -+} -+END_TEST -+ - /* Test an external entity parser set to use latin-1 detects UTF-16 - * BOMs correctly. - */ -@@ -6284,6 +6324,8 @@ make_basic_test_case(Suite *s) { - tcase_add_test(tc_basic, test_unknown_encoding_invalid_surrogate); - tcase_add_test(tc_basic, test_unknown_encoding_invalid_high); - tcase_add_test(tc_basic, test_unknown_encoding_invalid_attr_value); -+ tcase_add_test(tc_basic, test_unknown_encoding_user_data_primary); -+ tcase_add_test(tc_basic, test_unknown_encoding_user_data_secondary); - tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16le_bom); - tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16be_bom); - tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16le_bom2); -diff --git a/tests/handlers.c b/tests/handlers.c -index bdb5b0e..5078014 100644 ---- a/tests/handlers.c -+++ b/tests/handlers.c -@@ -45,6 +45,7 @@ - # undef NDEBUG /* because test suite relies on assert(...) at the moment */ - #endif - -+#include- #include - #include - #include -@@ -407,6 +408,15 @@ long_encoding_handler(void *userData, const XML_Char *encoding, - return XML_STATUS_OK; - } - -+int XMLCALL -+user_data_checking_unknown_encoding_handler(void *userData, -+ const XML_Char *encoding, -+ XML_Encoding *info) { -+ const intptr_t number = (intptr_t)userData; -+ assert_true(number == 0xC0FFEE); -+ return long_encoding_handler(userData, encoding, info); -+} -+ - /* External Entity Handlers */ - - int XMLCALL -diff --git a/tests/handlers.h b/tests/handlers.h -index 4d6a08d..ac4ca94 100644 ---- a/tests/handlers.h -+++ b/tests/handlers.h -@@ -159,6 +159,9 @@ extern int XMLCALL long_encoding_handler(void *userData, - const XML_Char *encoding, - XML_Encoding *info); - -+extern int XMLCALL user_data_checking_unknown_encoding_handler( -+ void *userData, const XML_Char *encoding, XML_Encoding *info); -+ - /* External Entity Handlers */ - - typedef struct ExtOption { --- -2.45.4 - - -From dea97bc0c894b5494f2e4d46d6076d49dc227e8f Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Sun, 18 Jan 2026 18:19:25 +0100 -Subject: [PATCH 3/3] Changes: Document CVE-2026-24515 - --- -2.45.4 - diff --git a/SPECS/expat/CVE-2026-25210.patch b/SPECS/expat/CVE-2026-25210.patch deleted file mode 100644 index 204ac03cca5..00000000000 --- a/SPECS/expat/CVE-2026-25210.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 5ffd029337a8db6b3bef77ecd0a040b3e1e573f2 Mon Sep 17 00:00:00 2001 -From: Matthew Fernandez -Date: Thu, 2 Oct 2025 17:15:15 -0700 -Subject: [PATCH 1/3] lib: Make a doubling more readable - -Suggested-by: Sebastian Pipping ---- - lib/xmlparse.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index d804753..a48acd2 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -3492,7 +3492,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, - tag->name.strLen = convLen; - break; - } -- bufSize = (int)(tag->bufEnd - tag->buf) << 1; -+ bufSize = (int)(tag->bufEnd - tag->buf) * 2; - { - char *temp = (char *)REALLOC(parser, tag->buf, bufSize); - if (temp == NULL) --- -2.45.4 - - -From 07d55b4f18ded4740946a9a436e787b3c178176c Mon Sep 17 00:00:00 2001 -From: Matthew Fernandez -Date: Thu, 2 Oct 2025 17:15:15 -0700 -Subject: [PATCH 2/3] lib: Realign a size with the `REALLOC` type signature it - is passed into - -Note that this implicitly assumes `tag->bufEnd >= tag->buf`, which should -already be guaranteed true. ---- - lib/xmlparse.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index a48acd2..ed505b7 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -3481,7 +3481,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, - const char *fromPtr = tag->rawName; - toPtr = (XML_Char *)tag->buf; - for (;;) { -- int bufSize; - int convLen; - const enum XML_Convert_Result convert_res - = XmlConvert(enc, &fromPtr, rawNameEnd, (ICHAR **)&toPtr, -@@ -3492,7 +3491,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, - tag->name.strLen = convLen; - break; - } -- bufSize = (int)(tag->bufEnd - tag->buf) * 2; -+ const size_t bufSize = (size_t)(tag->bufEnd - tag->buf) * 2; - { - char *temp = (char *)REALLOC(parser, tag->buf, bufSize); - if (temp == NULL) --- -2.45.4 - - -From 3776e1554b8b9506387ec8a0591560898fb1ef87 Mon Sep 17 00:00:00 2001 -From: Matthew Fernandez -Date: Thu, 2 Oct 2025 17:15:15 -0700 -Subject: [PATCH 3/3] lib: Introduce an integer overflow check for tag buffer - reallocation - -Suggested-by: Sebastian Pipping -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: https://github.com/libexpat/libexpat/pull/1075.patch ---- - lib/xmlparse.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index ed505b7..0bf913c 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -3491,6 +3491,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, - tag->name.strLen = convLen; - break; - } -+ if (SIZE_MAX / 2 < (size_t)(tag->bufEnd - tag->buf)) -+ return XML_ERROR_NO_MEMORY; - const size_t bufSize = (size_t)(tag->bufEnd - tag->buf) * 2; - { - char *temp = (char *)REALLOC(parser, tag->buf, bufSize); --- -2.45.4 - diff --git a/SPECS/expat/CVE-2026-32776.patch b/SPECS/expat/CVE-2026-32776.patch deleted file mode 100644 index e3e370e4d65..00000000000 --- a/SPECS/expat/CVE-2026-32776.patch +++ /dev/null @@ -1,88 +0,0 @@ -From bfc23e1f8e08527a455ec4fdd47f410058ff2a7d Mon Sep 17 00:00:00 2001 -From: Francesco Bertolaccini -Date: Tue, 3 Mar 2026 16:41:43 +0100 -Subject: [PATCH] Fix NULL function-pointer dereference for empty external - parameter entities - -When an external parameter entity with empty text is referenced inside -an entity declaration value, the sub-parser created to handle it receives -0 bytes of input. Processing enters entityValueInitProcessor which calls -storeEntityValue() with the parser's encoding; since no bytes were ever -processed, encoding detection has not yet occurred and the encoding is -still the initial probing encoding set up by XmlInitEncoding(). That -encoding only populates scanners[] (for prolog and content), not -literalScanners[]. XmlEntityValueTok() calls through -literalScanners[XML_ENTITY_VALUE_LITERAL] which is NULL, causing a -SEGV. - -Skip the tokenization loop entirely when entityTextPtr >= entityTextEnd, -and initialize the `next` pointer before the early exit so that callers -(callStoreEntityValue) receive a valid value through nextPtr. - -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: https://github.com/libexpat/libexpat/pull/1158.patch ---- - lib/xmlparse.c | 9 ++++++++- - tests/basic_tests.c | 19 +++++++++++++++++++ - 2 files changed, 27 insertions(+), 1 deletion(-) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index 0bf913c..d126f5b 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -6765,7 +6765,14 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc, - return XML_ERROR_NO_MEMORY; - } - -- const char *next; -+ const char *next = entityTextPtr; -+ -+ /* Nothing to tokenize. */ -+ if (entityTextPtr >= entityTextEnd) { -+ result = XML_ERROR_NONE; -+ goto endEntityValue; -+ } -+ - for (;;) { - next - = entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */ -diff --git a/tests/basic_tests.c b/tests/basic_tests.c -index 2db2a76..cfb09f3 100644 ---- a/tests/basic_tests.c -+++ b/tests/basic_tests.c -@@ -6123,6 +6123,24 @@ START_TEST(test_varying_buffer_fills) { - } - END_TEST - -+START_TEST(test_empty_ext_param_entity_in_value) { -+ const char *text = " "; -+ ExtOption options[] = { -+ {XCS("ext.dtd"), "" -+ ""}, -+ {XCS("empty"), ""}, -+ {NULL, NULL}, -+ }; -+ -+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); -+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner); -+ XML_SetUserData(g_parser, options); -+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) -+ == XML_STATUS_ERROR) -+ xml_failure(g_parser); -+} -+END_TEST -+ - void - make_basic_test_case(Suite *s) { - TCase *tc_basic = tcase_create("basic tests"); -@@ -6368,6 +6386,7 @@ make_basic_test_case(Suite *s) { - tcase_add_test(tc_basic, test_empty_element_abort); - tcase_add_test__ifdef_xml_dtd(tc_basic, - test_pool_integrity_with_unfinished_attr); -+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_ext_param_entity_in_value); - tcase_add_test__if_xml_ge(tc_basic, test_entity_ref_no_elements); - tcase_add_test__if_xml_ge(tc_basic, test_deep_nested_entity); - tcase_add_test__if_xml_ge(tc_basic, test_deep_nested_attribute_entity); --- -2.45.4 - diff --git a/SPECS/expat/CVE-2026-32777.patch b/SPECS/expat/CVE-2026-32777.patch deleted file mode 100644 index 437d8cdc101..00000000000 --- a/SPECS/expat/CVE-2026-32777.patch +++ /dev/null @@ -1,92 +0,0 @@ -From f86ec6b7d5a7280caeb68d5432fd45ee8f41f274 Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Sun, 1 Mar 2026 20:16:13 +0100 -Subject: [PATCH 1/2] lib: Reject XML_TOK_INSTANCE_START infinite loop in - entityValueProcessor - -.. that OSS-Fuzz/ClusterFuzz uncovered - -Upstream-reference: https://github.com/libexpat/libexpat/pull/1162.patch ---- - lib/xmlparse.c | 11 ++++++++++- - tests/misc_tests.c | 30 ++++++++++++++++++++++ - 2 file changed, 40 insertions(+), 1 deletion(-) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index d126f5b..88361a7 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -5068,7 +5068,7 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end, - } - /* 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 -- ""; -+ -+ struct ExtOption options[] = { -+ {XCS("secondary.txt"), -+ ""}, -+ {XCS("tertiary.txt"), " -Date: Sun, 8 Mar 2026 17:28:06 -0700 -Subject: [PATCH 1/2] copy prefix name to pool before lookup - -.. so that we cannot end up with a zombie PREFIX in the pool -that has NULL for a name. - -Co-authored-by: Sebastian Pipping ---- - lib/xmlparse.c | 43 +++++++++++++++++++++++++++++++++++-------- - 1 file changed, 35 insertions(+), 8 deletions(-) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index 88361a7..69027f6 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -590,6 +590,8 @@ static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, - static XML_Bool FASTCALL poolGrow(STRING_POOL *pool); - static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool, - const XML_Char *s); -+static const XML_Char *FASTCALL poolCopyStringNoFinish(STRING_POOL *pool, -+ const XML_Char *s); - static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, - int n); - static const XML_Char *FASTCALL poolAppendString(STRING_POOL *pool, -@@ -7431,16 +7433,24 @@ setContext(XML_Parser parser, const XML_Char *context) { - else { - if (! poolAppendChar(&parser->m_tempPool, XML_T('\0'))) - return XML_FALSE; -- prefix -- = (PREFIX *)lookup(parser, &dtd->prefixes, -- poolStart(&parser->m_tempPool), sizeof(PREFIX)); -- if (! prefix) -+ const XML_Char *const prefixName = poolCopyStringNoFinish( -+ &dtd->pool, poolStart(&parser->m_tempPool)); -+ if (! prefixName) { - return XML_FALSE; -- if (prefix->name == poolStart(&parser->m_tempPool)) { -- prefix->name = poolCopyString(&dtd->pool, prefix->name); -- if (! prefix->name) -- return XML_FALSE; - } -+ -+ prefix = (PREFIX *)lookup(parser, &dtd->prefixes, prefixName, -+ sizeof(PREFIX)); -+ -+ const bool prefixNameUsed = prefix && prefix->name == prefixName; -+ if (prefixNameUsed) -+ poolFinish(&dtd->pool); -+ else -+ poolDiscard(&dtd->pool); -+ -+ if (! prefix) -+ return XML_FALSE; -+ - poolDiscard(&parser->m_tempPool); - } - for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0'); -@@ -8029,6 +8039,23 @@ poolCopyString(STRING_POOL *pool, const XML_Char *s) { - return s; - } - -+// A version of `poolCopyString` that does not call `poolFinish` -+// and reverts any partial advancement upon failure. -+static const XML_Char *FASTCALL -+poolCopyStringNoFinish(STRING_POOL *pool, const XML_Char *s) { -+ const XML_Char *const original = s; -+ do { -+ if (! poolAppendChar(pool, *s)) { -+ // Revert any previously successful advancement -+ const ptrdiff_t advancedBy = s - original; -+ if (advancedBy > 0) -+ pool->ptr -= advancedBy; -+ return NULL; -+ } -+ } while (*s++); -+ return pool->start; -+} -+ - static const XML_Char * - poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) { - if (! pool->ptr && ! poolGrow(pool)) { --- -2.45.4 - - -From 777bd1a1b2196ac14cbc5efb71a3078583c8dfb2 Mon Sep 17 00:00:00 2001 -From: laserbear <10689391+Laserbear@users.noreply.github.com> -Date: Sun, 8 Mar 2026 17:28:06 -0700 -Subject: [PATCH 2/2] test that we do not end up with a zombie PREFIX in the - pool - -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: https://github.com/libexpat/libexpat/pull/1163.patch ---- - tests/nsalloc_tests.c | 27 +++++++++++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/tests/nsalloc_tests.c b/tests/nsalloc_tests.c -index a8f5718..d284a58 100644 ---- a/tests/nsalloc_tests.c -+++ b/tests/nsalloc_tests.c -@@ -1505,6 +1505,32 @@ START_TEST(test_nsalloc_prefixed_element) { - } - END_TEST - -+/* Verify that retry after OOM in setContext() does not crash. -+ */ -+START_TEST(test_nsalloc_setContext_zombie) { -+ const char *text = " Hello "; -+ unsigned int i; -+ const unsigned int max_alloc_count = 30; -+ -+ for (i = 0; i < max_alloc_count; i++) { -+ g_allocation_count = (int)i; -+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) -+ != XML_STATUS_ERROR) -+ break; -+ /* Retry on the same parser — must not crash */ -+ g_allocation_count = ALLOC_ALWAYS_SUCCEED; -+ XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE); -+ -+ nsalloc_teardown(); -+ nsalloc_setup(); -+ } -+ if (i == 0) -+ fail("Parsing worked despite failing allocations"); -+ else if (i == max_alloc_count) -+ fail("Parsing failed even at maximum allocation count"); -+} -+END_TEST -+ - void - make_nsalloc_test_case(Suite *s) { - TCase *tc_nsalloc = tcase_create("namespace allocation tests"); -@@ -1539,4 +1565,5 @@ make_nsalloc_test_case(Suite *s) { - tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_long_default_in_ext); - tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext); - tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element); -+ tcase_add_test(tc_nsalloc, test_nsalloc_setContext_zombie); - } --- -2.45.4 - diff --git a/SPECS/expat/Stop-updating-event-pointer-on-exit-for-reentry.patch b/SPECS/expat/Stop-updating-event-pointer-on-exit-for-reentry.patch deleted file mode 100644 index 6df6758fbcc..00000000000 --- a/SPECS/expat/Stop-updating-event-pointer-on-exit-for-reentry.patch +++ /dev/null @@ -1,256 +0,0 @@ -From 89a9c6807c982b4fa8aa806dd72771d6642dd8a1 Mon Sep 17 00:00:00 2001 -From: Berkay Eren Ürünm_parsingStatus.parsing) { - case XML_SUSPENDED: -+ *eventPP = next; - *nextPtr = next; - return XML_ERROR_NONE; - case XML_FINISHED: -+ *eventPP = next; - return XML_ERROR_ABORTED; - case XML_PARSING: - if (parser->m_reenter) { -@@ -3768,6 +3769,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, - } - /* Fall through */ - default:; -+ *eventPP = s = next; - } - } - /* not reached */ -@@ -4684,12 +4686,13 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, - /* LCOV_EXCL_STOP */ - } - -- *eventPP = s = next; - switch (parser->m_parsingStatus.parsing) { - case XML_SUSPENDED: -+ *eventPP = next; - *nextPtr = next; - return XML_ERROR_NONE; - case XML_FINISHED: -+ *eventPP = next; - return XML_ERROR_ABORTED; - case XML_PARSING: - if (parser->m_reenter) { -@@ -4697,6 +4700,7 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, - } - /* Fall through */ - default:; -+ *eventPP = s = next; - } - } - /* not reached */ -@@ -6307,12 +6311,13 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end, - default: - return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; - } -- parser->m_eventPtr = s = next; - switch (parser->m_parsingStatus.parsing) { - case XML_SUSPENDED: -+ parser->m_eventPtr = next; - *nextPtr = next; - return XML_ERROR_NONE; - case XML_FINISHED: -+ parser->m_eventPtr = next; - return XML_ERROR_ABORTED; - case XML_PARSING: - if (parser->m_reenter) { -@@ -6320,6 +6325,7 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end, - } - /* Fall through */ - default:; -+ parser->m_eventPtr = s = next; - } - } - } -diff --git a/tests/common.c b/tests/common.c -index 3aea8d7..b267dbb 100644 ---- a/tests/common.c -+++ b/tests/common.c -@@ -42,6 +42,8 @@ - */ - - #include -+#include -+#include // for SIZE_MAX - #include - #include - -@@ -294,3 +296,26 @@ duff_reallocator(void *ptr, size_t size) { - g_reallocation_count--; - return realloc(ptr, size); - } -+ -+// Portable remake of strndup(3) for C99; does not care about space efficiency -+char * -+portable_strndup(const char *s, size_t n) { -+ if ((s == NULL) || (n == SIZE_MAX)) { -+ errno = EINVAL; -+ return NULL; -+ } -+ -+ char *const buffer = (char *)malloc(n + 1); -+ if (buffer == NULL) { -+ errno = ENOMEM; -+ return NULL; -+ } -+ -+ errno = 0; -+ -+ memcpy(buffer, s, n); -+ -+ buffer[n] = '\0'; -+ -+ return buffer; -+} -diff --git a/tests/common.h b/tests/common.h -index bc4c7da..8871130 100644 ---- a/tests/common.h -+++ b/tests/common.h -@@ -146,6 +146,8 @@ extern void *duff_allocator(size_t size); - - extern void *duff_reallocator(void *ptr, size_t size); - -+extern char *portable_strndup(const char *s, size_t n); -+ - #endif /* XML_COMMON_H */ - - #ifdef __cplusplus -diff --git a/tests/misc_tests.c b/tests/misc_tests.c -index f9a78f6..2b9f793 100644 ---- a/tests/misc_tests.c -+++ b/tests/misc_tests.c -@@ -561,6 +561,66 @@ START_TEST(test_renter_loop_finite_content) { - } - END_TEST - -+// Inspired by function XML_OriginalString of Perl's XML::Parser -+static char * -+dup_original_string(XML_Parser parser) { -+ const int byte_count = XML_GetCurrentByteCount(parser); -+ -+ assert_true(byte_count >= 0); -+ -+ int offset = -1; -+ int size = -1; -+ -+ const char *const context = XML_GetInputContext(parser, &offset, &size); -+ -+#if XML_CONTEXT_BYTES > 0 -+ assert_true(context != NULL); -+ assert_true(offset >= 0); -+ assert_true(size >= 0); -+ return portable_strndup(context + offset, byte_count); -+#else -+ assert_true(context == NULL); -+ return NULL; -+#endif -+} -+ -+static void -+on_characters_issue_980(void *userData, const XML_Char *s, int len) { -+ (void)s; -+ (void)len; -+ XML_Parser parser = (XML_Parser)userData; -+ -+ char *const original_string = dup_original_string(parser); -+ -+#if XML_CONTEXT_BYTES > 0 -+ assert_true(original_string != NULL); -+ assert_true(strcmp(original_string, "&draft.day;") == 0); -+ free(original_string); -+#else -+ assert_true(original_string == NULL); -+#endif -+} -+ -+START_TEST(test_misc_expected_event_ptr_issue_980) { -+ // NOTE: This is a tiny subset of sample "REC-xml-19980210.xml" -+ // from Perl's XML::Parser -+ const char *const doc = "\n" -+ "]>\n" -+ " &draft.day; \n"; -+ -+ XML_Parser parser = XML_ParserCreate(NULL); -+ XML_SetUserData(parser, parser); -+ XML_SetCharacterDataHandler(parser, on_characters_issue_980); -+ -+ assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), -+ /*isFinal=*/XML_TRUE) -+ == XML_STATUS_OK); -+ -+ XML_ParserFree(parser); -+} -+END_TEST -+ - void - make_miscellaneous_test_case(Suite *s) { - TCase *tc_misc = tcase_create("miscellaneous tests"); -@@ -588,4 +648,5 @@ make_miscellaneous_test_case(Suite *s) { - tcase_add_test(tc_misc, test_misc_resumeparser_not_crashing); - tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser); - tcase_add_test__if_xml_ge(tc_misc, test_renter_loop_finite_content); -+ tcase_add_test(tc_misc, test_misc_expected_event_ptr_issue_980); - } --- -2.45.4 - diff --git a/SPECS/expat/expat.signatures.json b/SPECS/expat/expat.signatures.json index faaee12cd64..1d591f132d4 100644 --- a/SPECS/expat/expat.signatures.json +++ b/SPECS/expat/expat.signatures.json @@ -1,5 +1,5 @@ { "Signatures": { - "expat-2.6.4.tar.bz2": "8dc480b796163d4436e6f1352e71800a774f73dbae213f1860b60607d2a83ada" + "expat-2.8.1.tar.bz2": "f5833dd2e1cd7739ec9182804a1a29c4f0cc7c2f26b633d3a2188b7766a88ecb" } } \ No newline at end of file diff --git a/SPECS/expat/expat.spec b/SPECS/expat/expat.spec index 59f199cb0e4..bc89f710efe 100644 --- a/SPECS/expat/expat.spec +++ b/SPECS/expat/expat.spec @@ -1,22 +1,14 @@ %define underscore_version %(echo %{version} | cut -d. -f1-3 --output-delimiter="_") Summary: An XML parser library Name: expat -Version: 2.6.4 -Release: 6%{?dist} +Version: 2.8.1 +Release: 1%{?dist} License: MIT Vendor: Microsoft Corporation Distribution: Azure Linux Group: System Environment/GeneralLibraries URL: https://libexpat.github.io/ Source0: https://github.com/libexpat/libexpat/releases/download/R_%{underscore_version}/%{name}-%{version}.tar.bz2 -Patch0: CVE-2024-8176.patch -Patch1: CVE-2025-59375.patch -Patch2: CVE-2026-24515.patch -Patch3: CVE-2026-25210.patch -Patch4: Stop-updating-event-pointer-on-exit-for-reentry.patch -Patch5: CVE-2026-32776.patch -Patch6: CVE-2026-32777.patch -Patch7: CVE-2026-32778.patch Requires: %{name}-libs = %{version}-%{release} %description @@ -74,6 +66,9 @@ rm -rf %{buildroot}/%{_docdir}/%{name} %{_libdir}/libexpat.so.1* %changelog +* Mon Jun 22 2026 BinduSri Adabala- 2.8.1-1 +- Upgrade to 2.8.1 to fix CVE-2026-7210 + * Wed Apr 15 2026 Azure Linux Security Servicing Account - 2.6.4-6 - Patch for CVE-2026-32778, CVE-2026-32777, CVE-2026-32776 diff --git a/cgmanifest.json b/cgmanifest.json index 4612bf55249..88d58fcb8f1 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -3518,8 +3518,8 @@ "type": "other", "other": { "name": "expat", - "version": "2.6.4", - "downloadUrl": "https://github.com/libexpat/libexpat/releases/download/R_2_6_4/expat-2.6.4.tar.bz2" + "version": "2.8.1", + "downloadUrl": "https://github.com/libexpat/libexpat/releases/download/R_2_8_1/expat-2.8.1.tar.bz2" } } }, diff --git a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt index 460e60c208f..0ee77d1bc0f 100644 --- a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt @@ -99,9 +99,9 @@ elfutils-libelf-0.189-6.azl3.aarch64.rpm elfutils-libelf-devel-0.189-6.azl3.aarch64.rpm elfutils-libelf-devel-static-0.189-6.azl3.aarch64.rpm elfutils-libelf-lang-0.189-6.azl3.aarch64.rpm -expat-2.6.4-6.azl3.aarch64.rpm -expat-devel-2.6.4-6.azl3.aarch64.rpm -expat-libs-2.6.4-6.azl3.aarch64.rpm +expat-2.8.1-1.azl3.aarch64.rpm +expat-devel-2.8.1-1.azl3.aarch64.rpm +expat-libs-2.8.1-1.azl3.aarch64.rpm libpipeline-1.5.7-1.azl3.aarch64.rpm libpipeline-devel-1.5.7-1.azl3.aarch64.rpm gdbm-1.23-1.azl3.aarch64.rpm diff --git a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt index 0d7b3bdb00d..092ec66b739 100644 --- a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt @@ -99,9 +99,9 @@ elfutils-libelf-0.189-6.azl3.x86_64.rpm elfutils-libelf-devel-0.189-6.azl3.x86_64.rpm elfutils-libelf-devel-static-0.189-6.azl3.x86_64.rpm elfutils-libelf-lang-0.189-6.azl3.x86_64.rpm -expat-2.6.4-6.azl3.x86_64.rpm -expat-devel-2.6.4-6.azl3.x86_64.rpm -expat-libs-2.6.4-6.azl3.x86_64.rpm +expat-2.8.1-1.azl3.x86_64.rpm +expat-devel-2.8.1-1.azl3.x86_64.rpm +expat-libs-2.8.1-1.azl3.x86_64.rpm libpipeline-1.5.7-1.azl3.x86_64.rpm libpipeline-devel-1.5.7-1.azl3.x86_64.rpm gdbm-1.23-1.azl3.x86_64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_aarch64.txt b/toolkit/resources/manifests/package/toolchain_aarch64.txt index 7ab6383f9fc..c98f2ab337a 100644 --- a/toolkit/resources/manifests/package/toolchain_aarch64.txt +++ b/toolkit/resources/manifests/package/toolchain_aarch64.txt @@ -94,10 +94,10 @@ elfutils-libelf-0.189-6.azl3.aarch64.rpm elfutils-libelf-devel-0.189-6.azl3.aarch64.rpm elfutils-libelf-devel-static-0.189-6.azl3.aarch64.rpm elfutils-libelf-lang-0.189-6.azl3.aarch64.rpm -expat-2.6.4-6.azl3.aarch64.rpm -expat-debuginfo-2.6.4-6.azl3.aarch64.rpm -expat-devel-2.6.4-6.azl3.aarch64.rpm -expat-libs-2.6.4-6.azl3.aarch64.rpm +expat-2.8.1-1.azl3.aarch64.rpm +expat-debuginfo-2.8.1-1.azl3.aarch64.rpm +expat-devel-2.8.1-1.azl3.aarch64.rpm +expat-libs-2.8.1-1.azl3.aarch64.rpm file-5.45-1.azl3.aarch64.rpm file-debuginfo-5.45-1.azl3.aarch64.rpm file-devel-5.45-1.azl3.aarch64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_x86_64.txt b/toolkit/resources/manifests/package/toolchain_x86_64.txt index e0886b97054..52d6321c700 100644 --- a/toolkit/resources/manifests/package/toolchain_x86_64.txt +++ b/toolkit/resources/manifests/package/toolchain_x86_64.txt @@ -99,10 +99,10 @@ elfutils-libelf-0.189-6.azl3.x86_64.rpm elfutils-libelf-devel-0.189-6.azl3.x86_64.rpm elfutils-libelf-devel-static-0.189-6.azl3.x86_64.rpm elfutils-libelf-lang-0.189-6.azl3.x86_64.rpm -expat-2.6.4-6.azl3.x86_64.rpm -expat-debuginfo-2.6.4-6.azl3.x86_64.rpm -expat-devel-2.6.4-6.azl3.x86_64.rpm -expat-libs-2.6.4-6.azl3.x86_64.rpm +expat-2.8.1-1.azl3.x86_64.rpm +expat-debuginfo-2.8.1-1.azl3.x86_64.rpm +expat-devel-2.8.1-1.azl3.x86_64.rpm +expat-libs-2.8.1-1.azl3.x86_64.rpm file-5.45-1.azl3.x86_64.rpm file-debuginfo-5.45-1.azl3.x86_64.rpm file-devel-5.45-1.azl3.x86_64.rpm