From 4b43b8dacc96fd538254e17a69abc9745c3a2ed4 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Fri, 19 Sep 2025 23:32:46 +0200 Subject: [PATCH] lib: Fix alignment of internal allocations for some non-amd64 architectures sparc32 is known to be affected. CVE: CVE-2025-59375 Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/4b43b8dacc96fd538254e17a69abc9745c3a2ed4] Signed-off-by: Peter Marko --- lib/internal.h | 6 ++++++ lib/xmlparse.c | 38 ++++++++++++++++++++++---------------- tests/alloc_tests.c | 13 ++++++++++--- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/lib/internal.h b/lib/internal.h index 6e087858..8f5edf48 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -108,6 +108,7 @@ #endif #include // ULONG_MAX +#include // size_t #if defined(_WIN32) \ && (! defined(__USE_MINGW_ANSI_STDIO) \ @@ -150,6 +151,11 @@ #define EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT \ 67108864 // 64 MiB, 2^26 +// NOTE: If function expat_alloc was user facing, EXPAT_MALLOC_ALIGNMENT would +// have to take sizeof(long double) into account +#define EXPAT_MALLOC_ALIGNMENT sizeof(long long) // largest parser (sub)member +#define EXPAT_MALLOC_PADDING ((EXPAT_MALLOC_ALIGNMENT) - sizeof(size_t)) + /* NOTE END */ #include "expat.h" // so we can use type XML_Parser below diff --git a/lib/xmlparse.c b/lib/xmlparse.c index 24fd7b97..ce29ab6f 100644 --- a/lib/xmlparse.c +++ b/lib/xmlparse.c @@ -850,14 +850,14 @@ static void * # endif expat_malloc(XML_Parser parser, size_t size, int sourceLine) { // Detect integer overflow - if (SIZE_MAX - size < sizeof(size_t)) { + if (SIZE_MAX - size < sizeof(size_t) + EXPAT_MALLOC_PADDING) { return NULL; } const XML_Parser rootParser = getRootParserOf(parser, NULL); assert(rootParser->m_parentParser == NULL); - const size_t bytesToAllocate = sizeof(size_t) + size; + const size_t bytesToAllocate = sizeof(size_t) + EXPAT_MALLOC_PADDING + size; if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated < bytesToAllocate) { @@ -894,7 +894,7 @@ expat_malloc(XML_Parser parser, size_t size, int sourceLine) { rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); } - return (char *)mallocedPtr + sizeof(size_t); + return (char *)mallocedPtr + sizeof(size_t) + EXPAT_MALLOC_PADDING; } # if defined(XML_TESTING) @@ -914,8 +914,9 @@ expat_free(XML_Parser parser, void *ptr, int sourceLine) { // 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; + void *const mallocedPtr = (char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t); + const size_t bytesAllocated + = sizeof(size_t) + EXPAT_MALLOC_PADDING + *(size_t *)mallocedPtr; // Update accounting assert(rootParser->m_alloc_tracker.bytesAllocated >= bytesAllocated); @@ -954,7 +955,7 @@ expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { // Extract original size (to the eyes of the caller) and the original // pointer returned by malloc/realloc - void *mallocedPtr = (char *)ptr - sizeof(size_t); + void *mallocedPtr = (char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t); const size_t prevSize = *(size_t *)mallocedPtr; // Classify upcoming change @@ -971,10 +972,11 @@ expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { // NOTE: Integer overflow detection has already been done for us // by expat_heap_increase_tolerable(..) above - assert(SIZE_MAX - sizeof(size_t) >= size); + assert(SIZE_MAX - sizeof(size_t) - EXPAT_MALLOC_PADDING >= size); // Actually allocate - mallocedPtr = parser->m_mem.realloc_fcn(mallocedPtr, sizeof(size_t) + size); + mallocedPtr = parser->m_mem.realloc_fcn( + mallocedPtr, sizeof(size_t) + EXPAT_MALLOC_PADDING + size); if (mallocedPtr == NULL) { return NULL; @@ -1005,7 +1007,7 @@ expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { // Update in-block recorded size *(size_t *)mallocedPtr = size; - return (char *)mallocedPtr + sizeof(size_t); + return (char *)mallocedPtr + sizeof(size_t) + EXPAT_MALLOC_PADDING; } #endif // XML_GE == 1 @@ -1337,7 +1339,8 @@ parserCreate(const XML_Char *encodingName, XML_Parser parser = NULL; #if XML_GE == 1 - const size_t increase = sizeof(size_t) + sizeof(struct XML_ParserStruct); + const size_t increase + = sizeof(size_t) + EXPAT_MALLOC_PADDING + sizeof(struct XML_ParserStruct); if (parentParser != NULL) { const XML_Parser rootParser = getRootParserOf(parentParser, NULL); @@ -1352,11 +1355,13 @@ parserCreate(const XML_Char *encodingName, if (memsuite) { XML_Memory_Handling_Suite *mtemp; #if XML_GE == 1 - void *const sizeAndParser = memsuite->malloc_fcn( - sizeof(size_t) + sizeof(struct XML_ParserStruct)); + void *const sizeAndParser + = memsuite->malloc_fcn(sizeof(size_t) + EXPAT_MALLOC_PADDING + + sizeof(struct XML_ParserStruct)); if (sizeAndParser != NULL) { *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); - parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)); + parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t) + + EXPAT_MALLOC_PADDING); #else parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); if (parser != NULL) { @@ -1369,11 +1374,12 @@ parserCreate(const XML_Char *encodingName, } else { XML_Memory_Handling_Suite *mtemp; #if XML_GE == 1 - void *const sizeAndParser - = malloc(sizeof(size_t) + sizeof(struct XML_ParserStruct)); + void *const sizeAndParser = malloc(sizeof(size_t) + EXPAT_MALLOC_PADDING + + sizeof(struct XML_ParserStruct)); if (sizeAndParser != NULL) { *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); - parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)); + parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t) + + EXPAT_MALLOC_PADDING); #else parser = malloc(sizeof(struct XML_ParserStruct)); if (parser != NULL) { diff --git a/tests/alloc_tests.c b/tests/alloc_tests.c index 644a4952..dabdf0da 100644 --- a/tests/alloc_tests.c +++ b/tests/alloc_tests.c @@ -2091,6 +2091,13 @@ START_TEST(test_alloc_reset_after_external_entity_parser_create_fail) { } END_TEST +#if XML_GE == 1 +static size_t +sizeRecordedFor(void *ptr) { + return *(size_t *)((char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t)); +} +#endif // XML_GE == 1 + START_TEST(test_alloc_tracker_size_recorded) { XML_Memory_Handling_Suite memsuite = {malloc, realloc, free}; @@ -2106,16 +2113,16 @@ START_TEST(test_alloc_tracker_size_recorded) { void *ptr = expat_malloc(parser, 10, -1); assert_true(ptr != NULL); - assert_true(*((size_t *)ptr - 1) == 10); + assert_true(sizeRecordedFor(ptr) == 10); assert_true(expat_realloc(parser, ptr, SIZE_MAX / 2, -1) == NULL); - assert_true(*((size_t *)ptr - 1) == 10); // i.e. unchanged + assert_true(sizeRecordedFor(ptr) == 10); // i.e. unchanged ptr = expat_realloc(parser, ptr, 20, -1); assert_true(ptr != NULL); - assert_true(*((size_t *)ptr - 1) == 20); + assert_true(sizeRecordedFor(ptr) == 20); expat_free(parser, ptr, -1); #endif