diff options
26 files changed, 2858 insertions, 0 deletions
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-00.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-00.patch new file mode 100644 index 0000000000..e3cbd0f604 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-00.patch | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | From 87321ac84a0d6cb42ee64a591adc79c1ec37fb5b Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Tue, 2 Sep 2025 20:52:29 +0200 | ||
| 4 | Subject: [PATCH] xmlwf: Mention supported environment variables in --help | ||
| 5 | output | ||
| 6 | |||
| 7 | CVE: CVE-2025-59375 | ||
| 8 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/87321ac84a0d6cb42ee64a591adc79c1ec37fb5b] | ||
| 9 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 10 | --- | ||
| 11 | xmlwf/xmlwf.c | 8 ++++++++ | ||
| 12 | xmlwf/xmlwf_helpgen.py | 8 ++++++++ | ||
| 13 | 2 files changed, 16 insertions(+) | ||
| 14 | |||
| 15 | diff --git a/xmlwf/xmlwf.c b/xmlwf/xmlwf.c | ||
| 16 | index ec7e51c9..8cfc73ca 100644 | ||
| 17 | --- a/xmlwf/xmlwf.c | ||
| 18 | +++ b/xmlwf/xmlwf.c | ||
| 19 | @@ -926,6 +926,14 @@ usage(const XML_Char *prog, int rc) { | ||
| 20 | T(" -h, --help show this [h]elp message and exit\n") | ||
| 21 | T(" -v, --version show program's [v]ersion number and exit\n") | ||
| 22 | T("\n") | ||
| 23 | + T("environment variables:\n") | ||
| 24 | + T(" EXPAT_ACCOUNTING_DEBUG=(0|1|2|3)\n") | ||
| 25 | + T(" Control verbosity of accounting debugging (default: 0)\n") | ||
| 26 | + T(" EXPAT_ENTITY_DEBUG=(0|1)\n") | ||
| 27 | + T(" Control verbosity of entity debugging (default: 0)\n") | ||
| 28 | + T(" EXPAT_ENTROPY_DEBUG=(0|1)\n") | ||
| 29 | + T(" Control verbosity of entropy debugging (default: 0)\n") | ||
| 30 | + T("\n") | ||
| 31 | T("exit status:\n") | ||
| 32 | T(" 0 the input files are well-formed and the output (if requested) was written successfully\n") | ||
| 33 | T(" 1 could not allocate data structures, signals a serious problem with execution environment\n") | ||
| 34 | diff --git a/xmlwf/xmlwf_helpgen.py b/xmlwf/xmlwf_helpgen.py | ||
| 35 | index c3257f0e..39a3dc13 100755 | ||
| 36 | --- a/xmlwf/xmlwf_helpgen.py | ||
| 37 | +++ b/xmlwf/xmlwf_helpgen.py | ||
| 38 | @@ -32,6 +32,14 @@ | ||
| 39 | import argparse | ||
| 40 | |||
| 41 | epilog = """ | ||
| 42 | +environment variables: | ||
| 43 | + EXPAT_ACCOUNTING_DEBUG=(0|1|2|3) | ||
| 44 | + Control verbosity of accounting debugging (default: 0) | ||
| 45 | + EXPAT_ENTITY_DEBUG=(0|1) | ||
| 46 | + Control verbosity of entity debugging (default: 0) | ||
| 47 | + EXPAT_ENTROPY_DEBUG=(0|1) | ||
| 48 | + Control verbosity of entropy debugging (default: 0) | ||
| 49 | + | ||
| 50 | exit status: | ||
| 51 | 0 the input files are well-formed and the output (if requested) was written successfully | ||
| 52 | 1 could not allocate data structures, signals a serious problem with execution environment | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-01.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-01.patch new file mode 100644 index 0000000000..6708bbef45 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-01.patch | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | From 0872c189db6e457084fca335662a9cb49e8ec4c7 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Mon, 1 Sep 2025 18:06:59 +0200 | ||
| 4 | Subject: [PATCH] lib: Make function dtdCreate use macro MALLOC | ||
| 5 | |||
| 6 | .. and give its body access to the parser for upcoming changes | ||
| 7 | |||
| 8 | CVE: CVE-2025-59375 | ||
| 9 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/0872c189db6e457084fca335662a9cb49e8ec4c7] | ||
| 10 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 11 | --- | ||
| 12 | lib/xmlparse.c | 9 +++++---- | ||
| 13 | 1 file changed, 5 insertions(+), 4 deletions(-) | ||
| 14 | |||
| 15 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 16 | index 25f786ec..b9d6eed1 100644 | ||
| 17 | --- a/lib/xmlparse.c | ||
| 18 | +++ b/lib/xmlparse.c | ||
| 19 | @@ -555,7 +555,7 @@ static XML_Bool setContext(XML_Parser parser, const XML_Char *context); | ||
| 20 | |||
| 21 | static void FASTCALL normalizePublicId(XML_Char *s); | ||
| 22 | |||
| 23 | -static DTD *dtdCreate(const XML_Memory_Handling_Suite *ms); | ||
| 24 | +static DTD *dtdCreate(XML_Parser parser); | ||
| 25 | /* do not call if m_parentParser != NULL */ | ||
| 26 | static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms); | ||
| 27 | static void dtdDestroy(DTD *p, XML_Bool isDocEntity, | ||
| 28 | @@ -1166,7 +1166,7 @@ parserCreate(const XML_Char *encodingName, | ||
| 29 | if (dtd) | ||
| 30 | parser->m_dtd = dtd; | ||
| 31 | else { | ||
| 32 | - parser->m_dtd = dtdCreate(&parser->m_mem); | ||
| 33 | + parser->m_dtd = dtdCreate(parser); | ||
| 34 | if (parser->m_dtd == NULL) { | ||
| 35 | FREE(parser, parser->m_dataBuf); | ||
| 36 | FREE(parser, parser->m_atts); | ||
| 37 | @@ -7126,8 +7126,9 @@ normalizePublicId(XML_Char *publicId) { | ||
| 38 | } | ||
| 39 | |||
| 40 | static DTD * | ||
| 41 | -dtdCreate(const XML_Memory_Handling_Suite *ms) { | ||
| 42 | - DTD *p = ms->malloc_fcn(sizeof(DTD)); | ||
| 43 | +dtdCreate(XML_Parser parser) { | ||
| 44 | + const XML_Memory_Handling_Suite *const ms = &parser->m_mem; | ||
| 45 | + DTD *p = MALLOC(parser, sizeof(DTD)); | ||
| 46 | if (p == NULL) | ||
| 47 | return p; | ||
| 48 | poolInit(&(p->pool), ms); | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-02.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-02.patch new file mode 100644 index 0000000000..b0543370ad --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-02.patch | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | From 8768dadae479d9f2e984b747fb2ba79bb78de94f Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Mon, 1 Sep 2025 18:10:26 +0200 | ||
| 4 | Subject: [PATCH] lib: Make string pools use macros MALLOC, FREE, REALLOC | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/8768dadae479d9f2e984b747fb2ba79bb78de94f] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | lib/xmlparse.c | 27 +++++++++++++-------------- | ||
| 11 | 1 file changed, 13 insertions(+), 14 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 14 | index b9d6eed1..a56c71ea 100644 | ||
| 15 | --- a/lib/xmlparse.c | ||
| 16 | +++ b/lib/xmlparse.c | ||
| 17 | @@ -357,7 +357,7 @@ typedef struct { | ||
| 18 | const XML_Char *end; | ||
| 19 | XML_Char *ptr; | ||
| 20 | XML_Char *start; | ||
| 21 | - const XML_Memory_Handling_Suite *mem; | ||
| 22 | + XML_Parser parser; | ||
| 23 | } STRING_POOL; | ||
| 24 | |||
| 25 | /* The XML_Char before the name is used to determine whether | ||
| 26 | @@ -574,8 +574,7 @@ static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *iter, | ||
| 27 | const HASH_TABLE *table); | ||
| 28 | static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *iter); | ||
| 29 | |||
| 30 | -static void FASTCALL poolInit(STRING_POOL *pool, | ||
| 31 | - const XML_Memory_Handling_Suite *ms); | ||
| 32 | +static void FASTCALL poolInit(STRING_POOL *pool, XML_Parser parser); | ||
| 33 | static void FASTCALL poolClear(STRING_POOL *pool); | ||
| 34 | static void FASTCALL poolDestroy(STRING_POOL *pool); | ||
| 35 | static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, | ||
| 36 | @@ -1200,8 +1199,8 @@ parserCreate(const XML_Char *encodingName, | ||
| 37 | |||
| 38 | parser->m_protocolEncodingName = NULL; | ||
| 39 | |||
| 40 | - poolInit(&parser->m_tempPool, &(parser->m_mem)); | ||
| 41 | - poolInit(&parser->m_temp2Pool, &(parser->m_mem)); | ||
| 42 | + poolInit(&parser->m_tempPool, parser); | ||
| 43 | + poolInit(&parser->m_temp2Pool, parser); | ||
| 44 | parserInit(parser, encodingName); | ||
| 45 | |||
| 46 | if (encodingName && ! parser->m_protocolEncodingName) { | ||
| 47 | @@ -7131,8 +7130,8 @@ dtdCreate(XML_Parser parser) { | ||
| 48 | DTD *p = MALLOC(parser, sizeof(DTD)); | ||
| 49 | if (p == NULL) | ||
| 50 | return p; | ||
| 51 | - poolInit(&(p->pool), ms); | ||
| 52 | - poolInit(&(p->entityValuePool), ms); | ||
| 53 | + poolInit(&(p->pool), parser); | ||
| 54 | + poolInit(&(p->entityValuePool), parser); | ||
| 55 | hashTableInit(&(p->generalEntities), ms); | ||
| 56 | hashTableInit(&(p->elementTypes), ms); | ||
| 57 | hashTableInit(&(p->attributeIds), ms); | ||
| 58 | @@ -7596,13 +7595,13 @@ hashTableIterNext(HASH_TABLE_ITER *iter) { | ||
| 59 | } | ||
| 60 | |||
| 61 | static void FASTCALL | ||
| 62 | -poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) { | ||
| 63 | +poolInit(STRING_POOL *pool, XML_Parser parser) { | ||
| 64 | pool->blocks = NULL; | ||
| 65 | pool->freeBlocks = NULL; | ||
| 66 | pool->start = NULL; | ||
| 67 | pool->ptr = NULL; | ||
| 68 | pool->end = NULL; | ||
| 69 | - pool->mem = ms; | ||
| 70 | + pool->parser = parser; | ||
| 71 | } | ||
| 72 | |||
| 73 | static void FASTCALL | ||
| 74 | @@ -7629,13 +7628,13 @@ poolDestroy(STRING_POOL *pool) { | ||
| 75 | BLOCK *p = pool->blocks; | ||
| 76 | while (p) { | ||
| 77 | BLOCK *tem = p->next; | ||
| 78 | - pool->mem->free_fcn(p); | ||
| 79 | + FREE(pool->parser, p); | ||
| 80 | p = tem; | ||
| 81 | } | ||
| 82 | p = pool->freeBlocks; | ||
| 83 | while (p) { | ||
| 84 | BLOCK *tem = p->next; | ||
| 85 | - pool->mem->free_fcn(p); | ||
| 86 | + FREE(pool->parser, p); | ||
| 87 | p = tem; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | @@ -7790,8 +7789,8 @@ poolGrow(STRING_POOL *pool) { | ||
| 91 | if (bytesToAllocate == 0) | ||
| 92 | return XML_FALSE; | ||
| 93 | |||
| 94 | - temp = (BLOCK *)pool->mem->realloc_fcn(pool->blocks, | ||
| 95 | - (unsigned)bytesToAllocate); | ||
| 96 | + temp = (BLOCK *)REALLOC(pool->parser, pool->blocks, | ||
| 97 | + (unsigned)bytesToAllocate); | ||
| 98 | if (temp == NULL) | ||
| 99 | return XML_FALSE; | ||
| 100 | pool->blocks = temp; | ||
| 101 | @@ -7831,7 +7830,7 @@ poolGrow(STRING_POOL *pool) { | ||
| 102 | if (bytesToAllocate == 0) | ||
| 103 | return XML_FALSE; | ||
| 104 | |||
| 105 | - tem = pool->mem->malloc_fcn(bytesToAllocate); | ||
| 106 | + tem = MALLOC(pool->parser, bytesToAllocate); | ||
| 107 | if (! tem) | ||
| 108 | return XML_FALSE; | ||
| 109 | tem->size = blockSize; | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-03.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-03.patch new file mode 100644 index 0000000000..b8c2c595e1 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-03.patch | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | From 4fc6f1ee9f2b282cfe446bf645c992e37f8c3e15 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Mon, 1 Sep 2025 18:14:09 +0200 | ||
| 4 | Subject: [PATCH] lib: Make function hash tables use macros MALLOC and FREE | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/4fc6f1ee9f2b282cfe446bf645c992e37f8c3e15] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | lib/xmlparse.c | 34 ++++++++++++++++------------------ | ||
| 11 | 1 file changed, 16 insertions(+), 18 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 14 | index a56c71ea..a65b0265 100644 | ||
| 15 | --- a/lib/xmlparse.c | ||
| 16 | +++ b/lib/xmlparse.c | ||
| 17 | @@ -234,7 +234,7 @@ typedef struct { | ||
| 18 | unsigned char power; | ||
| 19 | size_t size; | ||
| 20 | size_t used; | ||
| 21 | - const XML_Memory_Handling_Suite *mem; | ||
| 22 | + XML_Parser parser; | ||
| 23 | } HASH_TABLE; | ||
| 24 | |||
| 25 | static size_t keylen(KEY s); | ||
| 26 | @@ -566,8 +566,7 @@ static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable, | ||
| 27 | STRING_POOL *newPool, const HASH_TABLE *oldTable); | ||
| 28 | static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name, | ||
| 29 | size_t createSize); | ||
| 30 | -static void FASTCALL hashTableInit(HASH_TABLE *table, | ||
| 31 | - const XML_Memory_Handling_Suite *ms); | ||
| 32 | +static void FASTCALL hashTableInit(HASH_TABLE *table, XML_Parser parser); | ||
| 33 | static void FASTCALL hashTableClear(HASH_TABLE *table); | ||
| 34 | static void FASTCALL hashTableDestroy(HASH_TABLE *table); | ||
| 35 | static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *iter, | ||
| 36 | @@ -7126,19 +7125,18 @@ normalizePublicId(XML_Char *publicId) { | ||
| 37 | |||
| 38 | static DTD * | ||
| 39 | dtdCreate(XML_Parser parser) { | ||
| 40 | - const XML_Memory_Handling_Suite *const ms = &parser->m_mem; | ||
| 41 | DTD *p = MALLOC(parser, sizeof(DTD)); | ||
| 42 | if (p == NULL) | ||
| 43 | return p; | ||
| 44 | poolInit(&(p->pool), parser); | ||
| 45 | poolInit(&(p->entityValuePool), parser); | ||
| 46 | - hashTableInit(&(p->generalEntities), ms); | ||
| 47 | - hashTableInit(&(p->elementTypes), ms); | ||
| 48 | - hashTableInit(&(p->attributeIds), ms); | ||
| 49 | - hashTableInit(&(p->prefixes), ms); | ||
| 50 | + hashTableInit(&(p->generalEntities), parser); | ||
| 51 | + hashTableInit(&(p->elementTypes), parser); | ||
| 52 | + hashTableInit(&(p->attributeIds), parser); | ||
| 53 | + hashTableInit(&(p->prefixes), parser); | ||
| 54 | #ifdef XML_DTD | ||
| 55 | p->paramEntityRead = XML_FALSE; | ||
| 56 | - hashTableInit(&(p->paramEntities), ms); | ||
| 57 | + hashTableInit(&(p->paramEntities), parser); | ||
| 58 | #endif /* XML_DTD */ | ||
| 59 | p->defaultPrefix.name = NULL; | ||
| 60 | p->defaultPrefix.binding = NULL; | ||
| 61 | @@ -7473,7 +7471,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { | ||
| 62 | /* table->size is a power of 2 */ | ||
| 63 | table->size = (size_t)1 << INIT_POWER; | ||
| 64 | tsize = table->size * sizeof(NAMED *); | ||
| 65 | - table->v = table->mem->malloc_fcn(tsize); | ||
| 66 | + table->v = MALLOC(table->parser, tsize); | ||
| 67 | if (! table->v) { | ||
| 68 | table->size = 0; | ||
| 69 | return NULL; | ||
| 70 | @@ -7513,7 +7511,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { | ||
| 71 | } | ||
| 72 | |||
| 73 | size_t tsize = newSize * sizeof(NAMED *); | ||
| 74 | - NAMED **newV = table->mem->malloc_fcn(tsize); | ||
| 75 | + NAMED **newV = MALLOC(table->parser, tsize); | ||
| 76 | if (! newV) | ||
| 77 | return NULL; | ||
| 78 | memset(newV, 0, tsize); | ||
| 79 | @@ -7529,7 +7527,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { | ||
| 80 | } | ||
| 81 | newV[j] = table->v[i]; | ||
| 82 | } | ||
| 83 | - table->mem->free_fcn(table->v); | ||
| 84 | + FREE(table->parser, table->v); | ||
| 85 | table->v = newV; | ||
| 86 | table->power = newPower; | ||
| 87 | table->size = newSize; | ||
| 88 | @@ -7542,7 +7540,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | - table->v[i] = table->mem->malloc_fcn(createSize); | ||
| 93 | + table->v[i] = MALLOC(table->parser, createSize); | ||
| 94 | if (! table->v[i]) | ||
| 95 | return NULL; | ||
| 96 | memset(table->v[i], 0, createSize); | ||
| 97 | @@ -7555,7 +7553,7 @@ static void FASTCALL | ||
| 98 | hashTableClear(HASH_TABLE *table) { | ||
| 99 | size_t i; | ||
| 100 | for (i = 0; i < table->size; i++) { | ||
| 101 | - table->mem->free_fcn(table->v[i]); | ||
| 102 | + FREE(table->parser, table->v[i]); | ||
| 103 | table->v[i] = NULL; | ||
| 104 | } | ||
| 105 | table->used = 0; | ||
| 106 | @@ -7565,17 +7563,17 @@ static void FASTCALL | ||
| 107 | hashTableDestroy(HASH_TABLE *table) { | ||
| 108 | size_t i; | ||
| 109 | for (i = 0; i < table->size; i++) | ||
| 110 | - table->mem->free_fcn(table->v[i]); | ||
| 111 | - table->mem->free_fcn(table->v); | ||
| 112 | + FREE(table->parser, table->v[i]); | ||
| 113 | + FREE(table->parser, table->v); | ||
| 114 | } | ||
| 115 | |||
| 116 | static void FASTCALL | ||
| 117 | -hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) { | ||
| 118 | +hashTableInit(HASH_TABLE *p, XML_Parser parser) { | ||
| 119 | p->power = 0; | ||
| 120 | p->size = 0; | ||
| 121 | p->used = 0; | ||
| 122 | p->v = NULL; | ||
| 123 | - p->mem = ms; | ||
| 124 | + p->parser = parser; | ||
| 125 | } | ||
| 126 | |||
| 127 | static void FASTCALL | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-04.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-04.patch new file mode 100644 index 0000000000..78d9e2fc91 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-04.patch | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | From 51487ad9d760faa4809b0f8e189d2f666317e41a Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Mon, 1 Sep 2025 17:45:50 +0200 | ||
| 4 | Subject: [PATCH] lib: Make function copyString use macro MALLOC | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/51487ad9d760faa4809b0f8e189d2f666317e41a] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | lib/xmlparse.c | 11 +++++------ | ||
| 11 | 1 file changed, 5 insertions(+), 6 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 14 | index a65b0265..c0576abd 100644 | ||
| 15 | --- a/lib/xmlparse.c | ||
| 16 | +++ b/lib/xmlparse.c | ||
| 17 | @@ -593,8 +593,7 @@ static XML_Content *build_model(XML_Parser parser); | ||
| 18 | static ELEMENT_TYPE *getElementType(XML_Parser parser, const ENCODING *enc, | ||
| 19 | const char *ptr, const char *end); | ||
| 20 | |||
| 21 | -static XML_Char *copyString(const XML_Char *s, | ||
| 22 | - const XML_Memory_Handling_Suite *memsuite); | ||
| 23 | +static XML_Char *copyString(const XML_Char *s, XML_Parser parser); | ||
| 24 | |||
| 25 | static unsigned long generate_hash_secret_salt(XML_Parser parser); | ||
| 26 | static XML_Bool startParsing(XML_Parser parser); | ||
| 27 | @@ -1231,7 +1230,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) { | ||
| 28 | parser->m_processor = prologInitProcessor; | ||
| 29 | XmlPrologStateInit(&parser->m_prologState); | ||
| 30 | if (encodingName != NULL) { | ||
| 31 | - parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem)); | ||
| 32 | + parser->m_protocolEncodingName = copyString(encodingName, parser); | ||
| 33 | } | ||
| 34 | parser->m_curBase = NULL; | ||
| 35 | XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0); | ||
| 36 | @@ -1419,7 +1418,7 @@ XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) { | ||
| 37 | parser->m_protocolEncodingName = NULL; | ||
| 38 | else { | ||
| 39 | /* Copy the new encoding name into allocated memory */ | ||
| 40 | - parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem)); | ||
| 41 | + parser->m_protocolEncodingName = copyString(encodingName, parser); | ||
| 42 | if (! parser->m_protocolEncodingName) | ||
| 43 | return XML_STATUS_ERROR; | ||
| 44 | } | ||
| 45 | @@ -8064,7 +8063,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, | ||
| 46 | } | ||
| 47 | |||
| 48 | static XML_Char * | ||
| 49 | -copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { | ||
| 50 | +copyString(const XML_Char *s, XML_Parser parser) { | ||
| 51 | size_t charsRequired = 0; | ||
| 52 | XML_Char *result; | ||
| 53 | |||
| 54 | @@ -8076,7 +8075,7 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { | ||
| 55 | charsRequired++; | ||
| 56 | |||
| 57 | /* Now allocate space for the copy */ | ||
| 58 | - result = memsuite->malloc_fcn(charsRequired * sizeof(XML_Char)); | ||
| 59 | + result = MALLOC(parser, charsRequired * sizeof(XML_Char)); | ||
| 60 | if (result == NULL) | ||
| 61 | return NULL; | ||
| 62 | /* Copy the original into place */ | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-05.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-05.patch new file mode 100644 index 0000000000..37b882fbf4 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-05.patch | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | From b3f0bda5f5e979781469532f7c304f7e223568d5 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Mon, 1 Sep 2025 17:48:02 +0200 | ||
| 4 | Subject: [PATCH] lib: Make function dtdReset use macro FREE | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/b3f0bda5f5e979781469532f7c304f7e223568d5] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | lib/xmlparse.c | 12 ++++++------ | ||
| 11 | 1 file changed, 6 insertions(+), 6 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 14 | index c0576abd..65fcce30 100644 | ||
| 15 | --- a/lib/xmlparse.c | ||
| 16 | +++ b/lib/xmlparse.c | ||
| 17 | @@ -557,7 +557,7 @@ static void FASTCALL normalizePublicId(XML_Char *s); | ||
| 18 | |||
| 19 | static DTD *dtdCreate(XML_Parser parser); | ||
| 20 | /* do not call if m_parentParser != NULL */ | ||
| 21 | -static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms); | ||
| 22 | +static void dtdReset(DTD *p, XML_Parser parser); | ||
| 23 | static void dtdDestroy(DTD *p, XML_Bool isDocEntity, | ||
| 24 | const XML_Memory_Handling_Suite *ms); | ||
| 25 | static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, | ||
| 26 | @@ -1382,7 +1382,7 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) { | ||
| 27 | FREE(parser, (void *)parser->m_protocolEncodingName); | ||
| 28 | parser->m_protocolEncodingName = NULL; | ||
| 29 | parserInit(parser, encodingName); | ||
| 30 | - dtdReset(parser->m_dtd, &parser->m_mem); | ||
| 31 | + dtdReset(parser->m_dtd, parser); | ||
| 32 | return XML_TRUE; | ||
| 33 | } | ||
| 34 | |||
| 35 | @@ -7155,7 +7155,7 @@ dtdCreate(XML_Parser parser) { | ||
| 36 | } | ||
| 37 | |||
| 38 | static void | ||
| 39 | -dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { | ||
| 40 | +dtdReset(DTD *p, XML_Parser parser) { | ||
| 41 | HASH_TABLE_ITER iter; | ||
| 42 | hashTableIterInit(&iter, &(p->elementTypes)); | ||
| 43 | for (;;) { | ||
| 44 | @@ -7163,7 +7163,7 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { | ||
| 45 | if (! e) | ||
| 46 | break; | ||
| 47 | if (e->allocDefaultAtts != 0) | ||
| 48 | - ms->free_fcn(e->defaultAtts); | ||
| 49 | + FREE(parser, e->defaultAtts); | ||
| 50 | } | ||
| 51 | hashTableClear(&(p->generalEntities)); | ||
| 52 | #ifdef XML_DTD | ||
| 53 | @@ -7180,9 +7180,9 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) { | ||
| 54 | |||
| 55 | p->in_eldecl = XML_FALSE; | ||
| 56 | |||
| 57 | - ms->free_fcn(p->scaffIndex); | ||
| 58 | + FREE(parser, p->scaffIndex); | ||
| 59 | p->scaffIndex = NULL; | ||
| 60 | - ms->free_fcn(p->scaffold); | ||
| 61 | + FREE(parser, p->scaffold); | ||
| 62 | p->scaffold = NULL; | ||
| 63 | |||
| 64 | p->scaffLevel = 0; | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-06.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-06.patch new file mode 100644 index 0000000000..04f975a458 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-06.patch | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | From 53a3eda0ae2e0317afd071b72b41976053d82732 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Mon, 1 Sep 2025 17:50:59 +0200 | ||
| 4 | Subject: [PATCH] lib: Make function dtdDestroy use macro FREE | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/53a3eda0ae2e0317afd071b72b41976053d82732] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | lib/xmlparse.c | 16 +++++++--------- | ||
| 11 | 1 file changed, 7 insertions(+), 9 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 14 | index 65fcce30..e7df97da 100644 | ||
| 15 | --- a/lib/xmlparse.c | ||
| 16 | +++ b/lib/xmlparse.c | ||
| 17 | @@ -558,8 +558,7 @@ static void FASTCALL normalizePublicId(XML_Char *s); | ||
| 18 | static DTD *dtdCreate(XML_Parser parser); | ||
| 19 | /* do not call if m_parentParser != NULL */ | ||
| 20 | static void dtdReset(DTD *p, XML_Parser parser); | ||
| 21 | -static void dtdDestroy(DTD *p, XML_Bool isDocEntity, | ||
| 22 | - const XML_Memory_Handling_Suite *ms); | ||
| 23 | +static void dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser); | ||
| 24 | static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, | ||
| 25 | const XML_Memory_Handling_Suite *ms); | ||
| 26 | static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable, | ||
| 27 | @@ -1685,8 +1684,7 @@ XML_ParserFree(XML_Parser parser) { | ||
| 28 | #else | ||
| 29 | if (parser->m_dtd) | ||
| 30 | #endif /* XML_DTD */ | ||
| 31 | - dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser, | ||
| 32 | - &parser->m_mem); | ||
| 33 | + dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser, parser); | ||
| 34 | FREE(parser, (void *)parser->m_atts); | ||
| 35 | #ifdef XML_ATTR_INFO | ||
| 36 | FREE(parser, (void *)parser->m_attInfo); | ||
| 37 | @@ -7196,7 +7194,7 @@ dtdReset(DTD *p, XML_Parser parser) { | ||
| 38 | } | ||
| 39 | |||
| 40 | static void | ||
| 41 | -dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { | ||
| 42 | +dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser) { | ||
| 43 | HASH_TABLE_ITER iter; | ||
| 44 | hashTableIterInit(&iter, &(p->elementTypes)); | ||
| 45 | for (;;) { | ||
| 46 | @@ -7204,7 +7202,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { | ||
| 47 | if (! e) | ||
| 48 | break; | ||
| 49 | if (e->allocDefaultAtts != 0) | ||
| 50 | - ms->free_fcn(e->defaultAtts); | ||
| 51 | + FREE(parser, e->defaultAtts); | ||
| 52 | } | ||
| 53 | hashTableDestroy(&(p->generalEntities)); | ||
| 54 | #ifdef XML_DTD | ||
| 55 | @@ -7216,10 +7214,10 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) { | ||
| 56 | poolDestroy(&(p->pool)); | ||
| 57 | poolDestroy(&(p->entityValuePool)); | ||
| 58 | if (isDocEntity) { | ||
| 59 | - ms->free_fcn(p->scaffIndex); | ||
| 60 | - ms->free_fcn(p->scaffold); | ||
| 61 | + FREE(parser, p->scaffIndex); | ||
| 62 | + FREE(parser, p->scaffold); | ||
| 63 | } | ||
| 64 | - ms->free_fcn(p); | ||
| 65 | + FREE(parser, p); | ||
| 66 | } | ||
| 67 | |||
| 68 | /* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise. | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-07.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-07.patch new file mode 100644 index 0000000000..7eff0009d2 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-07.patch | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | From 4e7a5d03daf672f20c73d40dc8970385c18b30d3 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Mon, 1 Sep 2025 17:52:58 +0200 | ||
| 4 | Subject: [PATCH] lib: Make function dtdCopy use macro MALLOC | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/4e7a5d03daf672f20c73d40dc8970385c18b30d3] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | lib/xmlparse.c | 8 ++++---- | ||
| 11 | 1 file changed, 4 insertions(+), 4 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 14 | index e7df97da..9f0a8b3e 100644 | ||
| 15 | --- a/lib/xmlparse.c | ||
| 16 | +++ b/lib/xmlparse.c | ||
| 17 | @@ -560,7 +560,7 @@ static DTD *dtdCreate(XML_Parser parser); | ||
| 18 | static void dtdReset(DTD *p, XML_Parser parser); | ||
| 19 | static void dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser); | ||
| 20 | static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, | ||
| 21 | - const XML_Memory_Handling_Suite *ms); | ||
| 22 | + XML_Parser parser); | ||
| 23 | static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable, | ||
| 24 | STRING_POOL *newPool, const HASH_TABLE *oldTable); | ||
| 25 | static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name, | ||
| 26 | @@ -1572,7 +1572,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, | ||
| 27 | parser->m_prologState.inEntityValue = oldInEntityValue; | ||
| 28 | if (context) { | ||
| 29 | #endif /* XML_DTD */ | ||
| 30 | - if (! dtdCopy(oldParser, parser->m_dtd, oldDtd, &parser->m_mem) | ||
| 31 | + if (! dtdCopy(oldParser, parser->m_dtd, oldDtd, parser) | ||
| 32 | || ! setContext(parser, context)) { | ||
| 33 | XML_ParserFree(parser); | ||
| 34 | return NULL; | ||
| 35 | @@ -7225,7 +7225,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser) { | ||
| 36 | */ | ||
| 37 | static int | ||
| 38 | dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, | ||
| 39 | - const XML_Memory_Handling_Suite *ms) { | ||
| 40 | + XML_Parser parser) { | ||
| 41 | HASH_TABLE_ITER iter; | ||
| 42 | |||
| 43 | /* Copy the prefix table. */ | ||
| 44 | @@ -7306,7 +7306,7 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, | ||
| 45 | } | ||
| 46 | #endif | ||
| 47 | newE->defaultAtts | ||
| 48 | - = ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); | ||
| 49 | + = MALLOC(parser, oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); | ||
| 50 | if (! newE->defaultAtts) { | ||
| 51 | return 0; | ||
| 52 | } | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-08.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-08.patch new file mode 100644 index 0000000000..deda31bebc --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-08.patch | |||
| @@ -0,0 +1,577 @@ | |||
| 1 | From cfce28e171676fe6f70d17b97ed8a59eaeb83f15 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Mon, 1 Sep 2025 17:34:58 +0200 | ||
| 4 | Subject: [PATCH] lib: Implement tracking of dynamic memory allocations | ||
| 5 | |||
| 6 | **PLEASE NOTE** that distributors intending to backport (or cherry-pick) | ||
| 7 | this fix need to copy 99% of the related pull request, not just this | ||
| 8 | commit, to not end up with a state that literally does both too much and | ||
| 9 | too little at the same time. Appending ".diff" to the pull request URL | ||
| 10 | could be of help. | ||
| 11 | |||
| 12 | CVE: CVE-2025-59375 | ||
| 13 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/cfce28e171676fe6f70d17b97ed8a59eaeb83f15] | ||
| 14 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 15 | --- | ||
| 16 | lib/expat.h | 15 +- | ||
| 17 | lib/internal.h | 5 + | ||
| 18 | lib/libexpat.def.cmake | 3 + | ||
| 19 | lib/xmlparse.c | 337 +++++++++++++++++++++++++++++++++++++++-- | ||
| 20 | tests/basic_tests.c | 4 + | ||
| 21 | tests/nsalloc_tests.c | 5 + | ||
| 22 | xmlwf/xmlwf.c | 2 + | ||
| 23 | xmlwf/xmlwf_helpgen.py | 2 + | ||
| 24 | 8 files changed, 361 insertions(+), 12 deletions(-) | ||
| 25 | |||
| 26 | diff --git a/lib/expat.h b/lib/expat.h | ||
| 27 | index 610e1ddc..66a253c1 100644 | ||
| 28 | --- a/lib/expat.h | ||
| 29 | +++ b/lib/expat.h | ||
| 30 | @@ -1032,7 +1032,10 @@ enum XML_FeatureEnum { | ||
| 31 | XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT, | ||
| 32 | XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT, | ||
| 33 | /* Added in Expat 2.6.0. */ | ||
| 34 | - XML_FEATURE_GE | ||
| 35 | + XML_FEATURE_GE, | ||
| 36 | + /* Added in Expat 2.7.2. */ | ||
| 37 | + XML_FEATURE_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT, | ||
| 38 | + XML_FEATURE_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT, | ||
| 39 | /* Additional features must be added to the end of this enum. */ | ||
| 40 | }; | ||
| 41 | |||
| 42 | @@ -1057,6 +1060,16 @@ XML_SetBillionLaughsAttackProtectionMaximumAmplification( | ||
| 43 | XMLPARSEAPI(XML_Bool) | ||
| 44 | XML_SetBillionLaughsAttackProtectionActivationThreshold( | ||
| 45 | XML_Parser parser, unsigned long long activationThresholdBytes); | ||
| 46 | + | ||
| 47 | +/* Added in Expat 2.7.2. */ | ||
| 48 | +XMLPARSEAPI(XML_Bool) | ||
| 49 | +XML_SetAllocTrackerMaximumAmplification(XML_Parser parser, | ||
| 50 | + float maximumAmplificationFactor); | ||
| 51 | + | ||
| 52 | +/* Added in Expat 2.7.2. */ | ||
| 53 | +XMLPARSEAPI(XML_Bool) | ||
| 54 | +XML_SetAllocTrackerActivationThreshold( | ||
| 55 | + XML_Parser parser, unsigned long long activationThresholdBytes); | ||
| 56 | #endif | ||
| 57 | |||
| 58 | /* Added in Expat 2.6.0. */ | ||
| 59 | diff --git a/lib/internal.h b/lib/internal.h | ||
| 60 | index 6bde6ae6..eb67cf50 100644 | ||
| 61 | --- a/lib/internal.h | ||
| 62 | +++ b/lib/internal.h | ||
| 63 | @@ -145,6 +145,11 @@ | ||
| 64 | 100.0f | ||
| 65 | #define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT \ | ||
| 66 | 8388608 // 8 MiB, 2^23 | ||
| 67 | + | ||
| 68 | +#define EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT 100.0f | ||
| 69 | +#define EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT \ | ||
| 70 | + 67108864 // 64 MiB, 2^26 | ||
| 71 | + | ||
| 72 | /* NOTE END */ | ||
| 73 | |||
| 74 | #include "expat.h" // so we can use type XML_Parser below | ||
| 75 | diff --git a/lib/libexpat.def.cmake b/lib/libexpat.def.cmake | ||
| 76 | index 10ee9cd6..7a3a7ec0 100644 | ||
| 77 | --- a/lib/libexpat.def.cmake | ||
| 78 | +++ b/lib/libexpat.def.cmake | ||
| 79 | @@ -79,3 +79,6 @@ EXPORTS | ||
| 80 | @_EXPAT_COMMENT_DTD_OR_GE@ XML_SetBillionLaughsAttackProtectionMaximumAmplification @70 | ||
| 81 | ; added with version 2.6.0 | ||
| 82 | XML_SetReparseDeferralEnabled @71 | ||
| 83 | +; added with version 2.7.2 | ||
| 84 | +@_EXPAT_COMMENT_DTD_OR_GE@ XML_SetAllocTrackerMaximumAmplification @72 | ||
| 85 | +@_EXPAT_COMMENT_DTD_OR_GE@ XML_SetAllocTrackerActivationThreshold @73 | ||
| 86 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 87 | index 9f0a8b3e..fcf1cfdd 100644 | ||
| 88 | --- a/lib/xmlparse.c | ||
| 89 | +++ b/lib/xmlparse.c | ||
| 90 | @@ -452,6 +452,14 @@ typedef struct accounting { | ||
| 91 | unsigned long long activationThresholdBytes; | ||
| 92 | } ACCOUNTING; | ||
| 93 | |||
| 94 | +typedef struct MALLOC_TRACKER { | ||
| 95 | + XmlBigCount bytesAllocated; | ||
| 96 | + XmlBigCount peakBytesAllocated; // updated live only for debug level >=2 | ||
| 97 | + unsigned long debugLevel; | ||
| 98 | + float maximumAmplificationFactor; // >=1.0 | ||
| 99 | + XmlBigCount activationThresholdBytes; | ||
| 100 | +} MALLOC_TRACKER; | ||
| 101 | + | ||
| 102 | typedef struct entity_stats { | ||
| 103 | unsigned int countEverOpened; | ||
| 104 | unsigned int currentDepth; | ||
| 105 | @@ -599,7 +607,8 @@ static XML_Bool startParsing(XML_Parser parser); | ||
| 106 | |||
| 107 | static XML_Parser parserCreate(const XML_Char *encodingName, | ||
| 108 | const XML_Memory_Handling_Suite *memsuite, | ||
| 109 | - const XML_Char *nameSep, DTD *dtd); | ||
| 110 | + const XML_Char *nameSep, DTD *dtd, | ||
| 111 | + XML_Parser parentParser); | ||
| 112 | |||
| 113 | static void parserInit(XML_Parser parser, const XML_Char *encodingName); | ||
| 114 | |||
| 115 | @@ -769,14 +778,220 @@ struct XML_ParserStruct { | ||
| 116 | unsigned long m_hash_secret_salt; | ||
| 117 | #if XML_GE == 1 | ||
| 118 | ACCOUNTING m_accounting; | ||
| 119 | + MALLOC_TRACKER m_alloc_tracker; | ||
| 120 | ENTITY_STATS m_entity_stats; | ||
| 121 | #endif | ||
| 122 | XML_Bool m_reenter; | ||
| 123 | }; | ||
| 124 | |||
| 125 | -#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s))) | ||
| 126 | -#define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p), (s))) | ||
| 127 | -#define FREE(parser, p) (parser->m_mem.free_fcn((p))) | ||
| 128 | +#if XML_GE == 1 | ||
| 129 | +# define MALLOC(parser, s) (expat_malloc((parser), (s), __LINE__)) | ||
| 130 | +# define REALLOC(parser, p, s) (expat_realloc((parser), (p), (s), __LINE__)) | ||
| 131 | +# define FREE(parser, p) (expat_free((parser), (p), __LINE__)) | ||
| 132 | +#else | ||
| 133 | +# define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s))) | ||
| 134 | +# define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p), (s))) | ||
| 135 | +# define FREE(parser, p) (parser->m_mem.free_fcn((p))) | ||
| 136 | +#endif | ||
| 137 | + | ||
| 138 | +#if XML_GE == 1 | ||
| 139 | +static void | ||
| 140 | +expat_heap_stat(XML_Parser rootParser, char operator, XmlBigCount absDiff, | ||
| 141 | + XmlBigCount newTotal, XmlBigCount peakTotal, int sourceLine) { | ||
| 142 | + // NOTE: This can be +infinity or -nan | ||
| 143 | + const float amplification | ||
| 144 | + = (float)newTotal / (float)rootParser->m_accounting.countBytesDirect; | ||
| 145 | + fprintf( | ||
| 146 | + stderr, | ||
| 147 | + "expat: Allocations(%p): Direct " EXPAT_FMT_ULL("10") ", allocated %c" EXPAT_FMT_ULL( | ||
| 148 | + "10") " to " EXPAT_FMT_ULL("10") " (" EXPAT_FMT_ULL("10") " peak), amplification %8.2f (xmlparse.c:%d)\n", | ||
| 149 | + (void *)rootParser, rootParser->m_accounting.countBytesDirect, operator, | ||
| 150 | + absDiff, newTotal, peakTotal, (double)amplification, sourceLine); | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | +static bool | ||
| 154 | +expat_heap_increase_tolerable(XML_Parser rootParser, XmlBigCount increase, | ||
| 155 | + int sourceLine) { | ||
| 156 | + assert(rootParser != NULL); | ||
| 157 | + assert(increase > 0); | ||
| 158 | + | ||
| 159 | + XmlBigCount newTotal = 0; | ||
| 160 | + bool tolerable = true; | ||
| 161 | + | ||
| 162 | + // Detect integer overflow | ||
| 163 | + if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated < increase) { | ||
| 164 | + tolerable = false; | ||
| 165 | + } else { | ||
| 166 | + newTotal = rootParser->m_alloc_tracker.bytesAllocated + increase; | ||
| 167 | + | ||
| 168 | + if (newTotal >= rootParser->m_alloc_tracker.activationThresholdBytes) { | ||
| 169 | + assert(newTotal > 0); | ||
| 170 | + // NOTE: This can be +infinity when dividing by zero but not -nan | ||
| 171 | + const float amplification | ||
| 172 | + = (float)newTotal / (float)rootParser->m_accounting.countBytesDirect; | ||
| 173 | + if (amplification | ||
| 174 | + > rootParser->m_alloc_tracker.maximumAmplificationFactor) { | ||
| 175 | + tolerable = false; | ||
| 176 | + } | ||
| 177 | + } | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + if (! tolerable && (rootParser->m_alloc_tracker.debugLevel >= 1)) { | ||
| 181 | + expat_heap_stat(rootParser, '+', increase, newTotal, newTotal, sourceLine); | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + return tolerable; | ||
| 185 | +} | ||
| 186 | + | ||
| 187 | +static void * | ||
| 188 | +expat_malloc(XML_Parser parser, size_t size, int sourceLine) { | ||
| 189 | + // Detect integer overflow | ||
| 190 | + if (SIZE_MAX - size < sizeof(size_t)) { | ||
| 191 | + return NULL; | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + const XML_Parser rootParser = getRootParserOf(parser, NULL); | ||
| 195 | + assert(rootParser->m_parentParser == NULL); | ||
| 196 | + | ||
| 197 | + const size_t bytesToAllocate = sizeof(size_t) + size; | ||
| 198 | + | ||
| 199 | + if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated | ||
| 200 | + < bytesToAllocate) { | ||
| 201 | + return NULL; // i.e. signal integer overflow as out-of-memory | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + if (! expat_heap_increase_tolerable(rootParser, bytesToAllocate, | ||
| 205 | + sourceLine)) { | ||
| 206 | + return NULL; // i.e. signal violation as out-of-memory | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + // Actually allocate | ||
| 210 | + void *const mallocedPtr = parser->m_mem.malloc_fcn(bytesToAllocate); | ||
| 211 | + | ||
| 212 | + if (mallocedPtr == NULL) { | ||
| 213 | + return NULL; | ||
| 214 | + } | ||
| 215 | + | ||
| 216 | + // Update in-block recorded size | ||
| 217 | + *(size_t *)mallocedPtr = size; | ||
| 218 | + | ||
| 219 | + // Update accounting | ||
| 220 | + rootParser->m_alloc_tracker.bytesAllocated += bytesToAllocate; | ||
| 221 | + | ||
| 222 | + // Report as needed | ||
| 223 | + if (rootParser->m_alloc_tracker.debugLevel >= 2) { | ||
| 224 | + if (rootParser->m_alloc_tracker.bytesAllocated | ||
| 225 | + > rootParser->m_alloc_tracker.peakBytesAllocated) { | ||
| 226 | + rootParser->m_alloc_tracker.peakBytesAllocated | ||
| 227 | + = rootParser->m_alloc_tracker.bytesAllocated; | ||
| 228 | + } | ||
| 229 | + expat_heap_stat(rootParser, '+', bytesToAllocate, | ||
| 230 | + rootParser->m_alloc_tracker.bytesAllocated, | ||
| 231 | + rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); | ||
| 232 | + } | ||
| 233 | + | ||
| 234 | + return (char *)mallocedPtr + sizeof(size_t); | ||
| 235 | +} | ||
| 236 | + | ||
| 237 | +static void | ||
| 238 | +expat_free(XML_Parser parser, void *ptr, int sourceLine) { | ||
| 239 | + assert(parser != NULL); | ||
| 240 | + | ||
| 241 | + if (ptr == NULL) { | ||
| 242 | + return; | ||
| 243 | + } | ||
| 244 | + | ||
| 245 | + const XML_Parser rootParser = getRootParserOf(parser, NULL); | ||
| 246 | + assert(rootParser->m_parentParser == NULL); | ||
| 247 | + | ||
| 248 | + // Extract size (to the eyes of malloc_fcn/realloc_fcn) and | ||
| 249 | + // the original pointer returned by malloc/realloc | ||
| 250 | + void *const mallocedPtr = (char *)ptr - sizeof(size_t); | ||
| 251 | + const size_t bytesAllocated = sizeof(size_t) + *(size_t *)mallocedPtr; | ||
| 252 | + | ||
| 253 | + // Update accounting | ||
| 254 | + assert(rootParser->m_alloc_tracker.bytesAllocated >= bytesAllocated); | ||
| 255 | + rootParser->m_alloc_tracker.bytesAllocated -= bytesAllocated; | ||
| 256 | + | ||
| 257 | + // Report as needed | ||
| 258 | + if (rootParser->m_alloc_tracker.debugLevel >= 2) { | ||
| 259 | + expat_heap_stat(rootParser, '-', bytesAllocated, | ||
| 260 | + rootParser->m_alloc_tracker.bytesAllocated, | ||
| 261 | + rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + // NOTE: This may be freeing rootParser, so freeing has to come last | ||
| 265 | + parser->m_mem.free_fcn(mallocedPtr); | ||
| 266 | +} | ||
| 267 | + | ||
| 268 | +static void * | ||
| 269 | +expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { | ||
| 270 | + assert(parser != NULL); | ||
| 271 | + | ||
| 272 | + if (ptr == NULL) { | ||
| 273 | + return expat_malloc(parser, size, sourceLine); | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + if (size == 0) { | ||
| 277 | + expat_free(parser, ptr, sourceLine); | ||
| 278 | + return NULL; | ||
| 279 | + } | ||
| 280 | + | ||
| 281 | + const XML_Parser rootParser = getRootParserOf(parser, NULL); | ||
| 282 | + assert(rootParser->m_parentParser == NULL); | ||
| 283 | + | ||
| 284 | + // Extract original size (to the eyes of the caller) and the original | ||
| 285 | + // pointer returned by malloc/realloc | ||
| 286 | + void *mallocedPtr = (char *)ptr - sizeof(size_t); | ||
| 287 | + const size_t prevSize = *(size_t *)mallocedPtr; | ||
| 288 | + | ||
| 289 | + // Classify upcoming change | ||
| 290 | + const bool isIncrease = (size > prevSize); | ||
| 291 | + const size_t absDiff | ||
| 292 | + = (size > prevSize) ? (size - prevSize) : (prevSize - size); | ||
| 293 | + | ||
| 294 | + // Ask for permission from accounting | ||
| 295 | + if (isIncrease) { | ||
| 296 | + if (! expat_heap_increase_tolerable(rootParser, absDiff, sourceLine)) { | ||
| 297 | + return NULL; // i.e. signal violation as out-of-memory | ||
| 298 | + } | ||
| 299 | + } | ||
| 300 | + | ||
| 301 | + // Actually allocate | ||
| 302 | + mallocedPtr = parser->m_mem.realloc_fcn(mallocedPtr, sizeof(size_t) + size); | ||
| 303 | + | ||
| 304 | + if (mallocedPtr == NULL) { | ||
| 305 | + return NULL; | ||
| 306 | + } | ||
| 307 | + | ||
| 308 | + // Update accounting | ||
| 309 | + if (isIncrease) { | ||
| 310 | + assert((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated | ||
| 311 | + >= absDiff); | ||
| 312 | + rootParser->m_alloc_tracker.bytesAllocated += absDiff; | ||
| 313 | + } else { // i.e. decrease | ||
| 314 | + assert(rootParser->m_alloc_tracker.bytesAllocated >= absDiff); | ||
| 315 | + rootParser->m_alloc_tracker.bytesAllocated -= absDiff; | ||
| 316 | + } | ||
| 317 | + | ||
| 318 | + // Report as needed | ||
| 319 | + if (rootParser->m_alloc_tracker.debugLevel >= 2) { | ||
| 320 | + if (rootParser->m_alloc_tracker.bytesAllocated | ||
| 321 | + > rootParser->m_alloc_tracker.peakBytesAllocated) { | ||
| 322 | + rootParser->m_alloc_tracker.peakBytesAllocated | ||
| 323 | + = rootParser->m_alloc_tracker.bytesAllocated; | ||
| 324 | + } | ||
| 325 | + expat_heap_stat(rootParser, isIncrease ? '+' : '-', absDiff, | ||
| 326 | + rootParser->m_alloc_tracker.bytesAllocated, | ||
| 327 | + rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); | ||
| 328 | + } | ||
| 329 | + | ||
| 330 | + // Update in-block recorded size | ||
| 331 | + *(size_t *)mallocedPtr = size; | ||
| 332 | + | ||
| 333 | + return (char *)mallocedPtr + sizeof(size_t); | ||
| 334 | +} | ||
| 335 | +#endif // XML_GE == 1 | ||
| 336 | |||
| 337 | XML_Parser XMLCALL | ||
| 338 | XML_ParserCreate(const XML_Char *encodingName) { | ||
| 339 | @@ -1096,19 +1311,40 @@ XML_Parser XMLCALL | ||
| 340 | XML_ParserCreate_MM(const XML_Char *encodingName, | ||
| 341 | const XML_Memory_Handling_Suite *memsuite, | ||
| 342 | const XML_Char *nameSep) { | ||
| 343 | - return parserCreate(encodingName, memsuite, nameSep, NULL); | ||
| 344 | + return parserCreate(encodingName, memsuite, nameSep, NULL, NULL); | ||
| 345 | } | ||
| 346 | |||
| 347 | static XML_Parser | ||
| 348 | parserCreate(const XML_Char *encodingName, | ||
| 349 | const XML_Memory_Handling_Suite *memsuite, const XML_Char *nameSep, | ||
| 350 | - DTD *dtd) { | ||
| 351 | - XML_Parser parser; | ||
| 352 | + DTD *dtd, XML_Parser parentParser) { | ||
| 353 | + XML_Parser parser = NULL; | ||
| 354 | + | ||
| 355 | +#if XML_GE == 1 | ||
| 356 | + const size_t increase = sizeof(size_t) + sizeof(struct XML_ParserStruct); | ||
| 357 | + | ||
| 358 | + if (parentParser != NULL) { | ||
| 359 | + const XML_Parser rootParser = getRootParserOf(parentParser, NULL); | ||
| 360 | + if (! expat_heap_increase_tolerable(rootParser, increase, __LINE__)) { | ||
| 361 | + return NULL; | ||
| 362 | + } | ||
| 363 | + } | ||
| 364 | +#else | ||
| 365 | + UNUSED_P(parentParser); | ||
| 366 | +#endif | ||
| 367 | |||
| 368 | if (memsuite) { | ||
| 369 | XML_Memory_Handling_Suite *mtemp; | ||
| 370 | +#if XML_GE == 1 | ||
| 371 | + void *const sizeAndParser = memsuite->malloc_fcn( | ||
| 372 | + sizeof(size_t) + sizeof(struct XML_ParserStruct)); | ||
| 373 | + if (sizeAndParser != NULL) { | ||
| 374 | + *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); | ||
| 375 | + parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)); | ||
| 376 | +#else | ||
| 377 | parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); | ||
| 378 | if (parser != NULL) { | ||
| 379 | +#endif | ||
| 380 | mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); | ||
| 381 | mtemp->malloc_fcn = memsuite->malloc_fcn; | ||
| 382 | mtemp->realloc_fcn = memsuite->realloc_fcn; | ||
| 383 | @@ -1116,18 +1352,67 @@ parserCreate(const XML_Char *encodingName, | ||
| 384 | } | ||
| 385 | } else { | ||
| 386 | XML_Memory_Handling_Suite *mtemp; | ||
| 387 | +#if XML_GE == 1 | ||
| 388 | + void *const sizeAndParser | ||
| 389 | + = (XML_Parser)malloc(sizeof(size_t) + sizeof(struct XML_ParserStruct)); | ||
| 390 | + if (sizeAndParser != NULL) { | ||
| 391 | + *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); | ||
| 392 | + parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)); | ||
| 393 | +#else | ||
| 394 | parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct)); | ||
| 395 | if (parser != NULL) { | ||
| 396 | +#endif | ||
| 397 | mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); | ||
| 398 | mtemp->malloc_fcn = malloc; | ||
| 399 | mtemp->realloc_fcn = realloc; | ||
| 400 | mtemp->free_fcn = free; | ||
| 401 | } | ||
| 402 | - } | ||
| 403 | + } // cppcheck-suppress[memleak symbolName=sizeAndParser] // Cppcheck >=2.18.0 | ||
| 404 | |||
| 405 | if (! parser) | ||
| 406 | return parser; | ||
| 407 | |||
| 408 | +#if XML_GE == 1 | ||
| 409 | + // Initialize .m_alloc_tracker | ||
| 410 | + memset(&parser->m_alloc_tracker, 0, sizeof(MALLOC_TRACKER)); | ||
| 411 | + if (parentParser == NULL) { | ||
| 412 | + parser->m_alloc_tracker.debugLevel | ||
| 413 | + = getDebugLevel("EXPAT_MALLOC_DEBUG", 0u); | ||
| 414 | + parser->m_alloc_tracker.maximumAmplificationFactor | ||
| 415 | + = EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT; | ||
| 416 | + parser->m_alloc_tracker.activationThresholdBytes | ||
| 417 | + = EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT; | ||
| 418 | + | ||
| 419 | + // NOTE: This initialization needs to come this early because these fields | ||
| 420 | + // are read by allocation tracking code | ||
| 421 | + parser->m_parentParser = NULL; | ||
| 422 | + parser->m_accounting.countBytesDirect = 0; | ||
| 423 | + } else { | ||
| 424 | + parser->m_parentParser = parentParser; | ||
| 425 | + } | ||
| 426 | + | ||
| 427 | + // Record XML_ParserStruct allocation we did a few lines up before | ||
| 428 | + const XML_Parser rootParser = getRootParserOf(parser, NULL); | ||
| 429 | + assert(rootParser->m_parentParser == NULL); | ||
| 430 | + assert(SIZE_MAX - rootParser->m_alloc_tracker.bytesAllocated >= increase); | ||
| 431 | + rootParser->m_alloc_tracker.bytesAllocated += increase; | ||
| 432 | + | ||
| 433 | + // Report on allocation | ||
| 434 | + if (rootParser->m_alloc_tracker.debugLevel >= 2) { | ||
| 435 | + if (rootParser->m_alloc_tracker.bytesAllocated | ||
| 436 | + > rootParser->m_alloc_tracker.peakBytesAllocated) { | ||
| 437 | + rootParser->m_alloc_tracker.peakBytesAllocated | ||
| 438 | + = rootParser->m_alloc_tracker.bytesAllocated; | ||
| 439 | + } | ||
| 440 | + | ||
| 441 | + expat_heap_stat(rootParser, '+', increase, | ||
| 442 | + rootParser->m_alloc_tracker.bytesAllocated, | ||
| 443 | + rootParser->m_alloc_tracker.peakBytesAllocated, __LINE__); | ||
| 444 | + } | ||
| 445 | +#else | ||
| 446 | + parser->m_parentParser = NULL; | ||
| 447 | +#endif // XML_GE == 1 | ||
| 448 | + | ||
| 449 | parser->m_buffer = NULL; | ||
| 450 | parser->m_bufferLim = NULL; | ||
| 451 | |||
| 452 | @@ -1291,7 +1576,6 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) { | ||
| 453 | parser->m_unknownEncodingMem = NULL; | ||
| 454 | parser->m_unknownEncodingRelease = NULL; | ||
| 455 | parser->m_unknownEncodingData = NULL; | ||
| 456 | - parser->m_parentParser = NULL; | ||
| 457 | parser->m_parsingStatus.parsing = XML_INITIALIZED; | ||
| 458 | // Reentry can only be triggered inside m_processor calls | ||
| 459 | parser->m_reenter = XML_FALSE; | ||
| 460 | @@ -1526,9 +1810,10 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, | ||
| 461 | */ | ||
| 462 | if (parser->m_ns) { | ||
| 463 | XML_Char tmp[2] = {parser->m_namespaceSeparator, 0}; | ||
| 464 | - parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); | ||
| 465 | + parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd, oldParser); | ||
| 466 | } else { | ||
| 467 | - parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); | ||
| 468 | + parser | ||
| 469 | + = parserCreate(encodingName, &parser->m_mem, NULL, newDtd, oldParser); | ||
| 470 | } | ||
| 471 | |||
| 472 | if (! parser) | ||
| 473 | @@ -2708,6 +2993,13 @@ XML_GetFeatureList(void) { | ||
| 474 | EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT}, | ||
| 475 | /* Added in Expat 2.6.0. */ | ||
| 476 | {XML_FEATURE_GE, XML_L("XML_GE"), 0}, | ||
| 477 | + /* Added in Expat 2.7.2. */ | ||
| 478 | + {XML_FEATURE_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT, | ||
| 479 | + XML_L("XML_AT_MAX_AMP"), | ||
| 480 | + (long int)EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT}, | ||
| 481 | + {XML_FEATURE_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT, | ||
| 482 | + XML_L("XML_AT_ACT_THRES"), | ||
| 483 | + (long int)EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT}, | ||
| 484 | #endif | ||
| 485 | {XML_FEATURE_END, NULL, 0}}; | ||
| 486 | |||
| 487 | @@ -2736,6 +3028,29 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( | ||
| 488 | parser->m_accounting.activationThresholdBytes = activationThresholdBytes; | ||
| 489 | return XML_TRUE; | ||
| 490 | } | ||
| 491 | + | ||
| 492 | +XML_Bool XMLCALL | ||
| 493 | +XML_SetAllocTrackerMaximumAmplification(XML_Parser parser, | ||
| 494 | + float maximumAmplificationFactor) { | ||
| 495 | + if ((parser == NULL) || (parser->m_parentParser != NULL) | ||
| 496 | + || isnan(maximumAmplificationFactor) | ||
| 497 | + || (maximumAmplificationFactor < 1.0f)) { | ||
| 498 | + return XML_FALSE; | ||
| 499 | + } | ||
| 500 | + parser->m_alloc_tracker.maximumAmplificationFactor | ||
| 501 | + = maximumAmplificationFactor; | ||
| 502 | + return XML_TRUE; | ||
| 503 | +} | ||
| 504 | + | ||
| 505 | +XML_Bool XMLCALL | ||
| 506 | +XML_SetAllocTrackerActivationThreshold( | ||
| 507 | + XML_Parser parser, unsigned long long activationThresholdBytes) { | ||
| 508 | + if ((parser == NULL) || (parser->m_parentParser != NULL)) { | ||
| 509 | + return XML_FALSE; | ||
| 510 | + } | ||
| 511 | + parser->m_alloc_tracker.activationThresholdBytes = activationThresholdBytes; | ||
| 512 | + return XML_TRUE; | ||
| 513 | +} | ||
| 514 | #endif /* XML_GE == 1 */ | ||
| 515 | |||
| 516 | XML_Bool XMLCALL | ||
| 517 | diff --git a/tests/basic_tests.c b/tests/basic_tests.c | ||
| 518 | index 129db1d8..0231e094 100644 | ||
| 519 | --- a/tests/basic_tests.c | ||
| 520 | +++ b/tests/basic_tests.c | ||
| 521 | @@ -3089,6 +3089,10 @@ START_TEST(test_buffer_can_grow_to_max) { | ||
| 522 | for (int i = 0; i < num_prefixes; ++i) { | ||
| 523 | set_subtest("\"%s\"", prefixes[i]); | ||
| 524 | XML_Parser parser = XML_ParserCreate(NULL); | ||
| 525 | +#if XML_GE == 1 | ||
| 526 | + assert_true(XML_SetAllocTrackerActivationThreshold(parser, (size_t)-1) | ||
| 527 | + == XML_TRUE); // i.e. deactivate | ||
| 528 | +#endif | ||
| 529 | const int prefix_len = (int)strlen(prefixes[i]); | ||
| 530 | const enum XML_Status s | ||
| 531 | = _XML_Parse_SINGLE_BYTES(parser, prefixes[i], prefix_len, XML_FALSE); | ||
| 532 | diff --git a/tests/nsalloc_tests.c b/tests/nsalloc_tests.c | ||
| 533 | index 48520f42..0a594e14 100644 | ||
| 534 | --- a/tests/nsalloc_tests.c | ||
| 535 | +++ b/tests/nsalloc_tests.c | ||
| 536 | @@ -454,10 +454,15 @@ START_TEST(test_nsalloc_realloc_attributes) { | ||
| 537 | nsalloc_teardown(); | ||
| 538 | nsalloc_setup(); | ||
| 539 | } | ||
| 540 | +#if XML_GE == 1 | ||
| 541 | + assert_true( | ||
| 542 | + i == 0); // because expat_realloc relies on expat_malloc to some extent | ||
| 543 | +#else | ||
| 544 | if (i == 0) | ||
| 545 | fail("Parsing worked despite failing reallocations"); | ||
| 546 | else if (i == max_realloc_count) | ||
| 547 | fail("Parsing failed at max reallocation count"); | ||
| 548 | +#endif | ||
| 549 | } | ||
| 550 | END_TEST | ||
| 551 | |||
| 552 | diff --git a/xmlwf/xmlwf.c b/xmlwf/xmlwf.c | ||
| 553 | index 8cfc73ca..b9d0a7fc 100644 | ||
| 554 | --- a/xmlwf/xmlwf.c | ||
| 555 | +++ b/xmlwf/xmlwf.c | ||
| 556 | @@ -933,6 +933,8 @@ usage(const XML_Char *prog, int rc) { | ||
| 557 | T(" Control verbosity of entity debugging (default: 0)\n") | ||
| 558 | T(" EXPAT_ENTROPY_DEBUG=(0|1)\n") | ||
| 559 | T(" Control verbosity of entropy debugging (default: 0)\n") | ||
| 560 | + T(" EXPAT_MALLOC_DEBUG=(0|1|2)\n") | ||
| 561 | + T(" Control verbosity of allocation tracker (default: 0)\n") | ||
| 562 | T("\n") | ||
| 563 | T("exit status:\n") | ||
| 564 | T(" 0 the input files are well-formed and the output (if requested) was written successfully\n") | ||
| 565 | diff --git a/xmlwf/xmlwf_helpgen.py b/xmlwf/xmlwf_helpgen.py | ||
| 566 | index 39a3dc13..2360820d 100755 | ||
| 567 | --- a/xmlwf/xmlwf_helpgen.py | ||
| 568 | +++ b/xmlwf/xmlwf_helpgen.py | ||
| 569 | @@ -39,6 +39,8 @@ environment variables: | ||
| 570 | Control verbosity of entity debugging (default: 0) | ||
| 571 | EXPAT_ENTROPY_DEBUG=(0|1) | ||
| 572 | Control verbosity of entropy debugging (default: 0) | ||
| 573 | + EXPAT_MALLOC_DEBUG=(0|1|2) | ||
| 574 | + Control verbosity of allocation tracker (default: 0) | ||
| 575 | |||
| 576 | exit status: | ||
| 577 | 0 the input files are well-formed and the output (if requested) was written successfully | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-09.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-09.patch new file mode 100644 index 0000000000..364c28183a --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-09.patch | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | From 1270e5bc0836d296ac4970fc9e1cf53d83972083 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Sun, 7 Sep 2025 12:18:08 +0200 | ||
| 4 | Subject: [PATCH] lib: Make XML_MemFree and XML_FreeContentModel match their | ||
| 5 | siblings | ||
| 6 | |||
| 7 | .. XML_MemMalloc and XML_MemRealloc in structure, prior to upcoming changes | ||
| 8 | |||
| 9 | CVE: CVE-2025-59375 | ||
| 10 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/1270e5bc0836d296ac4970fc9e1cf53d83972083] | ||
| 11 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 12 | --- | ||
| 13 | lib/xmlparse.c | 10 ++++++---- | ||
| 14 | 1 file changed, 6 insertions(+), 4 deletions(-) | ||
| 15 | |||
| 16 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 17 | index fcf1cfdd..5d27cd45 100644 | ||
| 18 | --- a/lib/xmlparse.c | ||
| 19 | +++ b/lib/xmlparse.c | ||
| 20 | @@ -2772,8 +2772,9 @@ XML_GetCurrentColumnNumber(XML_Parser parser) { | ||
| 21 | |||
| 22 | void XMLCALL | ||
| 23 | XML_FreeContentModel(XML_Parser parser, XML_Content *model) { | ||
| 24 | - if (parser != NULL) | ||
| 25 | - FREE(parser, model); | ||
| 26 | + if (parser == NULL) | ||
| 27 | + return; | ||
| 28 | + FREE(parser, model); | ||
| 29 | } | ||
| 30 | |||
| 31 | void *XMLCALL | ||
| 32 | @@ -2792,8 +2793,9 @@ XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) { | ||
| 33 | |||
| 34 | void XMLCALL | ||
| 35 | XML_MemFree(XML_Parser parser, void *ptr) { | ||
| 36 | - if (parser != NULL) | ||
| 37 | - FREE(parser, ptr); | ||
| 38 | + if (parser == NULL) | ||
| 39 | + return; | ||
| 40 | + FREE(parser, ptr); | ||
| 41 | } | ||
| 42 | |||
| 43 | void XMLCALL | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-10.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-10.patch new file mode 100644 index 0000000000..fe5452000e --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-10.patch | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | From 96c7467281c72028aada525c1d3822512758b266 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Sun, 7 Sep 2025 12:06:43 +0200 | ||
| 4 | Subject: [PATCH] lib: Exclude XML_Mem* functions from allocation tracking | ||
| 5 | |||
| 6 | .. so that allocations by the user application | ||
| 7 | are not being limited. | ||
| 8 | |||
| 9 | CVE: CVE-2025-59375 | ||
| 10 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/96c7467281c72028aada525c1d3822512758b266] | ||
| 11 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 12 | --- | ||
| 13 | lib/xmlparse.c | 16 +++++++++++++--- | ||
| 14 | 1 file changed, 13 insertions(+), 3 deletions(-) | ||
| 15 | |||
| 16 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 17 | index 5d27cd45..8145a049 100644 | ||
| 18 | --- a/lib/xmlparse.c | ||
| 19 | +++ b/lib/xmlparse.c | ||
| 20 | @@ -2781,21 +2781,31 @@ void *XMLCALL | ||
| 21 | XML_MemMalloc(XML_Parser parser, size_t size) { | ||
| 22 | if (parser == NULL) | ||
| 23 | return NULL; | ||
| 24 | - return MALLOC(parser, size); | ||
| 25 | + | ||
| 26 | + // NOTE: We are avoiding MALLOC(..) here to not include | ||
| 27 | + // user allocations with allocation tracking and limiting. | ||
| 28 | + return parser->m_mem.malloc_fcn(size); | ||
| 29 | } | ||
| 30 | |||
| 31 | void *XMLCALL | ||
| 32 | XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) { | ||
| 33 | if (parser == NULL) | ||
| 34 | return NULL; | ||
| 35 | - return REALLOC(parser, ptr, size); | ||
| 36 | + | ||
| 37 | + // NOTE: We are avoiding REALLOC(..) here to not include | ||
| 38 | + // user allocations with allocation tracking and limiting. | ||
| 39 | + return parser->m_mem.realloc_fcn(ptr, size); | ||
| 40 | } | ||
| 41 | |||
| 42 | void XMLCALL | ||
| 43 | XML_MemFree(XML_Parser parser, void *ptr) { | ||
| 44 | if (parser == NULL) | ||
| 45 | return; | ||
| 46 | - FREE(parser, ptr); | ||
| 47 | + | ||
| 48 | + // NOTE: We are avoiding FREE(..) here because XML_MemMalloc and | ||
| 49 | + // XML_MemRealloc are not using MALLOC(..) and REALLOC(..) | ||
| 50 | + // but plain .malloc_fcn(..) and .realloc_fcn(..), internally. | ||
| 51 | + parser->m_mem.free_fcn(ptr); | ||
| 52 | } | ||
| 53 | |||
| 54 | void XMLCALL | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-11.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-11.patch new file mode 100644 index 0000000000..be892a7804 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-11.patch | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | From ae4086198d710a62a0a1560007b81307dba72909 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Tue, 9 Sep 2025 21:34:28 +0200 | ||
| 4 | Subject: [PATCH] lib: Exclude the main input buffer from allocation tracking | ||
| 5 | |||
| 6 | .. so that control of the input buffer size remains with the | ||
| 7 | application using Expat | ||
| 8 | |||
| 9 | CVE: CVE-2025-59375 | ||
| 10 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/ae4086198d710a62a0a1560007b81307dba72909] | ||
| 11 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 12 | --- | ||
| 13 | lib/xmlparse.c | 19 +++++++++++++++---- | ||
| 14 | 1 file changed, 15 insertions(+), 4 deletions(-) | ||
| 15 | |||
| 16 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 17 | index 8145a049..00139b94 100644 | ||
| 18 | --- a/lib/xmlparse.c | ||
| 19 | +++ b/lib/xmlparse.c | ||
| 20 | @@ -1975,7 +1975,10 @@ XML_ParserFree(XML_Parser parser) { | ||
| 21 | FREE(parser, (void *)parser->m_attInfo); | ||
| 22 | #endif | ||
| 23 | FREE(parser, parser->m_groupConnector); | ||
| 24 | - FREE(parser, parser->m_buffer); | ||
| 25 | + // NOTE: We are avoiding FREE(..) here because parser->m_buffer | ||
| 26 | + // is not being allocated with MALLOC(..) but with plain | ||
| 27 | + // .malloc_fcn(..). | ||
| 28 | + parser->m_mem.free_fcn(parser->m_buffer); | ||
| 29 | FREE(parser, parser->m_dataBuf); | ||
| 30 | FREE(parser, parser->m_nsAtts); | ||
| 31 | FREE(parser, parser->m_unknownEncodingMem); | ||
| 32 | @@ -2567,7 +2570,9 @@ XML_GetBuffer(XML_Parser parser, int len) { | ||
| 33 | parser->m_errorCode = XML_ERROR_NO_MEMORY; | ||
| 34 | return NULL; | ||
| 35 | } | ||
| 36 | - newBuf = (char *)MALLOC(parser, bufferSize); | ||
| 37 | + // NOTE: We are avoiding MALLOC(..) here to leave limiting | ||
| 38 | + // the input size to the application using Expat. | ||
| 39 | + newBuf = (char *)parser->m_mem.malloc_fcn(bufferSize); | ||
| 40 | if (newBuf == 0) { | ||
| 41 | parser->m_errorCode = XML_ERROR_NO_MEMORY; | ||
| 42 | return NULL; | ||
| 43 | @@ -2578,7 +2583,10 @@ XML_GetBuffer(XML_Parser parser, int len) { | ||
| 44 | memcpy(newBuf, &parser->m_bufferPtr[-keep], | ||
| 45 | EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr) | ||
| 46 | + keep); | ||
| 47 | - FREE(parser, parser->m_buffer); | ||
| 48 | + // NOTE: We are avoiding FREE(..) here because parser->m_buffer | ||
| 49 | + // is not being allocated with MALLOC(..) but with plain | ||
| 50 | + // .malloc_fcn(..). | ||
| 51 | + parser->m_mem.free_fcn(parser->m_buffer); | ||
| 52 | parser->m_buffer = newBuf; | ||
| 53 | parser->m_bufferEnd | ||
| 54 | = parser->m_buffer | ||
| 55 | @@ -2594,7 +2602,10 @@ XML_GetBuffer(XML_Parser parser, int len) { | ||
| 56 | if (parser->m_bufferPtr) { | ||
| 57 | memcpy(newBuf, parser->m_bufferPtr, | ||
| 58 | EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)); | ||
| 59 | - FREE(parser, parser->m_buffer); | ||
| 60 | + // NOTE: We are avoiding FREE(..) here because parser->m_buffer | ||
| 61 | + // is not being allocated with MALLOC(..) but with plain | ||
| 62 | + // .malloc_fcn(..). | ||
| 63 | + parser->m_mem.free_fcn(parser->m_buffer); | ||
| 64 | parser->m_bufferEnd | ||
| 65 | = newBuf | ||
| 66 | + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr); | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-12.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-12.patch new file mode 100644 index 0000000000..9e036a5284 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-12.patch | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | From 7e35240dc97e9fd4f609e31f27c27b659535e436 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Thu, 11 Sep 2025 00:27:05 +0200 | ||
| 4 | Subject: [PATCH] lib: Exclude the content model from allocation tracking | ||
| 5 | |||
| 6 | .. so that applications that are not using XML_FreeContentModel | ||
| 7 | but plain free(..) or .free_fcn() to free the content model's | ||
| 8 | memory are safe | ||
| 9 | |||
| 10 | CVE: CVE-2025-59375 | ||
| 11 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/7e35240dc97e9fd4f609e31f27c27b659535e436] | ||
| 12 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 13 | --- | ||
| 14 | lib/xmlparse.c | 16 +++++++++++++--- | ||
| 15 | 1 file changed, 13 insertions(+), 3 deletions(-) | ||
| 16 | |||
| 17 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 18 | index 00139b94..d0b6e0cd 100644 | ||
| 19 | --- a/lib/xmlparse.c | ||
| 20 | +++ b/lib/xmlparse.c | ||
| 21 | @@ -2785,7 +2785,10 @@ void XMLCALL | ||
| 22 | XML_FreeContentModel(XML_Parser parser, XML_Content *model) { | ||
| 23 | if (parser == NULL) | ||
| 24 | return; | ||
| 25 | - FREE(parser, model); | ||
| 26 | + | ||
| 27 | + // NOTE: We are avoiding FREE(..) here because the content model | ||
| 28 | + // has been created using plain .malloc_fcn(..) rather than MALLOC(..). | ||
| 29 | + parser->m_mem.free_fcn(model); | ||
| 30 | } | ||
| 31 | |||
| 32 | void *XMLCALL | ||
| 33 | @@ -6063,8 +6066,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, | ||
| 34 | case XML_ROLE_CONTENT_EMPTY: | ||
| 35 | if (dtd->in_eldecl) { | ||
| 36 | if (parser->m_elementDeclHandler) { | ||
| 37 | + // NOTE: We are avoiding MALLOC(..) here to so that | ||
| 38 | + // applications that are not using XML_FreeContentModel but | ||
| 39 | + // plain free(..) or .free_fcn() to free the content model's | ||
| 40 | + // memory are safe. | ||
| 41 | XML_Content *content | ||
| 42 | - = (XML_Content *)MALLOC(parser, sizeof(XML_Content)); | ||
| 43 | + = (XML_Content *)parser->m_mem.malloc_fcn(sizeof(XML_Content)); | ||
| 44 | if (! content) | ||
| 45 | return XML_ERROR_NO_MEMORY; | ||
| 46 | content->quant = XML_CQUANT_NONE; | ||
| 47 | @@ -8278,7 +8285,10 @@ build_model(XML_Parser parser) { | ||
| 48 | const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content) | ||
| 49 | + (dtd->contentStringLen * sizeof(XML_Char))); | ||
| 50 | |||
| 51 | - ret = (XML_Content *)MALLOC(parser, allocsize); | ||
| 52 | + // NOTE: We are avoiding MALLOC(..) here to so that | ||
| 53 | + // applications that are not using XML_FreeContentModel but plain | ||
| 54 | + // free(..) or .free_fcn() to free the content model's memory are safe. | ||
| 55 | + ret = (XML_Content *)parser->m_mem.malloc_fcn(allocsize); | ||
| 56 | if (! ret) | ||
| 57 | return NULL; | ||
| 58 | |||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-13.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-13.patch new file mode 100644 index 0000000000..209dd83a4b --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-13.patch | |||
| @@ -0,0 +1,309 @@ | |||
| 1 | From 31f9053c3c46741f4daf2ea2bdea75f40f720d42 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Tue, 2 Sep 2025 22:36:49 +0200 | ||
| 4 | Subject: [PATCH] tests: Cover allocation tracking and limiting with tests | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/31f9053c3c46741f4daf2ea2bdea75f40f720d42] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | lib/internal.h | 3 + | ||
| 11 | lib/xmlparse.c | 12 +++ | ||
| 12 | tests/alloc_tests.c | 214 ++++++++++++++++++++++++++++++++++++++++++++ | ||
| 13 | 3 files changed, 229 insertions(+) | ||
| 14 | |||
| 15 | diff --git a/lib/internal.h b/lib/internal.h | ||
| 16 | index eb67cf50..6e087858 100644 | ||
| 17 | --- a/lib/internal.h | ||
| 18 | +++ b/lib/internal.h | ||
| 19 | @@ -173,6 +173,9 @@ extern | ||
| 20 | #endif | ||
| 21 | XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c | ||
| 22 | #if defined(XML_TESTING) | ||
| 23 | +void *expat_malloc(XML_Parser parser, size_t size, int sourceLine); | ||
| 24 | +void expat_free(XML_Parser parser, void *ptr, int sourceLine); | ||
| 25 | +void *expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine); | ||
| 26 | extern unsigned int g_bytesScanned; // used for testing only | ||
| 27 | #endif | ||
| 28 | |||
| 29 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 30 | index d0b6e0cd..6e9c6fb2 100644 | ||
| 31 | --- a/lib/xmlparse.c | ||
| 32 | +++ b/lib/xmlparse.c | ||
| 33 | @@ -843,7 +843,11 @@ expat_heap_increase_tolerable(XML_Parser rootParser, XmlBigCount increase, | ||
| 34 | return tolerable; | ||
| 35 | } | ||
| 36 | |||
| 37 | +# if defined(XML_TESTING) | ||
| 38 | +void * | ||
| 39 | +# else | ||
| 40 | static void * | ||
| 41 | +# endif | ||
| 42 | expat_malloc(XML_Parser parser, size_t size, int sourceLine) { | ||
| 43 | // Detect integer overflow | ||
| 44 | if (SIZE_MAX - size < sizeof(size_t)) { | ||
| 45 | @@ -893,7 +897,11 @@ expat_malloc(XML_Parser parser, size_t size, int sourceLine) { | ||
| 46 | return (char *)mallocedPtr + sizeof(size_t); | ||
| 47 | } | ||
| 48 | |||
| 49 | +# if defined(XML_TESTING) | ||
| 50 | +void | ||
| 51 | +# else | ||
| 52 | static void | ||
| 53 | +# endif | ||
| 54 | expat_free(XML_Parser parser, void *ptr, int sourceLine) { | ||
| 55 | assert(parser != NULL); | ||
| 56 | |||
| 57 | @@ -924,7 +932,11 @@ expat_free(XML_Parser parser, void *ptr, int sourceLine) { | ||
| 58 | parser->m_mem.free_fcn(mallocedPtr); | ||
| 59 | } | ||
| 60 | |||
| 61 | +# if defined(XML_TESTING) | ||
| 62 | +void * | ||
| 63 | +# else | ||
| 64 | static void * | ||
| 65 | +# endif | ||
| 66 | expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { | ||
| 67 | assert(parser != NULL); | ||
| 68 | |||
| 69 | diff --git a/tests/alloc_tests.c b/tests/alloc_tests.c | ||
| 70 | index 4c3e2af4..275f92d5 100644 | ||
| 71 | --- a/tests/alloc_tests.c | ||
| 72 | +++ b/tests/alloc_tests.c | ||
| 73 | @@ -46,10 +46,16 @@ | ||
| 74 | # undef NDEBUG /* because test suite relies on assert(...) at the moment */ | ||
| 75 | #endif | ||
| 76 | |||
| 77 | +#include <math.h> /* NAN, INFINITY */ | ||
| 78 | +#include <stdbool.h> | ||
| 79 | +#include <stdint.h> /* for SIZE_MAX */ | ||
| 80 | #include <string.h> | ||
| 81 | #include <assert.h> | ||
| 82 | |||
| 83 | +#include "expat_config.h" | ||
| 84 | + | ||
| 85 | #include "expat.h" | ||
| 86 | +#include "internal.h" | ||
| 87 | #include "common.h" | ||
| 88 | #include "minicheck.h" | ||
| 89 | #include "dummy.h" | ||
| 90 | @@ -2085,6 +2091,203 @@ START_TEST(test_alloc_reset_after_external_entity_parser_create_fail) { | ||
| 91 | } | ||
| 92 | END_TEST | ||
| 93 | |||
| 94 | +START_TEST(test_alloc_tracker_size_recorded) { | ||
| 95 | + XML_Memory_Handling_Suite memsuite = {malloc, realloc, free}; | ||
| 96 | + | ||
| 97 | + bool values[] = {true, false}; | ||
| 98 | + for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) { | ||
| 99 | + const bool useMemSuite = values[i]; | ||
| 100 | + set_subtest("useMemSuite=%d", (int)useMemSuite); | ||
| 101 | + XML_Parser parser = useMemSuite | ||
| 102 | + ? XML_ParserCreate_MM(NULL, &memsuite, XCS("|")) | ||
| 103 | + : XML_ParserCreate(NULL); | ||
| 104 | + | ||
| 105 | +#if XML_GE == 1 | ||
| 106 | + void *ptr = expat_malloc(parser, 10, -1); | ||
| 107 | + | ||
| 108 | + assert_true(ptr != NULL); | ||
| 109 | + assert_true(*((size_t *)ptr - 1) == 10); | ||
| 110 | + | ||
| 111 | + assert_true(expat_realloc(parser, ptr, SIZE_MAX / 2, -1) == NULL); | ||
| 112 | + | ||
| 113 | + assert_true(*((size_t *)ptr - 1) == 10); // i.e. unchanged | ||
| 114 | + | ||
| 115 | + ptr = expat_realloc(parser, ptr, 20, -1); | ||
| 116 | + | ||
| 117 | + assert_true(ptr != NULL); | ||
| 118 | + assert_true(*((size_t *)ptr - 1) == 20); | ||
| 119 | + | ||
| 120 | + expat_free(parser, ptr, -1); | ||
| 121 | +#endif | ||
| 122 | + | ||
| 123 | + XML_ParserFree(parser); | ||
| 124 | + } | ||
| 125 | +} | ||
| 126 | +END_TEST | ||
| 127 | + | ||
| 128 | +START_TEST(test_alloc_tracker_maximum_amplification) { | ||
| 129 | + if (g_reparseDeferralEnabledDefault == XML_TRUE) { | ||
| 130 | + return; | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + XML_Parser parser = XML_ParserCreate(NULL); | ||
| 134 | + | ||
| 135 | + // Get .m_accounting.countBytesDirect from 0 to 3 | ||
| 136 | + const char *const chunk = "<e>"; | ||
| 137 | + assert_true(_XML_Parse_SINGLE_BYTES(parser, chunk, (int)strlen(chunk), | ||
| 138 | + /*isFinal=*/XML_FALSE) | ||
| 139 | + == XML_STATUS_OK); | ||
| 140 | + | ||
| 141 | +#if XML_GE == 1 | ||
| 142 | + // Stop activation threshold from interfering | ||
| 143 | + assert_true(XML_SetAllocTrackerActivationThreshold(parser, 0) == XML_TRUE); | ||
| 144 | + | ||
| 145 | + // Exceed maximum amplification: should be rejected. | ||
| 146 | + assert_true(expat_malloc(parser, 1000, -1) == NULL); | ||
| 147 | + | ||
| 148 | + // Increase maximum amplification, and try the same amount once more: should | ||
| 149 | + // work. | ||
| 150 | + assert_true(XML_SetAllocTrackerMaximumAmplification(parser, 3000.0f) | ||
| 151 | + == XML_TRUE); | ||
| 152 | + | ||
| 153 | + void *const ptr = expat_malloc(parser, 1000, -1); | ||
| 154 | + assert_true(ptr != NULL); | ||
| 155 | + expat_free(parser, ptr, -1); | ||
| 156 | +#endif | ||
| 157 | + | ||
| 158 | + XML_ParserFree(parser); | ||
| 159 | +} | ||
| 160 | +END_TEST | ||
| 161 | + | ||
| 162 | +START_TEST(test_alloc_tracker_threshold) { | ||
| 163 | + XML_Parser parser = XML_ParserCreate(NULL); | ||
| 164 | + | ||
| 165 | +#if XML_GE == 1 | ||
| 166 | + // Exceed maximum amplification *before* (default) threshold: should work. | ||
| 167 | + void *const ptr = expat_malloc(parser, 1000, -1); | ||
| 168 | + assert_true(ptr != NULL); | ||
| 169 | + expat_free(parser, ptr, -1); | ||
| 170 | + | ||
| 171 | + // Exceed maximum amplification *after* threshold: should be rejected. | ||
| 172 | + assert_true(XML_SetAllocTrackerActivationThreshold(parser, 999) == XML_TRUE); | ||
| 173 | + assert_true(expat_malloc(parser, 1000, -1) == NULL); | ||
| 174 | +#endif | ||
| 175 | + | ||
| 176 | + XML_ParserFree(parser); | ||
| 177 | +} | ||
| 178 | +END_TEST | ||
| 179 | + | ||
| 180 | +START_TEST(test_alloc_tracker_getbuffer_unlimited) { | ||
| 181 | + XML_Parser parser = XML_ParserCreate(NULL); | ||
| 182 | + | ||
| 183 | +#if XML_GE == 1 | ||
| 184 | + // Artificially lower threshold | ||
| 185 | + assert_true(XML_SetAllocTrackerActivationThreshold(parser, 0) == XML_TRUE); | ||
| 186 | + | ||
| 187 | + // Self-test: Prove that threshold is as rejecting as expected | ||
| 188 | + assert_true(expat_malloc(parser, 1000, -1) == NULL); | ||
| 189 | +#endif | ||
| 190 | + // XML_GetBuffer should be allowed to pass, though | ||
| 191 | + assert_true(XML_GetBuffer(parser, 1000) != NULL); | ||
| 192 | + | ||
| 193 | + XML_ParserFree(parser); | ||
| 194 | +} | ||
| 195 | +END_TEST | ||
| 196 | + | ||
| 197 | +START_TEST(test_alloc_tracker_api) { | ||
| 198 | + XML_Parser parserWithoutParent = XML_ParserCreate(NULL); | ||
| 199 | + XML_Parser parserWithParent = XML_ExternalEntityParserCreate( | ||
| 200 | + parserWithoutParent, XCS("entity123"), NULL); | ||
| 201 | + if (parserWithoutParent == NULL) | ||
| 202 | + fail("parserWithoutParent is NULL"); | ||
| 203 | + if (parserWithParent == NULL) | ||
| 204 | + fail("parserWithParent is NULL"); | ||
| 205 | + | ||
| 206 | +#if XML_GE == 1 | ||
| 207 | + // XML_SetAllocTrackerMaximumAmplification, error cases | ||
| 208 | + if (XML_SetAllocTrackerMaximumAmplification(NULL, 123.0f) == XML_TRUE) | ||
| 209 | + fail("Call with NULL parser is NOT supposed to succeed"); | ||
| 210 | + if (XML_SetAllocTrackerMaximumAmplification(parserWithParent, 123.0f) | ||
| 211 | + == XML_TRUE) | ||
| 212 | + fail("Call with non-root parser is NOT supposed to succeed"); | ||
| 213 | + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, NAN) | ||
| 214 | + == XML_TRUE) | ||
| 215 | + fail("Call with NaN limit is NOT supposed to succeed"); | ||
| 216 | + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, -1.0f) | ||
| 217 | + == XML_TRUE) | ||
| 218 | + fail("Call with negative limit is NOT supposed to succeed"); | ||
| 219 | + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, 0.9f) | ||
| 220 | + == XML_TRUE) | ||
| 221 | + fail("Call with positive limit <1.0 is NOT supposed to succeed"); | ||
| 222 | + | ||
| 223 | + // XML_SetAllocTrackerMaximumAmplification, success cases | ||
| 224 | + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, 1.0f) | ||
| 225 | + == XML_FALSE) | ||
| 226 | + fail("Call with positive limit >=1.0 is supposed to succeed"); | ||
| 227 | + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, 123456.789f) | ||
| 228 | + == XML_FALSE) | ||
| 229 | + fail("Call with positive limit >=1.0 is supposed to succeed"); | ||
| 230 | + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, INFINITY) | ||
| 231 | + == XML_FALSE) | ||
| 232 | + fail("Call with positive limit >=1.0 is supposed to succeed"); | ||
| 233 | + | ||
| 234 | + // XML_SetAllocTrackerActivationThreshold, error cases | ||
| 235 | + if (XML_SetAllocTrackerActivationThreshold(NULL, 123) == XML_TRUE) | ||
| 236 | + fail("Call with NULL parser is NOT supposed to succeed"); | ||
| 237 | + if (XML_SetAllocTrackerActivationThreshold(parserWithParent, 123) == XML_TRUE) | ||
| 238 | + fail("Call with non-root parser is NOT supposed to succeed"); | ||
| 239 | + | ||
| 240 | + // XML_SetAllocTrackerActivationThreshold, success cases | ||
| 241 | + if (XML_SetAllocTrackerActivationThreshold(parserWithoutParent, 123) | ||
| 242 | + == XML_FALSE) | ||
| 243 | + fail("Call with non-NULL parentless parser is supposed to succeed"); | ||
| 244 | +#endif // XML_GE == 1 | ||
| 245 | + | ||
| 246 | + XML_ParserFree(parserWithParent); | ||
| 247 | + XML_ParserFree(parserWithoutParent); | ||
| 248 | +} | ||
| 249 | +END_TEST | ||
| 250 | + | ||
| 251 | +START_TEST(test_mem_api_cycle) { | ||
| 252 | + XML_Parser parser = XML_ParserCreate(NULL); | ||
| 253 | + | ||
| 254 | + void *ptr = XML_MemMalloc(parser, 10); | ||
| 255 | + | ||
| 256 | + assert_true(ptr != NULL); | ||
| 257 | + memset(ptr, 'x', 10); // assert writability, with ASan in mind | ||
| 258 | + | ||
| 259 | + ptr = XML_MemRealloc(parser, ptr, 20); | ||
| 260 | + | ||
| 261 | + assert_true(ptr != NULL); | ||
| 262 | + memset(ptr, 'y', 20); // assert writability, with ASan in mind | ||
| 263 | + | ||
| 264 | + XML_MemFree(parser, ptr); | ||
| 265 | + | ||
| 266 | + XML_ParserFree(parser); | ||
| 267 | +} | ||
| 268 | +END_TEST | ||
| 269 | + | ||
| 270 | +START_TEST(test_mem_api_unlimited) { | ||
| 271 | + XML_Parser parser = XML_ParserCreate(NULL); | ||
| 272 | + | ||
| 273 | +#if XML_GE == 1 | ||
| 274 | + assert_true(XML_SetAllocTrackerActivationThreshold(parser, 0) == XML_TRUE); | ||
| 275 | +#endif | ||
| 276 | + | ||
| 277 | + void *ptr = XML_MemMalloc(parser, 1000); | ||
| 278 | + | ||
| 279 | + assert_true(ptr != NULL); | ||
| 280 | + | ||
| 281 | + ptr = XML_MemRealloc(parser, ptr, 2000); | ||
| 282 | + | ||
| 283 | + assert_true(ptr != NULL); | ||
| 284 | + | ||
| 285 | + XML_MemFree(parser, ptr); | ||
| 286 | + | ||
| 287 | + XML_ParserFree(parser); | ||
| 288 | +} | ||
| 289 | +END_TEST | ||
| 290 | + | ||
| 291 | void | ||
| 292 | make_alloc_test_case(Suite *s) { | ||
| 293 | TCase *tc_alloc = tcase_create("allocation tests"); | ||
| 294 | @@ -2151,4 +2354,15 @@ make_alloc_test_case(Suite *s) { | ||
| 295 | |||
| 296 | tcase_add_test__ifdef_xml_dtd( | ||
| 297 | tc_alloc, test_alloc_reset_after_external_entity_parser_create_fail); | ||
| 298 | + | ||
| 299 | + tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_size_recorded); | ||
| 300 | + tcase_add_test__ifdef_xml_dtd(tc_alloc, | ||
| 301 | + test_alloc_tracker_maximum_amplification); | ||
| 302 | + tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_threshold); | ||
| 303 | + tcase_add_test__ifdef_xml_dtd(tc_alloc, | ||
| 304 | + test_alloc_tracker_getbuffer_unlimited); | ||
| 305 | + tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_api); | ||
| 306 | + | ||
| 307 | + tcase_add_test(tc_alloc, test_mem_api_cycle); | ||
| 308 | + tcase_add_test__ifdef_xml_dtd(tc_alloc, test_mem_api_unlimited); | ||
| 309 | } | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-14.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-14.patch new file mode 100644 index 0000000000..a339cc3f4b --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-14.patch | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | From 78366891a586f293aeff60a14a55e4afe1169586 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Tue, 2 Sep 2025 16:44:00 +0200 | ||
| 4 | Subject: [PATCH] xmlwf: Wire allocation tracker config to existing arguments | ||
| 5 | -a and -b | ||
| 6 | |||
| 7 | CVE: CVE-2025-59375 | ||
| 8 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/78366891a586f293aeff60a14a55e4afe1169586] | ||
| 9 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 10 | --- | ||
| 11 | doc/xmlwf.xml | 26 ++++++++++++++++++++------ | ||
| 12 | xmlwf/xmlwf.c | 7 +++++-- | ||
| 13 | xmlwf/xmlwf_helpgen.py | 4 ++-- | ||
| 14 | 3 files changed, 27 insertions(+), 10 deletions(-) | ||
| 15 | |||
| 16 | diff --git a/doc/xmlwf.xml b/doc/xmlwf.xml | ||
| 17 | index 17e9cf51..65d8ae9b 100644 | ||
| 18 | --- a/doc/xmlwf.xml | ||
| 19 | +++ b/doc/xmlwf.xml | ||
| 20 | @@ -158,19 +158,31 @@ supports both. | ||
| 21 | <listitem> | ||
| 22 | <para> | ||
| 23 | Sets the maximum tolerated amplification factor | ||
| 24 | - for protection against billion laughs attacks (default: 100.0). | ||
| 25 | + for protection against amplification attacks | ||
| 26 | + like the billion laughs attack | ||
| 27 | + (default: 100.0 | ||
| 28 | + for the sum of direct and indirect output and also | ||
| 29 | + for allocations of dynamic memory). | ||
| 30 | The amplification factor is calculated as .. | ||
| 31 | </para> | ||
| 32 | <literallayout> | ||
| 33 | amplification := (direct + indirect) / direct | ||
| 34 | </literallayout> | ||
| 35 | <para> | ||
| 36 | - .. while parsing, whereas | ||
| 37 | + .. with regard to use of entities and .. | ||
| 38 | + </para> | ||
| 39 | + <literallayout> | ||
| 40 | + amplification := allocated / direct | ||
| 41 | + </literallayout> | ||
| 42 | + <para> | ||
| 43 | + .. with regard to dynamic memory while parsing. | ||
| 44 | <direct> is the number of bytes read | ||
| 45 | - from the primary document in parsing and | ||
| 46 | + from the primary document in parsing, | ||
| 47 | <indirect> is the number of bytes | ||
| 48 | added by expanding entities and reading of external DTD files, | ||
| 49 | - combined. | ||
| 50 | + combined, and | ||
| 51 | + <allocated> is the total number of bytes of dynamic memory | ||
| 52 | + allocated (and not freed) per hierarchy of parsers. | ||
| 53 | </para> | ||
| 54 | <para> | ||
| 55 | <emphasis>NOTE</emphasis>: | ||
| 56 | @@ -185,8 +197,10 @@ supports both. | ||
| 57 | <listitem> | ||
| 58 | <para> | ||
| 59 | Sets the number of output bytes (including amplification) | ||
| 60 | - needed to activate protection against billion laughs attacks | ||
| 61 | - (default: 8 MiB). | ||
| 62 | + needed to activate protection against amplification attacks | ||
| 63 | + like billion laughs | ||
| 64 | + (default: 8 MiB for the sum of direct and indirect output, | ||
| 65 | + and 64 MiB for allocations of dynamic memory). | ||
| 66 | This can be thought of as an "activation threshold". | ||
| 67 | </para> | ||
| 68 | <para> | ||
| 69 | diff --git a/xmlwf/xmlwf.c b/xmlwf/xmlwf.c | ||
| 70 | index b9d0a7fc..14206d9e 100644 | ||
| 71 | --- a/xmlwf/xmlwf.c | ||
| 72 | +++ b/xmlwf/xmlwf.c | ||
| 73 | @@ -913,11 +913,11 @@ usage(const XML_Char *prog, int rc) { | ||
| 74 | T(" -t write no XML output for [t]iming of plain parsing\n") | ||
| 75 | T(" -N enable adding doctype and [n]otation declarations\n") | ||
| 76 | T("\n") | ||
| 77 | - T("billion laughs attack protection:\n") | ||
| 78 | + T("amplification attack protection (e.g. billion laughs):\n") | ||
| 79 | T(" NOTE: If you ever need to increase these values for non-attack payload, please file a bug report.\n") | ||
| 80 | T("\n") | ||
| 81 | T(" -a FACTOR set maximum tolerated [a]mplification factor (default: 100.0)\n") | ||
| 82 | - T(" -b BYTES set number of output [b]ytes needed to activate (default: 8 MiB)\n") | ||
| 83 | + T(" -b BYTES set number of output [b]ytes needed to activate (default: 8 MiB/64 MiB)\n") | ||
| 84 | T("\n") | ||
| 85 | T("reparse deferral:\n") | ||
| 86 | T(" -q disable reparse deferral, and allow [q]uadratic parse runtime with large tokens\n") | ||
| 87 | @@ -1181,12 +1181,15 @@ tmain(int argc, XML_Char **argv) { | ||
| 88 | #if XML_GE == 1 | ||
| 89 | XML_SetBillionLaughsAttackProtectionMaximumAmplification( | ||
| 90 | parser, attackMaximumAmplification); | ||
| 91 | + XML_SetAllocTrackerMaximumAmplification(parser, | ||
| 92 | + attackMaximumAmplification); | ||
| 93 | #endif | ||
| 94 | } | ||
| 95 | if (attackThresholdGiven) { | ||
| 96 | #if XML_GE == 1 | ||
| 97 | XML_SetBillionLaughsAttackProtectionActivationThreshold( | ||
| 98 | parser, attackThresholdBytes); | ||
| 99 | + XML_SetAllocTrackerActivationThreshold(parser, attackThresholdBytes); | ||
| 100 | #else | ||
| 101 | (void)attackThresholdBytes; // silence -Wunused-but-set-variable | ||
| 102 | #endif | ||
| 103 | diff --git a/xmlwf/xmlwf_helpgen.py b/xmlwf/xmlwf_helpgen.py | ||
| 104 | index 2360820d..e91c285c 100755 | ||
| 105 | --- a/xmlwf/xmlwf_helpgen.py | ||
| 106 | +++ b/xmlwf/xmlwf_helpgen.py | ||
| 107 | @@ -84,13 +84,13 @@ output_mode.add_argument('-m', action='store_true', help='write [m]eta XML, not | ||
| 108 | output_mode.add_argument('-t', action='store_true', help='write no XML output for [t]iming of plain parsing') | ||
| 109 | output_related.add_argument('-N', action='store_true', help='enable adding doctype and [n]otation declarations') | ||
| 110 | |||
| 111 | -billion_laughs = parser.add_argument_group('billion laughs attack protection', | ||
| 112 | +billion_laughs = parser.add_argument_group('amplification attack protection (e.g. billion laughs)', | ||
| 113 | description='NOTE: ' | ||
| 114 | 'If you ever need to increase these values ' | ||
| 115 | 'for non-attack payload, please file a bug report.') | ||
| 116 | billion_laughs.add_argument('-a', metavar='FACTOR', | ||
| 117 | help='set maximum tolerated [a]mplification factor (default: 100.0)') | ||
| 118 | -billion_laughs.add_argument('-b', metavar='BYTES', help='set number of output [b]ytes needed to activate (default: 8 MiB)') | ||
| 119 | +billion_laughs.add_argument('-b', metavar='BYTES', help='set number of output [b]ytes needed to activate (default: 8 MiB/64 MiB)') | ||
| 120 | |||
| 121 | reparse_deferral = parser.add_argument_group('reparse deferral') | ||
| 122 | reparse_deferral.add_argument('-q', metavar='FACTOR', | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-15.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-15.patch new file mode 100644 index 0000000000..8d06844192 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-15.patch | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | From 5ae51be57ed0ca1e87582881d07ea9c29c4f7c05 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Wed, 3 Sep 2025 17:06:41 +0200 | ||
| 4 | Subject: [PATCH] fuzz: Be robust towards NULL return from | ||
| 5 | XML_ExternalEntityParserCreate | ||
| 6 | |||
| 7 | CVE: CVE-2025-59375 | ||
| 8 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/5ae51be57ed0ca1e87582881d07ea9c29c4f7c05] | ||
| 9 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 10 | --- | ||
| 11 | fuzz/xml_parse_fuzzer.c | 14 ++++++++------ | ||
| 12 | fuzz/xml_parsebuffer_fuzzer.c | 14 ++++++++------ | ||
| 13 | 2 files changed, 16 insertions(+), 12 deletions(-) | ||
| 14 | |||
| 15 | diff --git a/fuzz/xml_parse_fuzzer.c b/fuzz/xml_parse_fuzzer.c | ||
| 16 | index 90c38549..29ab33ff 100644 | ||
| 17 | --- a/fuzz/xml_parse_fuzzer.c | ||
| 18 | +++ b/fuzz/xml_parse_fuzzer.c | ||
| 19 | @@ -89,15 +89,17 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { | ||
| 20 | |||
| 21 | XML_Parser externalEntityParser | ||
| 22 | = XML_ExternalEntityParserCreate(parentParser, "e1", NULL); | ||
| 23 | - assert(externalEntityParser); | ||
| 24 | - ParseOneInput(externalEntityParser, data, size); | ||
| 25 | - XML_ParserFree(externalEntityParser); | ||
| 26 | + if (externalEntityParser != NULL) { | ||
| 27 | + ParseOneInput(externalEntityParser, data, size); | ||
| 28 | + XML_ParserFree(externalEntityParser); | ||
| 29 | + } | ||
| 30 | |||
| 31 | XML_Parser externalDtdParser | ||
| 32 | = XML_ExternalEntityParserCreate(parentParser, NULL, NULL); | ||
| 33 | - assert(externalDtdParser); | ||
| 34 | - ParseOneInput(externalDtdParser, data, size); | ||
| 35 | - XML_ParserFree(externalDtdParser); | ||
| 36 | + if (externalDtdParser != NULL) { | ||
| 37 | + ParseOneInput(externalDtdParser, data, size); | ||
| 38 | + XML_ParserFree(externalDtdParser); | ||
| 39 | + } | ||
| 40 | |||
| 41 | // finally frees this parser which served as parent | ||
| 42 | XML_ParserFree(parentParser); | ||
| 43 | diff --git a/fuzz/xml_parsebuffer_fuzzer.c b/fuzz/xml_parsebuffer_fuzzer.c | ||
| 44 | index 0db67dce..38b9981b 100644 | ||
| 45 | --- a/fuzz/xml_parsebuffer_fuzzer.c | ||
| 46 | +++ b/fuzz/xml_parsebuffer_fuzzer.c | ||
| 47 | @@ -101,15 +101,17 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { | ||
| 48 | |||
| 49 | XML_Parser externalEntityParser | ||
| 50 | = XML_ExternalEntityParserCreate(parentParser, "e1", NULL); | ||
| 51 | - assert(externalEntityParser); | ||
| 52 | - ParseOneInput(externalEntityParser, data, size); | ||
| 53 | - XML_ParserFree(externalEntityParser); | ||
| 54 | + if (externalEntityParser != NULL) { | ||
| 55 | + ParseOneInput(externalEntityParser, data, size); | ||
| 56 | + XML_ParserFree(externalEntityParser); | ||
| 57 | + } | ||
| 58 | |||
| 59 | XML_Parser externalDtdParser | ||
| 60 | = XML_ExternalEntityParserCreate(parentParser, NULL, NULL); | ||
| 61 | - assert(externalDtdParser); | ||
| 62 | - ParseOneInput(externalDtdParser, data, size); | ||
| 63 | - XML_ParserFree(externalDtdParser); | ||
| 64 | + if (externalDtdParser != NULL) { | ||
| 65 | + ParseOneInput(externalDtdParser, data, size); | ||
| 66 | + XML_ParserFree(externalDtdParser); | ||
| 67 | + } | ||
| 68 | |||
| 69 | // finally frees this parser which served as parent | ||
| 70 | XML_ParserFree(parentParser); | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-16.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-16.patch new file mode 100644 index 0000000000..a276347d83 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-16.patch | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | From d6246c31a1238d065b4d9690d3bac740326f6485 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Wed, 3 Sep 2025 01:28:03 +0200 | ||
| 4 | Subject: [PATCH] docs: Document the two allocation tracking API functions | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/d6246c31a1238d065b4d9690d3bac740326f6485] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | doc/reference.html | 116 +++++++++++++++++++++++++++++++++++++++++++++ | ||
| 11 | 1 file changed, 116 insertions(+) | ||
| 12 | |||
| 13 | diff --git a/doc/reference.html b/doc/reference.html | ||
| 14 | index 89476710..81da4e6c 100644 | ||
| 15 | --- a/doc/reference.html | ||
| 16 | +++ b/doc/reference.html | ||
| 17 | @@ -157,6 +157,8 @@ interface.</p> | ||
| 18 | <ul> | ||
| 19 | <li><a href="#XML_SetBillionLaughsAttackProtectionMaximumAmplification">XML_SetBillionLaughsAttackProtectionMaximumAmplification</a></li> | ||
| 20 | <li><a href="#XML_SetBillionLaughsAttackProtectionActivationThreshold">XML_SetBillionLaughsAttackProtectionActivationThreshold</a></li> | ||
| 21 | + <li><a href="#XML_SetAllocTrackerMaximumAmplification">XML_SetAllocTrackerMaximumAmplification</a></li> | ||
| 22 | + <li><a href="#XML_SetAllocTrackerActivationThreshold">XML_SetAllocTrackerActivationThreshold</a></li> | ||
| 23 | <li><a href="#XML_SetReparseDeferralEnabled">XML_SetReparseDeferralEnabled</a></li> | ||
| 24 | </ul> | ||
| 25 | </li> | ||
| 26 | @@ -2262,6 +2264,120 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold(XML_Parser p, | ||
| 27 | </p> | ||
| 28 | </div> | ||
| 29 | |||
| 30 | +<h4 id="XML_SetAllocTrackerMaximumAmplification">XML_SetAllocTrackerMaximumAmplification</h4> | ||
| 31 | +<pre class="fcndec"> | ||
| 32 | +/* Added in Expat 2.7.2. */ | ||
| 33 | +XML_Bool | ||
| 34 | +XML_SetAllocTrackerMaximumAmplification(XML_Parser p, | ||
| 35 | + float maximumAmplificationFactor); | ||
| 36 | +</pre> | ||
| 37 | +<div class="fcndef"> | ||
| 38 | + <p> | ||
| 39 | + Sets the maximum tolerated amplification factor | ||
| 40 | + between direct input and bytes of dynamic memory allocated | ||
| 41 | + (default: <code>100.0</code>) | ||
| 42 | + of parser <code>p</code> to <code>maximumAmplificationFactor</code>, and | ||
| 43 | + returns <code>XML_TRUE</code> upon success and <code>XML_FALSE</code> upon error. | ||
| 44 | + </p> | ||
| 45 | + | ||
| 46 | + <p> | ||
| 47 | + <strong>Note:</strong> | ||
| 48 | + There are three types of allocations that intentionally bypass tracking and limiting: | ||
| 49 | + </p> | ||
| 50 | + <ul> | ||
| 51 | + <li> | ||
| 52 | + application calls to functions | ||
| 53 | + <code><a href="#XML_MemMalloc">XML_MemMalloc</a></code> | ||
| 54 | + and | ||
| 55 | + <code><a href="#XML_MemRealloc">XML_MemRealloc</a></code> | ||
| 56 | + — | ||
| 57 | + <em>healthy</em> use of these two functions continues to be a responsibility | ||
| 58 | + of the application using Expat | ||
| 59 | + —, | ||
| 60 | + </li> | ||
| 61 | + <li> | ||
| 62 | + the main character buffer used by functions | ||
| 63 | + <code><a href="#XML_GetBuffer">XML_GetBuffer</a></code> | ||
| 64 | + and | ||
| 65 | + <code><a href="#XML_ParseBuffer">XML_ParseBuffer</a></code> | ||
| 66 | + (and thus also by plain | ||
| 67 | + <code><a href="#XML_Parse">XML_Parse</a></code>), and | ||
| 68 | + </li> | ||
| 69 | + <li> | ||
| 70 | + the <a href="#XML_SetElementDeclHandler">content model memory</a> | ||
| 71 | + (that is passed to the | ||
| 72 | + <a href="#XML_SetElementDeclHandler">element declaration handler</a> | ||
| 73 | + and freed by a call to | ||
| 74 | + <code><a href="#XML_FreeContentModel">XML_FreeContentModel</a></code>). | ||
| 75 | + </li> | ||
| 76 | + </ul> | ||
| 77 | + | ||
| 78 | + <p>The amplification factor is calculated as ..</p> | ||
| 79 | + <pre>amplification := allocated / direct</pre> | ||
| 80 | + <p> | ||
| 81 | + .. while parsing, whereas | ||
| 82 | + <code>direct</code> is the number of bytes read from the primary document in parsing and | ||
| 83 | + <code>allocated</code> is the number of bytes of dynamic memory allocated in the parser hierarchy. | ||
| 84 | + </p> | ||
| 85 | + | ||
| 86 | + <p>For a call to <code>XML_SetAllocTrackerMaximumAmplification</code> to succeed:</p> | ||
| 87 | + <ul> | ||
| 88 | + <li>parser <code>p</code> must be a non-<code>NULL</code> root parser (without any parent parsers) and</li> | ||
| 89 | + <li><code>maximumAmplificationFactor</code> must be non-<code>NaN</code> and greater than or equal to <code>1.0</code>.</li> | ||
| 90 | + </ul> | ||
| 91 | + | ||
| 92 | + <p> | ||
| 93 | + <strong>Note:</strong> | ||
| 94 | + If you ever need to increase this value for non-attack payload, | ||
| 95 | + please <a href="https://github.com/libexpat/libexpat/issues">file a bug report</a>. | ||
| 96 | + </p> | ||
| 97 | + | ||
| 98 | + <p> | ||
| 99 | + <strong>Note:</strong> | ||
| 100 | + Amplifications factors greater than 100 can been observed near the start of parsing | ||
| 101 | + even with benign files in practice. | ||
| 102 | + | ||
| 103 | + So if you do reduce the maximum allowed amplification, | ||
| 104 | + please make sure that the activation threshold is still big enough | ||
| 105 | + to not end up with undesired false positives (i.e. benign files being rejected). | ||
| 106 | + </p> | ||
| 107 | +</div> | ||
| 108 | + | ||
| 109 | +<h4 id="XML_SetAllocTrackerActivationThreshold">XML_SetAllocTrackerActivationThreshold</h4> | ||
| 110 | +<pre class="fcndec"> | ||
| 111 | +/* Added in Expat 2.7.2. */ | ||
| 112 | +XML_Bool | ||
| 113 | +XML_SetAllocTrackerActivationThreshold(XML_Parser p, | ||
| 114 | + unsigned long long activationThresholdBytes); | ||
| 115 | +</pre> | ||
| 116 | +<div class="fcndef"> | ||
| 117 | + <p> | ||
| 118 | + Sets number of allocated bytes of dynamic memory | ||
| 119 | + needed to activate protection against disproportionate use of RAM | ||
| 120 | + (default: <code>64 MiB</code>) | ||
| 121 | + of parser <code>p</code> to <code>activationThresholdBytes</code>, and | ||
| 122 | + returns <code>XML_TRUE</code> upon success and <code>XML_FALSE</code> upon error. | ||
| 123 | + </p> | ||
| 124 | + | ||
| 125 | + <p> | ||
| 126 | + <strong>Note:</strong> | ||
| 127 | + For types of allocations that intentionally bypass tracking and limiting, please see | ||
| 128 | + <code><a href="#XML_SetAllocTrackerMaximumAmplification">XML_SetAllocTrackerMaximumAmplification</a></code> | ||
| 129 | + above. | ||
| 130 | + </p> | ||
| 131 | + | ||
| 132 | + <p>For a call to <code>XML_SetAllocTrackerActivationThreshold</code> to succeed:</p> | ||
| 133 | + <ul> | ||
| 134 | + <li>parser <code>p</code> must be a non-<code>NULL</code> root parser (without any parent parsers).</li> | ||
| 135 | + </ul> | ||
| 136 | + | ||
| 137 | + <p> | ||
| 138 | + <strong>Note:</strong> | ||
| 139 | + If you ever need to increase this value for non-attack payload, | ||
| 140 | + please <a href="https://github.com/libexpat/libexpat/issues">file a bug report</a>. | ||
| 141 | + </p> | ||
| 142 | +</div> | ||
| 143 | + | ||
| 144 | <h4 id="XML_SetReparseDeferralEnabled">XML_SetReparseDeferralEnabled</h4> | ||
| 145 | <pre class="fcndec"> | ||
| 146 | /* Added in Expat 2.6.0. */ | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-17.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-17.patch new file mode 100644 index 0000000000..ca0e3a34f7 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-17.patch | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | From a6a2a49367f03f5d8a73c9027b45b59953ca27d8 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Wed, 10 Sep 2025 19:52:39 +0200 | ||
| 4 | Subject: [PATCH] docs: Promote the contract to call XML_FreeContentModel | ||
| 5 | |||
| 6 | .. when registering a custom element declaration handler | ||
| 7 | (via a call to function XML_SetElementDeclHandler) | ||
| 8 | |||
| 9 | CVE: CVE-2025-59375 | ||
| 10 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/a6a2a49367f03f5d8a73c9027b45b59953ca27d8] | ||
| 11 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 12 | --- | ||
| 13 | doc/reference.html | 2 +- | ||
| 14 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
| 15 | |||
| 16 | diff --git a/doc/reference.html b/doc/reference.html | ||
| 17 | index 81da4e6c..564fc1b2 100644 | ||
| 18 | --- a/doc/reference.html | ||
| 19 | +++ b/doc/reference.html | ||
| 20 | @@ -1902,7 +1902,7 @@ struct XML_cp { | ||
| 21 | <p>Sets a handler for element declarations in a DTD. The handler gets | ||
| 22 | called with the name of the element in the declaration and a pointer | ||
| 23 | to a structure that contains the element model. It's the user code's | ||
| 24 | -responsibility to free model when finished with it. See <code> | ||
| 25 | +responsibility to free model when finished with via a call to <code> | ||
| 26 | <a href="#XML_FreeContentModel">XML_FreeContentModel</a></code>. | ||
| 27 | There is no need to free the model from the handler, it can be kept | ||
| 28 | around and freed at a later stage.</p> | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-18.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-18.patch new file mode 100644 index 0000000000..c29b301825 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-18.patch | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | From a21a3a8299e1ee0b0ae5ae2886a0746d088cf135 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Sun, 7 Sep 2025 16:00:35 +0200 | ||
| 4 | Subject: [PATCH] Changes: Document allocation tracking | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/a21a3a8299e1ee0b0ae5ae2886a0746d088cf135] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | Changes | 37 +++++++++++++++++++++++++++++++++++++ | ||
| 11 | 1 file changed, 37 insertions(+) | ||
| 12 | |||
| 13 | diff --git a/Changes b/Changes | ||
| 14 | index cb752151..ceb5c5dc 100644 | ||
| 15 | --- a/Changes | ||
| 16 | +++ b/Changes | ||
| 17 | @@ -30,6 +30,36 @@ | ||
| 18 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
| 19 | |||
| 20 | Patches: | ||
| 21 | + Security fixes: | ||
| 22 | + #1018 #1034 CVE-2025-59375 -- Disallow use of disproportional amounts of | ||
| 23 | + dynamic memory from within an Expat parser (e.g. previously | ||
| 24 | + a ~250 KiB sized document was able to cause allocation of | ||
| 25 | + ~800 MiB from the heap, i.e. an "amplification" of factor | ||
| 26 | + ~3,300); once a threshold (that defaults to 64 MiB) is | ||
| 27 | + reached, a maximum amplification factor (that defaults to | ||
| 28 | + 100.0) is enforced, and violating documents are rejected | ||
| 29 | + with an out-of-memory error. | ||
| 30 | + There are two new API functions to fine-tune this new | ||
| 31 | + behavior: | ||
| 32 | + - XML_SetAllocTrackerActivationThreshold | ||
| 33 | + - XML_SetAllocTrackerMaximumAmplification . | ||
| 34 | + If you ever need to increase these defaults for non-attack | ||
| 35 | + XML payload, please file a bug report with libexpat. | ||
| 36 | + There is also a new environment variable | ||
| 37 | + EXPAT_MALLOC_DEBUG=(0|1|2) to control the verbosity | ||
| 38 | + of allocations debugging at runtime, disabled by default. | ||
| 39 | + Known impact is (reliable and easy) denial of service: | ||
| 40 | + CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H/E:H/RL:O/RC:C | ||
| 41 | + (Base Score: 7.5, Temporal Score: 7.2) | ||
| 42 | + Please note that a layer of compression around XML can | ||
| 43 | + significantly reduce the minimum attack payload size. | ||
| 44 | + Distributors intending to backport (or cherry-pick) the | ||
| 45 | + fix need to copy 99% of the related pull request, not just | ||
| 46 | + the "lib: Implement tracking of dynamic memory allocations" | ||
| 47 | + commit, to not end up with a state that literally does both | ||
| 48 | + too much and too little at the same time. Appending ".diff" | ||
| 49 | + to the pull request URL could be of help. | ||
| 50 | + | ||
| 51 | Bug fixes: | ||
| 52 | #980 #989 Restore event pointer behavior from Expat 2.6.4 | ||
| 53 | (that the fix to CVE-2024-8176 changed in 2.7.0); | ||
| 54 | @@ -39,6 +69,10 @@ Patches: | ||
| 55 | - XML_GetCurrentColumnNumber | ||
| 56 | - XML_GetCurrentLineNumber | ||
| 57 | - XML_GetInputContext | ||
| 58 | + #1034 docs: Promote the contract to call function | ||
| 59 | + XML_FreeContentModel when registering a custom | ||
| 60 | + element declaration handler (via a call to function | ||
| 61 | + XML_SetElementDeclHandler) | ||
| 62 | |||
| 63 | Special thanks to: | ||
| 64 | Berkay Eren Ürün | ||
| 65 | @@ -71,6 +105,9 @@ Patches: | ||
| 66 | Linutronix | ||
| 67 | Red Hat | ||
| 68 | Siemens | ||
| 69 | + and | ||
| 70 | + OSS-Fuzz / ClusterFuzz | ||
| 71 | + Perl XML::Parser | ||
| 72 | |||
| 73 | Release 2.6.4 Wed November 6 2024 | ||
| 74 | Security fixes: | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-19.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-19.patch new file mode 100644 index 0000000000..afd4d91d03 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-19.patch | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | From f4b5bb033dc4430bbd31dcae8a55f988360bcec5 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Wed, 17 Sep 2025 23:14:02 +0200 | ||
| 4 | Subject: [PATCH] lib: Document and regression-proof absence of integer | ||
| 5 | overflow from expat_realloc | ||
| 6 | |||
| 7 | Matthew Fernandez (@Smattr) and I teamed up on whether function expat_realloc | ||
| 8 | could be vulnerable to integer overflow in line: | ||
| 9 | |||
| 10 | mallocedPtr = parser->m_mem.realloc_fcn(mallocedPtr, sizeof(size_t) + size); | ||
| 11 | ^ | ||
| 12 | We ended up with a mathematical proof that, fortunately, the current code | ||
| 13 | already is safe from overflow. | ||
| 14 | |||
| 15 | The proof uses technique "proof by contradiction". Let's assume, there *was* a | ||
| 16 | risk of integer overflow. For a risk of overflow, these four conditions would | ||
| 17 | all need to be met, together: | ||
| 18 | |||
| 19 | (1) `SIZE_MAX < sizeof(size_t) + size` | ||
| 20 | or we would not hit an overflow on `size_t`. | ||
| 21 | |||
| 22 | (2) `size > prevSize` | ||
| 23 | or `expat_malloc` would have already not allocated earlier | ||
| 24 | as `expat_realloc` relies on `expat_malloc` for the initial allocation. | ||
| 25 | |||
| 26 | (3) `rootParser->m_alloc_tracker.bytesAllocated >= sizeof(size_t) + prevSize` | ||
| 27 | or the previous allocation would be gone already or have bypassed accounting. | ||
| 28 | The code is not thread-safe in general, race conditions are off the table. | ||
| 29 | |||
| 30 | (4) `rootParser->m_alloc_tracker.bytesAllocated + (size - prevSize) <= SIZE_MAX` | ||
| 31 | or `expat_heap_increase_tolerable` would have returned `false` and | ||
| 32 | the overflow line would not be reached. | ||
| 33 | |||
| 34 | We encoded this for the Z3 Theorem Prover (https://github.com/Z3Prover/z3) | ||
| 35 | and ended up with this document: | ||
| 36 | |||
| 37 | $ cat proof_v2.smt2 | ||
| 38 | ; Copyright (c) 2025 Matthew Fernandez <matthew.fernandez@gmail.com> | ||
| 39 | ; Copyright (c) 2025 Sebastian Pipping <sebastian@pipping.org> | ||
| 40 | ; Licensed under the MIT license | ||
| 41 | |||
| 42 | ; (1), (2), (3), (4) form a contradiction | ||
| 43 | |||
| 44 | ; define `SIZE_MAX` | ||
| 45 | (declare-fun SIZE_MAX () (_ BitVec 64)) | ||
| 46 | (assert (= SIZE_MAX #xffffffffffffffff)) | ||
| 47 | |||
| 48 | ; define `sizeof(size_t)` | ||
| 49 | (declare-fun sizeof_size_t () (_ BitVec 64)) | ||
| 50 | (assert (= sizeof_size_t #x0000000000000008)) | ||
| 51 | |||
| 52 | ; claim we have inputs `size`, `prevSize`, and `bytesAllocated` | ||
| 53 | (declare-fun size () (_ BitVec 64)) | ||
| 54 | (declare-fun prevSize () (_ BitVec 64)) | ||
| 55 | (declare-fun bytesAllocated () (_ BitVec 64)) | ||
| 56 | |||
| 57 | ; assume `SIZE_MAX - sizeof(size_t) < size` (1) | ||
| 58 | (assert (bvult (bvsub SIZE_MAX sizeof_size_t) size)) | ||
| 59 | |||
| 60 | ; assume `bytesAllocated >= sizeof(size_t) + prevSize` (3) | ||
| 61 | (assert (bvuge bytesAllocated (bvadd sizeof_size_t prevSize))) | ||
| 62 | |||
| 63 | ; assume `bytesAllocated - prevSize <= SIZE_MAX - size` (4) | ||
| 64 | (assert (bvule (bvsub bytesAllocated prevSize) (bvsub SIZE_MAX size))) | ||
| 65 | |||
| 66 | ; assume `SIZE_MAX - sizeof(size_t) >= prevSize` (anti-overflow for 3) | ||
| 67 | (assert (bvuge (bvsub SIZE_MAX sizeof_size_t) prevSize)) | ||
| 68 | |||
| 69 | ; prove we have a contradiction | ||
| 70 | (check-sat) | ||
| 71 | |||
| 72 | Note that we operate on fixed-size bit vectors here, and hence had | ||
| 73 | to transform the assertions to not allow integer overflow by themselves. | ||
| 74 | |||
| 75 | Z3 confirms the contradiction, and thus the absence of integer overflow: | ||
| 76 | |||
| 77 | $ z3 -smt2 -model proof_v2.smt2 | ||
| 78 | unsat | ||
| 79 | |||
| 80 | Co-authored-by: Matthew Fernandez <matthew.fernandez@gmail.com> | ||
| 81 | |||
| 82 | CVE: CVE-2025-59375 | ||
| 83 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/f4b5bb033dc4430bbd31dcae8a55f988360bcec5] | ||
| 84 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 85 | --- | ||
| 86 | lib/xmlparse.c | 4 ++++ | ||
| 87 | 1 file changed, 4 insertions(+) | ||
| 88 | |||
| 89 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 90 | index de159493..24fd7b97 100644 | ||
| 91 | --- a/lib/xmlparse.c | ||
| 92 | +++ b/lib/xmlparse.c | ||
| 93 | @@ -969,6 +969,10 @@ expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | + // NOTE: Integer overflow detection has already been done for us | ||
| 98 | + // by expat_heap_increase_tolerable(..) above | ||
| 99 | + assert(SIZE_MAX - sizeof(size_t) >= size); | ||
| 100 | + | ||
| 101 | // Actually allocate | ||
| 102 | mallocedPtr = parser->m_mem.realloc_fcn(mallocedPtr, sizeof(size_t) + size); | ||
| 103 | |||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-20.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-20.patch new file mode 100644 index 0000000000..80628f20fb --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-20.patch | |||
| @@ -0,0 +1,285 @@ | |||
| 1 | From faf36f806c9065bfd9f0567b01924d5e27c4911c Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Mon, 15 Sep 2025 18:05:23 +0200 | ||
| 4 | Subject: [PATCH] lib: Drop casts around malloc/realloc returns that C99 does | ||
| 5 | not need | ||
| 6 | |||
| 7 | CVE: CVE-2025-59375 | ||
| 8 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/faf36f806c9065bfd9f0567b01924d5e27c4911c] | ||
| 9 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 10 | --- | ||
| 11 | lib/xmlparse.c | 80 ++++++++++++++++++++++---------------------------- | ||
| 12 | 1 file changed, 35 insertions(+), 45 deletions(-) | ||
| 13 | |||
| 14 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 15 | index 6e9c6fb2..fb8ad2e7 100644 | ||
| 16 | --- a/lib/xmlparse.c | ||
| 17 | +++ b/lib/xmlparse.c | ||
| 18 | @@ -1370,12 +1370,12 @@ parserCreate(const XML_Char *encodingName, | ||
| 19 | XML_Memory_Handling_Suite *mtemp; | ||
| 20 | #if XML_GE == 1 | ||
| 21 | void *const sizeAndParser | ||
| 22 | - = (XML_Parser)malloc(sizeof(size_t) + sizeof(struct XML_ParserStruct)); | ||
| 23 | + = malloc(sizeof(size_t) + sizeof(struct XML_ParserStruct)); | ||
| 24 | if (sizeAndParser != NULL) { | ||
| 25 | *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); | ||
| 26 | parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)); | ||
| 27 | #else | ||
| 28 | - parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct)); | ||
| 29 | + parser = malloc(sizeof(struct XML_ParserStruct)); | ||
| 30 | if (parser != NULL) { | ||
| 31 | #endif | ||
| 32 | mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); | ||
| 33 | @@ -1433,23 +1433,20 @@ parserCreate(const XML_Char *encodingName, | ||
| 34 | parser->m_bufferLim = NULL; | ||
| 35 | |||
| 36 | parser->m_attsSize = INIT_ATTS_SIZE; | ||
| 37 | - parser->m_atts | ||
| 38 | - = (ATTRIBUTE *)MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE)); | ||
| 39 | + parser->m_atts = MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE)); | ||
| 40 | if (parser->m_atts == NULL) { | ||
| 41 | FREE(parser, parser); | ||
| 42 | return NULL; | ||
| 43 | } | ||
| 44 | #ifdef XML_ATTR_INFO | ||
| 45 | - parser->m_attInfo = (XML_AttrInfo *)MALLOC( | ||
| 46 | - parser, parser->m_attsSize * sizeof(XML_AttrInfo)); | ||
| 47 | + parser->m_attInfo = MALLOC(parser, parser->m_attsSize * sizeof(XML_AttrInfo)); | ||
| 48 | if (parser->m_attInfo == NULL) { | ||
| 49 | FREE(parser, parser->m_atts); | ||
| 50 | FREE(parser, parser); | ||
| 51 | return NULL; | ||
| 52 | } | ||
| 53 | #endif | ||
| 54 | - parser->m_dataBuf | ||
| 55 | - = (XML_Char *)MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char)); | ||
| 56 | + parser->m_dataBuf = MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char)); | ||
| 57 | if (parser->m_dataBuf == NULL) { | ||
| 58 | FREE(parser, parser->m_atts); | ||
| 59 | #ifdef XML_ATTR_INFO | ||
| 60 | @@ -2588,7 +2585,7 @@ XML_GetBuffer(XML_Parser parser, int len) { | ||
| 61 | } | ||
| 62 | // NOTE: We are avoiding MALLOC(..) here to leave limiting | ||
| 63 | // the input size to the application using Expat. | ||
| 64 | - newBuf = (char *)parser->m_mem.malloc_fcn(bufferSize); | ||
| 65 | + newBuf = parser->m_mem.malloc_fcn(bufferSize); | ||
| 66 | if (newBuf == 0) { | ||
| 67 | parser->m_errorCode = XML_ERROR_NO_MEMORY; | ||
| 68 | return NULL; | ||
| 69 | @@ -3133,7 +3130,7 @@ storeRawNames(XML_Parser parser) { | ||
| 70 | return XML_FALSE; | ||
| 71 | bufSize = nameLen + (int)rawNameLen; | ||
| 72 | if (bufSize > tag->bufEnd - tag->buf) { | ||
| 73 | - char *temp = (char *)REALLOC(parser, tag->buf, bufSize); | ||
| 74 | + char *temp = REALLOC(parser, tag->buf, bufSize); | ||
| 75 | if (temp == NULL) | ||
| 76 | return XML_FALSE; | ||
| 77 | /* if tag->name.str points to tag->buf (only when namespace | ||
| 78 | @@ -3459,10 +3456,10 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, | ||
| 79 | tag = parser->m_freeTagList; | ||
| 80 | parser->m_freeTagList = parser->m_freeTagList->parent; | ||
| 81 | } else { | ||
| 82 | - tag = (TAG *)MALLOC(parser, sizeof(TAG)); | ||
| 83 | + tag = MALLOC(parser, sizeof(TAG)); | ||
| 84 | if (! tag) | ||
| 85 | return XML_ERROR_NO_MEMORY; | ||
| 86 | - tag->buf = (char *)MALLOC(parser, INIT_TAG_BUF_SIZE); | ||
| 87 | + tag->buf = MALLOC(parser, INIT_TAG_BUF_SIZE); | ||
| 88 | if (! tag->buf) { | ||
| 89 | FREE(parser, tag); | ||
| 90 | return XML_ERROR_NO_MEMORY; | ||
| 91 | @@ -3495,7 +3492,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, | ||
| 92 | } | ||
| 93 | bufSize = (int)(tag->bufEnd - tag->buf) << 1; | ||
| 94 | { | ||
| 95 | - char *temp = (char *)REALLOC(parser, tag->buf, bufSize); | ||
| 96 | + char *temp = REALLOC(parser, tag->buf, bufSize); | ||
| 97 | if (temp == NULL) | ||
| 98 | return XML_ERROR_NO_MEMORY; | ||
| 99 | tag->buf = temp; | ||
| 100 | @@ -3874,8 +3871,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, | ||
| 101 | } | ||
| 102 | #endif | ||
| 103 | |||
| 104 | - temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts, | ||
| 105 | - parser->m_attsSize * sizeof(ATTRIBUTE)); | ||
| 106 | + temp = REALLOC(parser, (void *)parser->m_atts, | ||
| 107 | + parser->m_attsSize * sizeof(ATTRIBUTE)); | ||
| 108 | if (temp == NULL) { | ||
| 109 | parser->m_attsSize = oldAttsSize; | ||
| 110 | return XML_ERROR_NO_MEMORY; | ||
| 111 | @@ -3893,8 +3890,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, | ||
| 112 | } | ||
| 113 | # endif | ||
| 114 | |||
| 115 | - temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo, | ||
| 116 | - parser->m_attsSize * sizeof(XML_AttrInfo)); | ||
| 117 | + temp2 = REALLOC(parser, (void *)parser->m_attInfo, | ||
| 118 | + parser->m_attsSize * sizeof(XML_AttrInfo)); | ||
| 119 | if (temp2 == NULL) { | ||
| 120 | parser->m_attsSize = oldAttsSize; | ||
| 121 | return XML_ERROR_NO_MEMORY; | ||
| 122 | @@ -4070,8 +4067,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, | ||
| 123 | } | ||
| 124 | #endif | ||
| 125 | |||
| 126 | - temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts, | ||
| 127 | - nsAttsSize * sizeof(NS_ATT)); | ||
| 128 | + temp = REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT)); | ||
| 129 | if (! temp) { | ||
| 130 | /* Restore actual size of memory in m_nsAtts */ | ||
| 131 | parser->m_nsAttsPower = oldNsAttsPower; | ||
| 132 | @@ -4252,7 +4248,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, | ||
| 133 | } | ||
| 134 | #endif | ||
| 135 | |||
| 136 | - uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char)); | ||
| 137 | + uri = MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char)); | ||
| 138 | if (! uri) | ||
| 139 | return XML_ERROR_NO_MEMORY; | ||
| 140 | binding->uriAlloc = n + EXPAND_SPARE; | ||
| 141 | @@ -4498,8 +4494,8 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, | ||
| 142 | } | ||
| 143 | #endif | ||
| 144 | |||
| 145 | - XML_Char *temp = (XML_Char *)REALLOC( | ||
| 146 | - parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); | ||
| 147 | + XML_Char *temp | ||
| 148 | + = REALLOC(parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); | ||
| 149 | if (temp == NULL) | ||
| 150 | return XML_ERROR_NO_MEMORY; | ||
| 151 | b->uri = temp; | ||
| 152 | @@ -4507,7 +4503,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, | ||
| 153 | } | ||
| 154 | parser->m_freeBindingList = b->nextTagBinding; | ||
| 155 | } else { | ||
| 156 | - b = (BINDING *)MALLOC(parser, sizeof(BINDING)); | ||
| 157 | + b = MALLOC(parser, sizeof(BINDING)); | ||
| 158 | if (! b) | ||
| 159 | return XML_ERROR_NO_MEMORY; | ||
| 160 | |||
| 161 | @@ -4525,8 +4521,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, | ||
| 162 | } | ||
| 163 | #endif | ||
| 164 | |||
| 165 | - b->uri | ||
| 166 | - = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE)); | ||
| 167 | + b->uri = MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE)); | ||
| 168 | if (! b->uri) { | ||
| 169 | FREE(parser, b); | ||
| 170 | return XML_ERROR_NO_MEMORY; | ||
| 171 | @@ -5897,7 +5892,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, | ||
| 172 | return XML_ERROR_NO_MEMORY; | ||
| 173 | } | ||
| 174 | |||
| 175 | - char *const new_connector = (char *)REALLOC( | ||
| 176 | + char *const new_connector = REALLOC( | ||
| 177 | parser, parser->m_groupConnector, parser->m_groupSize *= 2); | ||
| 178 | if (new_connector == NULL) { | ||
| 179 | parser->m_groupSize /= 2; | ||
| 180 | @@ -5917,15 +5912,14 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, | ||
| 181 | } | ||
| 182 | #endif | ||
| 183 | |||
| 184 | - int *const new_scaff_index = (int *)REALLOC( | ||
| 185 | + int *const new_scaff_index = REALLOC( | ||
| 186 | parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int)); | ||
| 187 | if (new_scaff_index == NULL) | ||
| 188 | return XML_ERROR_NO_MEMORY; | ||
| 189 | dtd->scaffIndex = new_scaff_index; | ||
| 190 | } | ||
| 191 | } else { | ||
| 192 | - parser->m_groupConnector | ||
| 193 | - = (char *)MALLOC(parser, parser->m_groupSize = 32); | ||
| 194 | + parser->m_groupConnector = MALLOC(parser, parser->m_groupSize = 32); | ||
| 195 | if (! parser->m_groupConnector) { | ||
| 196 | parser->m_groupSize = 0; | ||
| 197 | return XML_ERROR_NO_MEMORY; | ||
| 198 | @@ -6086,8 +6080,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, | ||
| 199 | // applications that are not using XML_FreeContentModel but | ||
| 200 | // plain free(..) or .free_fcn() to free the content model's | ||
| 201 | // memory are safe. | ||
| 202 | - XML_Content *content | ||
| 203 | - = (XML_Content *)parser->m_mem.malloc_fcn(sizeof(XML_Content)); | ||
| 204 | + XML_Content *content = parser->m_mem.malloc_fcn(sizeof(XML_Content)); | ||
| 205 | if (! content) | ||
| 206 | return XML_ERROR_NO_MEMORY; | ||
| 207 | content->quant = XML_CQUANT_NONE; | ||
| 208 | @@ -6364,8 +6357,7 @@ processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl, | ||
| 209 | openEntity = *freeEntityList; | ||
| 210 | *freeEntityList = openEntity->next; | ||
| 211 | } else { | ||
| 212 | - openEntity | ||
| 213 | - = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY)); | ||
| 214 | + openEntity = MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY)); | ||
| 215 | if (! openEntity) | ||
| 216 | return XML_ERROR_NO_MEMORY; | ||
| 217 | } | ||
| 218 | @@ -7164,8 +7156,8 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, | ||
| 219 | if (type->nDefaultAtts == type->allocDefaultAtts) { | ||
| 220 | if (type->allocDefaultAtts == 0) { | ||
| 221 | type->allocDefaultAtts = 8; | ||
| 222 | - type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC( | ||
| 223 | - parser, type->allocDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); | ||
| 224 | + type->defaultAtts | ||
| 225 | + = MALLOC(parser, type->allocDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); | ||
| 226 | if (! type->defaultAtts) { | ||
| 227 | type->allocDefaultAtts = 0; | ||
| 228 | return 0; | ||
| 229 | @@ -7190,8 +7182,8 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, | ||
| 230 | } | ||
| 231 | #endif | ||
| 232 | |||
| 233 | - temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts, | ||
| 234 | - (count * sizeof(DEFAULT_ATTRIBUTE))); | ||
| 235 | + temp = REALLOC(parser, type->defaultAtts, | ||
| 236 | + (count * sizeof(DEFAULT_ATTRIBUTE))); | ||
| 237 | if (temp == NULL) | ||
| 238 | return 0; | ||
| 239 | type->allocDefaultAtts = count; | ||
| 240 | @@ -8145,8 +8137,7 @@ poolGrow(STRING_POOL *pool) { | ||
| 241 | if (bytesToAllocate == 0) | ||
| 242 | return XML_FALSE; | ||
| 243 | |||
| 244 | - temp = (BLOCK *)REALLOC(pool->parser, pool->blocks, | ||
| 245 | - (unsigned)bytesToAllocate); | ||
| 246 | + temp = REALLOC(pool->parser, pool->blocks, (unsigned)bytesToAllocate); | ||
| 247 | if (temp == NULL) | ||
| 248 | return XML_FALSE; | ||
| 249 | pool->blocks = temp; | ||
| 250 | @@ -8217,7 +8208,7 @@ nextScaffoldPart(XML_Parser parser) { | ||
| 251 | return -1; | ||
| 252 | } | ||
| 253 | #endif | ||
| 254 | - dtd->scaffIndex = (int *)MALLOC(parser, parser->m_groupSize * sizeof(int)); | ||
| 255 | + dtd->scaffIndex = MALLOC(parser, parser->m_groupSize * sizeof(int)); | ||
| 256 | if (! dtd->scaffIndex) | ||
| 257 | return -1; | ||
| 258 | dtd->scaffIndex[0] = 0; | ||
| 259 | @@ -8240,14 +8231,13 @@ nextScaffoldPart(XML_Parser parser) { | ||
| 260 | } | ||
| 261 | #endif | ||
| 262 | |||
| 263 | - temp = (CONTENT_SCAFFOLD *)REALLOC( | ||
| 264 | - parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); | ||
| 265 | + temp = REALLOC(parser, dtd->scaffold, | ||
| 266 | + dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); | ||
| 267 | if (temp == NULL) | ||
| 268 | return -1; | ||
| 269 | dtd->scaffSize *= 2; | ||
| 270 | } else { | ||
| 271 | - temp = (CONTENT_SCAFFOLD *)MALLOC(parser, INIT_SCAFFOLD_ELEMENTS | ||
| 272 | - * sizeof(CONTENT_SCAFFOLD)); | ||
| 273 | + temp = MALLOC(parser, INIT_SCAFFOLD_ELEMENTS * sizeof(CONTENT_SCAFFOLD)); | ||
| 274 | if (temp == NULL) | ||
| 275 | return -1; | ||
| 276 | dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS; | ||
| 277 | @@ -8304,7 +8294,7 @@ build_model(XML_Parser parser) { | ||
| 278 | // NOTE: We are avoiding MALLOC(..) here to so that | ||
| 279 | // applications that are not using XML_FreeContentModel but plain | ||
| 280 | // free(..) or .free_fcn() to free the content model's memory are safe. | ||
| 281 | - ret = (XML_Content *)parser->m_mem.malloc_fcn(allocsize); | ||
| 282 | + ret = parser->m_mem.malloc_fcn(allocsize); | ||
| 283 | if (! ret) | ||
| 284 | return NULL; | ||
| 285 | |||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-21.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-21.patch new file mode 100644 index 0000000000..38bc0d1dd8 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-21.patch | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | From 4b43b8dacc96fd538254e17a69abc9745c3a2ed4 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Fri, 19 Sep 2025 23:32:46 +0200 | ||
| 4 | Subject: [PATCH] lib: Fix alignment of internal allocations for some non-amd64 | ||
| 5 | architectures | ||
| 6 | |||
| 7 | sparc32 is known to be affected. | ||
| 8 | |||
| 9 | CVE: CVE-2025-59375 | ||
| 10 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/4b43b8dacc96fd538254e17a69abc9745c3a2ed4] | ||
| 11 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 12 | --- | ||
| 13 | lib/internal.h | 6 ++++++ | ||
| 14 | lib/xmlparse.c | 38 ++++++++++++++++++++++---------------- | ||
| 15 | tests/alloc_tests.c | 13 ++++++++++--- | ||
| 16 | 3 files changed, 38 insertions(+), 19 deletions(-) | ||
| 17 | |||
| 18 | diff --git a/lib/internal.h b/lib/internal.h | ||
| 19 | index 6e087858..8f5edf48 100644 | ||
| 20 | --- a/lib/internal.h | ||
| 21 | +++ b/lib/internal.h | ||
| 22 | @@ -108,6 +108,7 @@ | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #include <limits.h> // ULONG_MAX | ||
| 26 | +#include <stddef.h> // size_t | ||
| 27 | |||
| 28 | #if defined(_WIN32) \ | ||
| 29 | && (! defined(__USE_MINGW_ANSI_STDIO) \ | ||
| 30 | @@ -150,6 +151,11 @@ | ||
| 31 | #define EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT \ | ||
| 32 | 67108864 // 64 MiB, 2^26 | ||
| 33 | |||
| 34 | +// NOTE: If function expat_alloc was user facing, EXPAT_MALLOC_ALIGNMENT would | ||
| 35 | +// have to take sizeof(long double) into account | ||
| 36 | +#define EXPAT_MALLOC_ALIGNMENT sizeof(long long) // largest parser (sub)member | ||
| 37 | +#define EXPAT_MALLOC_PADDING ((EXPAT_MALLOC_ALIGNMENT) - sizeof(size_t)) | ||
| 38 | + | ||
| 39 | /* NOTE END */ | ||
| 40 | |||
| 41 | #include "expat.h" // so we can use type XML_Parser below | ||
| 42 | diff --git a/lib/xmlparse.c b/lib/xmlparse.c | ||
| 43 | index 24fd7b97..ce29ab6f 100644 | ||
| 44 | --- a/lib/xmlparse.c | ||
| 45 | +++ b/lib/xmlparse.c | ||
| 46 | @@ -850,14 +850,14 @@ static void * | ||
| 47 | # endif | ||
| 48 | expat_malloc(XML_Parser parser, size_t size, int sourceLine) { | ||
| 49 | // Detect integer overflow | ||
| 50 | - if (SIZE_MAX - size < sizeof(size_t)) { | ||
| 51 | + if (SIZE_MAX - size < sizeof(size_t) + EXPAT_MALLOC_PADDING) { | ||
| 52 | return NULL; | ||
| 53 | } | ||
| 54 | |||
| 55 | const XML_Parser rootParser = getRootParserOf(parser, NULL); | ||
| 56 | assert(rootParser->m_parentParser == NULL); | ||
| 57 | |||
| 58 | - const size_t bytesToAllocate = sizeof(size_t) + size; | ||
| 59 | + const size_t bytesToAllocate = sizeof(size_t) + EXPAT_MALLOC_PADDING + size; | ||
| 60 | |||
| 61 | if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated | ||
| 62 | < bytesToAllocate) { | ||
| 63 | @@ -894,7 +894,7 @@ expat_malloc(XML_Parser parser, size_t size, int sourceLine) { | ||
| 64 | rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine); | ||
| 65 | } | ||
| 66 | |||
| 67 | - return (char *)mallocedPtr + sizeof(size_t); | ||
| 68 | + return (char *)mallocedPtr + sizeof(size_t) + EXPAT_MALLOC_PADDING; | ||
| 69 | } | ||
| 70 | |||
| 71 | # if defined(XML_TESTING) | ||
| 72 | @@ -914,8 +914,9 @@ expat_free(XML_Parser parser, void *ptr, int sourceLine) { | ||
| 73 | |||
| 74 | // Extract size (to the eyes of malloc_fcn/realloc_fcn) and | ||
| 75 | // the original pointer returned by malloc/realloc | ||
| 76 | - void *const mallocedPtr = (char *)ptr - sizeof(size_t); | ||
| 77 | - const size_t bytesAllocated = sizeof(size_t) + *(size_t *)mallocedPtr; | ||
| 78 | + void *const mallocedPtr = (char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t); | ||
| 79 | + const size_t bytesAllocated | ||
| 80 | + = sizeof(size_t) + EXPAT_MALLOC_PADDING + *(size_t *)mallocedPtr; | ||
| 81 | |||
| 82 | // Update accounting | ||
| 83 | assert(rootParser->m_alloc_tracker.bytesAllocated >= bytesAllocated); | ||
| 84 | @@ -954,7 +955,7 @@ expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { | ||
| 85 | |||
| 86 | // Extract original size (to the eyes of the caller) and the original | ||
| 87 | // pointer returned by malloc/realloc | ||
| 88 | - void *mallocedPtr = (char *)ptr - sizeof(size_t); | ||
| 89 | + void *mallocedPtr = (char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t); | ||
| 90 | const size_t prevSize = *(size_t *)mallocedPtr; | ||
| 91 | |||
| 92 | // Classify upcoming change | ||
| 93 | @@ -971,10 +972,11 @@ expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { | ||
| 94 | |||
| 95 | // NOTE: Integer overflow detection has already been done for us | ||
| 96 | // by expat_heap_increase_tolerable(..) above | ||
| 97 | - assert(SIZE_MAX - sizeof(size_t) >= size); | ||
| 98 | + assert(SIZE_MAX - sizeof(size_t) - EXPAT_MALLOC_PADDING >= size); | ||
| 99 | |||
| 100 | // Actually allocate | ||
| 101 | - mallocedPtr = parser->m_mem.realloc_fcn(mallocedPtr, sizeof(size_t) + size); | ||
| 102 | + mallocedPtr = parser->m_mem.realloc_fcn( | ||
| 103 | + mallocedPtr, sizeof(size_t) + EXPAT_MALLOC_PADDING + size); | ||
| 104 | |||
| 105 | if (mallocedPtr == NULL) { | ||
| 106 | return NULL; | ||
| 107 | @@ -1005,7 +1007,7 @@ expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) { | ||
| 108 | // Update in-block recorded size | ||
| 109 | *(size_t *)mallocedPtr = size; | ||
| 110 | |||
| 111 | - return (char *)mallocedPtr + sizeof(size_t); | ||
| 112 | + return (char *)mallocedPtr + sizeof(size_t) + EXPAT_MALLOC_PADDING; | ||
| 113 | } | ||
| 114 | #endif // XML_GE == 1 | ||
| 115 | |||
| 116 | @@ -1337,7 +1339,8 @@ parserCreate(const XML_Char *encodingName, | ||
| 117 | XML_Parser parser = NULL; | ||
| 118 | |||
| 119 | #if XML_GE == 1 | ||
| 120 | - const size_t increase = sizeof(size_t) + sizeof(struct XML_ParserStruct); | ||
| 121 | + const size_t increase | ||
| 122 | + = sizeof(size_t) + EXPAT_MALLOC_PADDING + sizeof(struct XML_ParserStruct); | ||
| 123 | |||
| 124 | if (parentParser != NULL) { | ||
| 125 | const XML_Parser rootParser = getRootParserOf(parentParser, NULL); | ||
| 126 | @@ -1352,11 +1355,13 @@ parserCreate(const XML_Char *encodingName, | ||
| 127 | if (memsuite) { | ||
| 128 | XML_Memory_Handling_Suite *mtemp; | ||
| 129 | #if XML_GE == 1 | ||
| 130 | - void *const sizeAndParser = memsuite->malloc_fcn( | ||
| 131 | - sizeof(size_t) + sizeof(struct XML_ParserStruct)); | ||
| 132 | + void *const sizeAndParser | ||
| 133 | + = memsuite->malloc_fcn(sizeof(size_t) + EXPAT_MALLOC_PADDING | ||
| 134 | + + sizeof(struct XML_ParserStruct)); | ||
| 135 | if (sizeAndParser != NULL) { | ||
| 136 | *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); | ||
| 137 | - parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)); | ||
| 138 | + parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t) | ||
| 139 | + + EXPAT_MALLOC_PADDING); | ||
| 140 | #else | ||
| 141 | parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); | ||
| 142 | if (parser != NULL) { | ||
| 143 | @@ -1369,11 +1374,12 @@ parserCreate(const XML_Char *encodingName, | ||
| 144 | } else { | ||
| 145 | XML_Memory_Handling_Suite *mtemp; | ||
| 146 | #if XML_GE == 1 | ||
| 147 | - void *const sizeAndParser | ||
| 148 | - = malloc(sizeof(size_t) + sizeof(struct XML_ParserStruct)); | ||
| 149 | + void *const sizeAndParser = malloc(sizeof(size_t) + EXPAT_MALLOC_PADDING | ||
| 150 | + + sizeof(struct XML_ParserStruct)); | ||
| 151 | if (sizeAndParser != NULL) { | ||
| 152 | *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct); | ||
| 153 | - parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)); | ||
| 154 | + parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t) | ||
| 155 | + + EXPAT_MALLOC_PADDING); | ||
| 156 | #else | ||
| 157 | parser = malloc(sizeof(struct XML_ParserStruct)); | ||
| 158 | if (parser != NULL) { | ||
| 159 | diff --git a/tests/alloc_tests.c b/tests/alloc_tests.c | ||
| 160 | index 644a4952..dabdf0da 100644 | ||
| 161 | --- a/tests/alloc_tests.c | ||
| 162 | +++ b/tests/alloc_tests.c | ||
| 163 | @@ -2091,6 +2091,13 @@ START_TEST(test_alloc_reset_after_external_entity_parser_create_fail) { | ||
| 164 | } | ||
| 165 | END_TEST | ||
| 166 | |||
| 167 | +#if XML_GE == 1 | ||
| 168 | +static size_t | ||
| 169 | +sizeRecordedFor(void *ptr) { | ||
| 170 | + return *(size_t *)((char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t)); | ||
| 171 | +} | ||
| 172 | +#endif // XML_GE == 1 | ||
| 173 | + | ||
| 174 | START_TEST(test_alloc_tracker_size_recorded) { | ||
| 175 | XML_Memory_Handling_Suite memsuite = {malloc, realloc, free}; | ||
| 176 | |||
| 177 | @@ -2106,16 +2113,16 @@ START_TEST(test_alloc_tracker_size_recorded) { | ||
| 178 | void *ptr = expat_malloc(parser, 10, -1); | ||
| 179 | |||
| 180 | assert_true(ptr != NULL); | ||
| 181 | - assert_true(*((size_t *)ptr - 1) == 10); | ||
| 182 | + assert_true(sizeRecordedFor(ptr) == 10); | ||
| 183 | |||
| 184 | assert_true(expat_realloc(parser, ptr, SIZE_MAX / 2, -1) == NULL); | ||
| 185 | |||
| 186 | - assert_true(*((size_t *)ptr - 1) == 10); // i.e. unchanged | ||
| 187 | + assert_true(sizeRecordedFor(ptr) == 10); // i.e. unchanged | ||
| 188 | |||
| 189 | ptr = expat_realloc(parser, ptr, 20, -1); | ||
| 190 | |||
| 191 | assert_true(ptr != NULL); | ||
| 192 | - assert_true(*((size_t *)ptr - 1) == 20); | ||
| 193 | + assert_true(sizeRecordedFor(ptr) == 20); | ||
| 194 | |||
| 195 | expat_free(parser, ptr, -1); | ||
| 196 | #endif | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-22.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-22.patch new file mode 100644 index 0000000000..9716be8084 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-22.patch | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | From 5cc0010ad93868ec03248e4ac814272bc7d607bc Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Fri, 19 Sep 2025 22:50:54 +0200 | ||
| 4 | Subject: [PATCH] tests: Fix test guard for test related to allocation tracking | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/5cc0010ad93868ec03248e4ac814272bc7d607bc] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | tests/alloc_tests.c | 14 ++++++-------- | ||
| 11 | 1 file changed, 6 insertions(+), 8 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/tests/alloc_tests.c b/tests/alloc_tests.c | ||
| 14 | index dabdf0da..045447b0 100644 | ||
| 15 | --- a/tests/alloc_tests.c | ||
| 16 | +++ b/tests/alloc_tests.c | ||
| 17 | @@ -2362,14 +2362,12 @@ make_alloc_test_case(Suite *s) { | ||
| 18 | tcase_add_test__ifdef_xml_dtd( | ||
| 19 | tc_alloc, test_alloc_reset_after_external_entity_parser_create_fail); | ||
| 20 | |||
| 21 | - tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_size_recorded); | ||
| 22 | - tcase_add_test__ifdef_xml_dtd(tc_alloc, | ||
| 23 | - test_alloc_tracker_maximum_amplification); | ||
| 24 | - tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_threshold); | ||
| 25 | - tcase_add_test__ifdef_xml_dtd(tc_alloc, | ||
| 26 | - test_alloc_tracker_getbuffer_unlimited); | ||
| 27 | - tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_api); | ||
| 28 | + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_size_recorded); | ||
| 29 | + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_maximum_amplification); | ||
| 30 | + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_threshold); | ||
| 31 | + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_getbuffer_unlimited); | ||
| 32 | + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_api); | ||
| 33 | |||
| 34 | tcase_add_test(tc_alloc, test_mem_api_cycle); | ||
| 35 | - tcase_add_test__ifdef_xml_dtd(tc_alloc, test_mem_api_unlimited); | ||
| 36 | + tcase_add_test__if_xml_ge(tc_alloc, test_mem_api_unlimited); | ||
| 37 | } | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-23.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-23.patch new file mode 100644 index 0000000000..60327df22b --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-23.patch | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | From 343594dc344e543acb7478d1283b50b299a1c110 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Fri, 19 Sep 2025 22:46:01 +0200 | ||
| 4 | Subject: [PATCH] tests: Add new test test_alloc_tracker_pointer_alignment | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/343594dc344e543acb7478d1283b50b299a1c110] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | tests/alloc_tests.c | 17 +++++++++++++++++ | ||
| 11 | 1 file changed, 17 insertions(+) | ||
| 12 | |||
| 13 | diff --git a/tests/alloc_tests.c b/tests/alloc_tests.c | ||
| 14 | index 045447b0..5ae6c6a7 100644 | ||
| 15 | --- a/tests/alloc_tests.c | ||
| 16 | +++ b/tests/alloc_tests.c | ||
| 17 | @@ -2132,6 +2132,22 @@ START_TEST(test_alloc_tracker_size_recorded) { | ||
| 18 | } | ||
| 19 | END_TEST | ||
| 20 | |||
| 21 | +START_TEST(test_alloc_tracker_pointer_alignment) { | ||
| 22 | + XML_Parser parser = XML_ParserCreate(NULL); | ||
| 23 | +#if XML_GE == 1 | ||
| 24 | + assert_true(sizeof(long long) >= sizeof(size_t)); // self-test | ||
| 25 | + long long *const ptr | ||
| 26 | + = (long long *)expat_malloc(parser, 4 * sizeof(long long), -1); | ||
| 27 | + ptr[0] = 0LL; | ||
| 28 | + ptr[1] = 1LL; | ||
| 29 | + ptr[2] = 2LL; | ||
| 30 | + ptr[3] = 3LL; | ||
| 31 | + expat_free(parser, ptr, -1); | ||
| 32 | +#endif | ||
| 33 | + XML_ParserFree(parser); | ||
| 34 | +} | ||
| 35 | +END_TEST | ||
| 36 | + | ||
| 37 | START_TEST(test_alloc_tracker_maximum_amplification) { | ||
| 38 | if (g_reparseDeferralEnabledDefault == XML_TRUE) { | ||
| 39 | return; | ||
| 40 | @@ -2363,6 +2379,7 @@ make_alloc_test_case(Suite *s) { | ||
| 41 | tc_alloc, test_alloc_reset_after_external_entity_parser_create_fail); | ||
| 42 | |||
| 43 | tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_size_recorded); | ||
| 44 | + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_pointer_alignment); | ||
| 45 | tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_maximum_amplification); | ||
| 46 | tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_threshold); | ||
| 47 | tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_getbuffer_unlimited); | ||
diff --git a/meta/recipes-core/expat/expat/CVE-2025-59375-24.patch b/meta/recipes-core/expat/expat/CVE-2025-59375-24.patch new file mode 100644 index 0000000000..e51b2bb327 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2025-59375-24.patch | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | From 6fe5df59a1229ca647d365a0e3a7e17fee4d4548 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Sebastian Pipping <sebastian@pipping.org> | ||
| 3 | Date: Fri, 19 Sep 2025 23:49:18 +0200 | ||
| 4 | Subject: [PATCH] Changes: Document pull request #1047 | ||
| 5 | |||
| 6 | CVE: CVE-2025-59375 | ||
| 7 | Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/6fe5df59a1229ca647d365a0e3a7e17fee4d4548] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | Changes | 5 +++++ | ||
| 11 | 1 file changed, 5 insertions(+) | ||
| 12 | |||
| 13 | diff --git a/Changes b/Changes | ||
| 14 | index 706a4ae1..58c222d9 100644 | ||
| 15 | --- a/Changes | ||
| 16 | +++ b/Changes | ||
| 17 | @@ -61,6 +61,9 @@ Patches: | ||
| 18 | to the pull request URL could be of help. | ||
| 19 | |||
| 20 | Bug fixes: | ||
| 21 | + #1046 #1047 Fix alignment of internal allocations for some non-amd64 | ||
| 22 | + architectures (e.g. sparc32); fixes up on the fix to | ||
| 23 | + CVE-2025-59375 in release 2.7.2 from #1034 | ||
| 24 | #980 #989 Restore event pointer behavior from Expat 2.6.4 | ||
| 25 | (that the fix to CVE-2024-8176 changed in 2.7.0); | ||
| 26 | affected API functions are: | ||
| 27 | @@ -76,7 +79,9 @@ Patches: | ||
| 28 | |||
| 29 | Special thanks to: | ||
| 30 | Berkay Eren Ürün | ||
| 31 | + Rolf Eike Beer | ||
| 32 | and | ||
| 33 | + Clang/GCC UndefinedBehaviorSanitizer | ||
| 34 | Perl XML::Parser | ||
| 35 | |||
| 36 | Security fixes: | ||
diff --git a/meta/recipes-core/expat/expat_2.6.4.bb b/meta/recipes-core/expat/expat_2.6.4.bb index 816beaa8a3..1d2d818ecf 100644 --- a/meta/recipes-core/expat/expat_2.6.4.bb +++ b/meta/recipes-core/expat/expat_2.6.4.bb | |||
| @@ -16,6 +16,31 @@ SRC_URI = "${GITHUB_BASE_URI}/download/R_${VERSION_TAG}/expat-${PV}.tar.bz2 \ | |||
| 16 | file://CVE-2024-8176-03.patch \ | 16 | file://CVE-2024-8176-03.patch \ |
| 17 | file://CVE-2024-8176-04.patch \ | 17 | file://CVE-2024-8176-04.patch \ |
| 18 | file://CVE-2024-8176-05.patch \ | 18 | file://CVE-2024-8176-05.patch \ |
| 19 | file://CVE-2025-59375-00.patch \ | ||
| 20 | file://CVE-2025-59375-01.patch \ | ||
| 21 | file://CVE-2025-59375-02.patch \ | ||
| 22 | file://CVE-2025-59375-03.patch \ | ||
| 23 | file://CVE-2025-59375-04.patch \ | ||
| 24 | file://CVE-2025-59375-05.patch \ | ||
| 25 | file://CVE-2025-59375-06.patch \ | ||
| 26 | file://CVE-2025-59375-07.patch \ | ||
| 27 | file://CVE-2025-59375-08.patch \ | ||
| 28 | file://CVE-2025-59375-09.patch \ | ||
| 29 | file://CVE-2025-59375-10.patch \ | ||
| 30 | file://CVE-2025-59375-11.patch \ | ||
| 31 | file://CVE-2025-59375-12.patch \ | ||
| 32 | file://CVE-2025-59375-13.patch \ | ||
| 33 | file://CVE-2025-59375-14.patch \ | ||
| 34 | file://CVE-2025-59375-15.patch \ | ||
| 35 | file://CVE-2025-59375-16.patch \ | ||
| 36 | file://CVE-2025-59375-17.patch \ | ||
| 37 | file://CVE-2025-59375-18.patch \ | ||
| 38 | file://CVE-2025-59375-19.patch \ | ||
| 39 | file://CVE-2025-59375-20.patch \ | ||
| 40 | file://CVE-2025-59375-21.patch \ | ||
| 41 | file://CVE-2025-59375-22.patch \ | ||
| 42 | file://CVE-2025-59375-23.patch \ | ||
| 43 | file://CVE-2025-59375-24.patch \ | ||
| 19 | " | 44 | " |
| 20 | 45 | ||
| 21 | GITHUB_BASE_URI = "https://github.com/libexpat/libexpat/releases/" | 46 | GITHUB_BASE_URI = "https://github.com/libexpat/libexpat/releases/" |
