Compare commits

..

No commits in common. "c8" and "c9s-CVE-2025-59375" have entirely different histories.

19 changed files with 243 additions and 2590 deletions

View File

@ -1 +0,0 @@
03d9882ede56aa48919fbf50fe17614630257a82 SOURCES/expat-2.5.0.tar.gz

1
.fmf/version Normal file
View File

@ -0,0 +1 @@
1

24
.gitignore vendored
View File

@ -1 +1,23 @@
SOURCES/expat-2.5.0.tar.gz
expat-1.95.8.tar.gz
i386
*.rpm
clog
expat-2.0.1.tar.gz
/results_expat
/expat-2.?.?
/expat-2.1.0.tar.gz
/expat-2.1.1.tar.bz2
/expat-2.2.0.tar.bz2
/expat-2.2.1.tar.gz
/expat-2.2.2.tar.gz
/libexpat-R_*
/expat-2.2.3.tar.gz
/expat-2.2.4.tar.gz
/expat-2.2.5.tar.gz
/expat-2.2.6.tar.gz
/expat-2.2.7.tar.gz
/expat-2.2.8.tar.gz
/expat-2.2.10.tar.gz
/expat-2.4.7.tar.gz
/expat-2.4.9.tar.gz
/expat-2.5.0.tar.gz

View File

@ -1,635 +0,0 @@
From 88e9daef8fdaea58da12044cd16f5c9c1f201bfa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Fri, 13 Mar 2026 13:26:45 +0100
Subject: [PATCH 1/6] Make "counting_start_element_handler" count default attrs
---
expat/tests/runtests.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c
index 4a0a2e3f..c66656e0 100644
--- a/expat/tests/runtests.c
+++ b/expat/tests/runtests.c
@@ -3045,6 +3045,7 @@ typedef struct attrInfo {
typedef struct elementInfo {
const XML_Char *name;
int attr_count;
+ int default_attr_count;
const XML_Char *id_name;
AttrInfo *attributes;
} ElementInfo;
@@ -3089,7 +3090,7 @@ counting_start_element_handler(void *userData, const XML_Char *name,
fail("ID does not have the correct name");
return;
}
- for (i = 0; i < info->attr_count; i++) {
+ for (i = 0; i < info->attr_count + info->default_attr_count; i++) {
attr = info->attributes;
while (attr->name != NULL) {
if (! xcstrcmp(atts[0], attr->name))
@@ -3122,9 +3123,9 @@ START_TEST(test_attributes) {
{XCS("id"), XCS("one")},
{NULL, NULL}};
AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}};
- ElementInfo info[] = {{XCS("doc"), 3, XCS("id"), NULL},
- {XCS("tag"), 1, NULL, NULL},
- {NULL, 0, NULL, NULL}};
+ ElementInfo info[] = {{XCS("doc"), 3, 0, XCS("id"), NULL},
+ {XCS("tag"), 1, 0, NULL, NULL},
+ {NULL, 0, 0, NULL, NULL}};
info[0].attributes = doc_info;
info[1].attributes = tag_info;
@@ -7111,7 +7112,7 @@ START_TEST(test_deep_nested_attribute_entity) {
(long unsigned)(N_LINES - 1));
AttrInfo doc_info[] = {{XCS("name"), XCS("deepText")}, {NULL, NULL}};
- ElementInfo info[] = {{XCS("foo"), 1, NULL, NULL}, {NULL, 0, NULL, NULL}};
+ ElementInfo info[] = {{XCS("foo"), 1, 0, NULL, NULL}, {NULL, 0, 0, NULL, NULL}};
info[0].attributes = doc_info;
XML_SetStartElementHandler(g_parser, counting_start_element_handler);
--
2.52.0
From 04796d5b0e71cc37a4bfa0031270d7bee6e0128a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Fri, 13 Mar 2026 13:27:31 +0100
Subject: [PATCH 2/6] test(attlist): Cover duplicate attribute names
Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
---
expat/tests/runtests.c | 315 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 302 insertions(+), 13 deletions(-)
diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c
index c66656e0..13583e0a 100644
--- a/expat/tests/runtests.c
+++ b/expat/tests/runtests.c
@@ -3059,7 +3059,9 @@ typedef struct StructParserAndElementInfo {
static void XMLCALL
counting_start_element_handler(void *userData, const XML_Char *name,
const XML_Char **atts) {
- ElementInfo *info = (ElementInfo *)userData;
+ ParserAndElementInfo *const parserAndElementInfos
+ = (ParserAndElementInfo *)userData;
+ ElementInfo *info = parserAndElementInfos->info;
AttrInfo *attr;
int count, id, i;
@@ -3076,17 +3078,17 @@ counting_start_element_handler(void *userData, const XML_Char *name,
* is possibly a little unexpected, but it is what the
* documentation in expat.h tells us to expect.
*/
- count = XML_GetSpecifiedAttributeCount(g_parser);
+ count = XML_GetSpecifiedAttributeCount(parserAndElementInfos->parser);
if (info->attr_count * 2 != count) {
fail("Not got expected attribute count");
return;
}
- id = XML_GetIdAttributeIndex(g_parser);
+ id = XML_GetIdAttributeIndex(parserAndElementInfos->parser);
if (id == -1 && info->id_name != NULL) {
fail("ID not present");
return;
}
- if (id != -1 && xcstrcmp(atts[id], info->id_name)) {
+ if (id != -1 && xcstrcmp(atts[id], info->id_name) != 0) {
fail("ID does not have the correct name");
return;
}
@@ -3101,7 +3103,7 @@ counting_start_element_handler(void *userData, const XML_Char *name,
fail("Attribute not recognised");
return;
}
- if (xcstrcmp(atts[1], attr->value)) {
+ if (xcstrcmp(atts[1], attr->value) != 0) {
fail("Attribute has wrong value");
return;
}
@@ -3123,20 +3125,296 @@ START_TEST(test_attributes) {
{XCS("id"), XCS("one")},
{NULL, NULL}};
AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}};
- ElementInfo info[] = {{XCS("doc"), 3, 0, XCS("id"), NULL},
- {XCS("tag"), 1, 0, NULL, NULL},
+ ElementInfo info[] = {{XCS("doc"), 3, 0, XCS("id"), doc_info},
+ {XCS("tag"), 1, 0, NULL, tag_info},
{NULL, 0, 0, NULL, NULL}};
- info[0].attributes = doc_info;
- info[1].attributes = tag_info;
+
+ ParserAndElementInfo parserAndElementInfos = {
+ g_parser,
+ info,
+ };
XML_SetStartElementHandler(g_parser, counting_start_element_handler);
- XML_SetUserData(g_parser, info);
+ XML_SetUserData(g_parser, &parserAndElementInfos);
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(g_parser);
}
END_TEST
+START_TEST(test_duplicate_cdata_attribute) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one definition is provided for the same attribute of a given
+ element type, the first declaration is binding and later declarations are
+ ignored.
+ */
+
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc attribute CDATA 'expected' attribute CDATA 'ignored'>\n"
+ "]>\n"
+ "<doc/>\n";
+ AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected")}, {NULL, NULL}};
+ ElementInfo info[]
+ = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_id_attribute_1) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one definition is provided for the same attribute of a given
+ element type, the first declaration is binding and later declarations are
+ ignored.
+ */
+
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc identifier CDATA 'expected' identifier ID #REQUIRED>\n"
+ "]>\n"
+ "<doc/>\n";
+ AttrInfo doc_info[] = {{XCS("identifier"), XCS("expected")}, {NULL, NULL}};
+ ElementInfo info[]
+ = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_id_attribute_2) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one definition is provided for the same attribute of a given
+ element type, the first declaration is binding and later declarations are
+ ignored.
+ */
+
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc identifier ID #REQUIRED identifier CDATA 'unexpected'>\n"
+ "]>\n"
+ "<doc/>\n";
+ AttrInfo doc_info[] = {{NULL, NULL}};
+
+ ElementInfo info[]
+ = {{XCS("doc"), 0, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one AttlistDecl is provided for a given element type,
+ the contents of all those provided are merged.
+ */
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc attribute CDATA 'expected'>\n"
+ " <!ATTLIST doc attribute CDATA 'ignored'>\n"
+ "]>\n"
+ "<doc/>\n";
+ AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected")}, {NULL, NULL}};
+ ElementInfo info[]
+ = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_2) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one AttlistDecl is provided for a given element type,
+ the contents of all those provided are merged.
+ */
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc attribute CDATA 'expected_doc'>\n"
+ " <!ATTLIST tag attribute CDATA 'expected_tag'>\n"
+ " <!ATTLIST doc attribute CDATA 'ignored_doc'>\n"
+ "]>\n"
+ "<doc><tag></tag></doc>\n";
+ AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected_doc")}, {NULL, NULL}};
+ AttrInfo tag_info[] = {{XCS("attribute"), XCS("expected_tag")}, {NULL, NULL}};
+ ElementInfo info[] = {{XCS("doc"), 0, 1, NULL, doc_info},
+ {XCS("tag"), 0, 1, NULL, tag_info},
+ {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_3) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one AttlistDecl is provided for a given element type,
+ the contents of all those provided are merged.
+ */
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc attribute CDATA 'expected_doc'>\n"
+ " <!ATTLIST tag attribute CDATA 'expected_tag'>\n"
+ " <!ATTLIST doc second_attribute CDATA 'second_expected_doc' attribute CDATA 'ignored_doc'>\n"
+ "]>\n"
+ "<doc><tag></tag></doc>\n";
+ AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected_doc")},
+ {XCS("second_attribute"), XCS("second_expected_doc")},
+ {NULL, NULL}};
+ AttrInfo tag_info[] = {{XCS("attribute"), XCS("expected_tag")}, {NULL, NULL}};
+ ElementInfo info[] = {{XCS("doc"), 0, 2, NULL, doc_info},
+ {XCS("tag"), 0, 1, NULL, tag_info},
+ {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_id_attribute_multiple_attlistdecl) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one AttlistDecl is provided for a given element type,
+ the contents of all those provided are merged.
+ */
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc identifier ID #REQUIRED>\n"
+ " <!ATTLIST tag identifier CDATA 'identifier_tag'>\n"
+ " <!ATTLIST doc identifier CDATA 'ignored'>\n"
+ "]>\n"
+ "<doc identifier='doc_identity'><tag></tag></doc>\n";
+ AttrInfo doc_info[]
+ = {{XCS("identifier"), XCS("doc_identity")}, {NULL, NULL}};
+ AttrInfo tag_info[]
+ = {{XCS("identifier"), XCS("identifier_tag")}, {NULL, NULL}};
+ ElementInfo info[] = {{XCS("doc"), 1, 0, XCS("identifier"), doc_info},
+ {XCS("tag"), 0, 1, NULL, tag_info},
+ {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
/* Test reset works correctly in the middle of processing an internal
* entity. Exercises some obscure code in XML_ParserReset().
*/
@@ -7112,11 +7390,13 @@ START_TEST(test_deep_nested_attribute_entity) {
(long unsigned)(N_LINES - 1));
AttrInfo doc_info[] = {{XCS("name"), XCS("deepText")}, {NULL, NULL}};
- ElementInfo info[] = {{XCS("foo"), 1, 0, NULL, NULL}, {NULL, 0, 0, NULL, NULL}};
- info[0].attributes = doc_info;
+ ElementInfo info[]
+ = {{XCS("foo"), 1, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
+
+ ParserAndElementInfo parserAndElementInfos = {g_parser, info};
XML_SetStartElementHandler(g_parser, counting_start_element_handler);
- XML_SetUserData(g_parser, &info);
+ XML_SetUserData(g_parser, &parserAndElementInfos);
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
@@ -13625,6 +13905,15 @@ make_suite(void) {
tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_foreign_dtd);
tcase_add_test(tc_basic, test_set_base);
tcase_add_test(tc_basic, test_attributes);
+ tcase_add_test(tc_basic, test_duplicate_cdata_attribute);
+ tcase_add_test(tc_basic, test_duplicate_id_attribute_1);
+ tcase_add_test(tc_basic, test_duplicate_id_attribute_2);
+ tcase_add_test(tc_basic, test_duplicate_cdata_attribute_multiple_attlistdecl);
+ tcase_add_test(tc_basic,
+ test_duplicate_cdata_attribute_multiple_attlistdecl_2);
+ tcase_add_test(tc_basic,
+ test_duplicate_cdata_attribute_multiple_attlistdecl_3);
+ tcase_add_test(tc_basic, test_duplicate_id_attribute_multiple_attlistdecl);
tcase_add_test(tc_basic, test_reset_in_entity);
tcase_add_test(tc_basic, test_resume_invalid_parse);
tcase_add_test(tc_basic, test_resume_resuspended);
--
2.52.0
From 58d4b742fd88c9789e4a5e68de02164145f9c593 Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Mon, 13 Apr 2026 01:34:03 +0200
Subject: [PATCH 3/6] tests: Make counting_start_element_handler enforce
complete attribute lists
---
expat/tests/runtests.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c
index 13583e0a..659ed030 100644
--- a/expat/tests/runtests.c
+++ b/expat/tests/runtests.c
@@ -3110,6 +3110,9 @@ counting_start_element_handler(void *userData, const XML_Char *name,
/* Remember, two entries in atts per attribute (see above) */
atts += 2;
}
+
+ // Self-test that the test case's list of expected attributes is complete
+ assert_true(atts[0] == NULL);
}
START_TEST(test_attributes) {
--
2.52.0
From 2f13a612e82242af9954508240c6edfaf7cb0721 Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Sun, 8 Mar 2026 22:14:41 +0100
Subject: [PATCH 4/6] lib: Extract a constant for upcoming reuse
---
expat/lib/xmlparse.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index cba41f4b..ac9512e9 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -7528,8 +7528,9 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
oldE->prefix->name, 0);
for (i = 0; i < newE->nDefaultAtts; i++) {
+ const XML_Char *const attributeName = oldE->defaultAtts[i].id->name;
newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup(
- oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
+ oldParser, &(newDtd->attributeIds), attributeName, 0);
newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
if (oldE->defaultAtts[i].value) {
newE->defaultAtts[i].value
--
2.52.0
From 8211c5affe00c6d92025f34ae7ffbc0f78426692 Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Sun, 8 Mar 2026 23:05:49 +0100
Subject: [PATCH 5/6] lib: Introduce ELEMENT_TYPE.defaultAttsNames
---
expat/lib/xmlparse.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index ac9512e9..d8e7335d 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -368,6 +368,7 @@ typedef struct {
int nDefaultAtts;
int allocDefaultAtts;
DEFAULT_ATTRIBUTE *defaultAtts;
+ HASH_TABLE defaultAttsNames;
} ELEMENT_TYPE;
typedef struct {
@@ -3756,6 +3757,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
sizeof(ELEMENT_TYPE));
if (! elementType)
return XML_ERROR_NO_MEMORY;
+ if (! elementType->defaultAttsNames.parser)
+ hashTableInit(&(elementType->defaultAttsNames), parser);
if (parser->m_ns && ! setElementTypePrefix(parser, elementType))
return XML_ERROR_NO_MEMORY;
}
@@ -7369,6 +7372,7 @@ dtdReset(DTD *p, XML_Parser parser) {
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
if (! e)
break;
+ hashTableDestroy(&(e->defaultAttsNames));
if (e->allocDefaultAtts != 0)
FREE(parser, e->defaultAtts);
}
@@ -7410,6 +7414,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser) {
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
if (! e)
break;
+ hashTableDestroy(&(e->defaultAttsNames));
if (e->allocDefaultAtts != 0)
FREE(parser, e->defaultAtts);
}
@@ -7503,6 +7508,10 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
sizeof(ELEMENT_TYPE));
if (! newE)
return 0;
+
+ if (! newE->defaultAttsNames.parser)
+ hashTableInit(&(newE->defaultAttsNames), parser);
+
if (oldE->nDefaultAtts) {
/* Detect and prevent integer overflow.
* The preprocessor guard addresses the "always false" warning
@@ -7539,6 +7548,12 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
return 0;
} else
newE->defaultAtts[i].value = NULL;
+
+ NAMED *const nameAddedOrFound = (NAMED *)lookup(
+ parser, &(newE->defaultAttsNames), attributeName, sizeof(NAMED));
+ if (! nameAddedOrFound) {
+ return 0;
+ }
}
}
@@ -8263,6 +8278,8 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
sizeof(ELEMENT_TYPE));
if (! ret)
return NULL;
+ if (! ret->defaultAttsNames.parser)
+ hashTableInit(&(ret->defaultAttsNames), getRootParserOf(parser, NULL));
if (ret->name != name)
poolDiscard(&dtd->pool);
else {
--
2.52.0
From 756dfc0850eb52005366da45859b1bb80a80466e Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Sun, 8 Mar 2026 23:06:29 +0100
Subject: [PATCH 6/6] lib: Leverage ELEMENT_TYPE.defaultAttsNames for attribute
collision detection
.. to resolve quadratic runtime behavior
---
expat/lib/xmlparse.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index d8e7335d..d7d815e8 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -7009,10 +7009,10 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
if (value || isId) {
/* The handling of default attributes gets messed up if we have
a default which duplicates a non-default. */
- int i;
- for (i = 0; i < type->nDefaultAtts; i++)
- if (attId == type->defaultAtts[i].id)
- return 1;
+ NAMED *const nameFound
+ = (NAMED *)lookup(parser, &(type->defaultAttsNames), attId->name, 0);
+ if (nameFound)
+ return 1;
if (isId && ! type->idAtt && ! attId->xmlns)
type->idAtt = attId;
}
@@ -7059,6 +7059,12 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
att->isCdata = isCdata;
if (! isCdata)
attId->maybeTokenized = XML_TRUE;
+
+ NAMED *const nameAddedOrFound = (NAMED *)lookup(
+ parser, &(type->defaultAttsNames), attId->name, sizeof(NAMED));
+ if (! nameAddedOrFound)
+ return 0;
+
type->nDefaultAtts += 1;
return 1;
}
--
2.52.0

File diff suppressed because it is too large Load Diff

View File

@ -1,288 +0,0 @@
From b5b73d23072fd277b3816b45c027238260467947 Mon Sep 17 00:00:00 2001
From: Matthew Fernandez <matthew.fernandez@gmail.com>
Date: Thu, 4 Jun 2026 17:01:02 -0700
Subject: [PATCH 1/5] lib: Remove reuse of `m_groupSize` to count
`m_scaffIndex` allocation
The sizes of the two arrays `m_groupConnector` and `scaffIndex` need to
vary independently. This change is a step towards allowing this.
Anthropic: ANT-2026-00037
Anthropic: ANT-2026-03621
Anthropic: ANT-2026-03867
Co-authored-by: Alessandro Gario <alessandro.gario@trailofbits.com>
---
expat/lib/xmlparse.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index d7d815e8..3b5e90b1 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -398,6 +398,7 @@ typedef struct {
unsigned scaffCount;
int scaffLevel;
int *scaffIndex;
+ size_t scaffIndexSize;
} DTD;
enum EntityType {
@@ -5812,6 +5813,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
if (new_scaff_index == NULL)
return XML_ERROR_NO_MEMORY;
dtd->scaffIndex = new_scaff_index;
+ dtd->scaffIndexSize = parser->m_groupSize;
}
} else {
parser->m_groupConnector
@@ -7358,6 +7360,7 @@ dtdCreate(XML_Parser parser) {
p->in_eldecl = XML_FALSE;
p->scaffIndex = NULL;
+ p->scaffIndexSize = 0;
p->scaffold = NULL;
p->scaffLevel = 0;
p->scaffSize = 0;
@@ -7399,6 +7402,7 @@ dtdReset(DTD *p, XML_Parser parser) {
FREE(parser, p->scaffIndex);
p->scaffIndex = NULL;
+ p->scaffIndexSize = 0;
FREE(parser, p->scaffold);
p->scaffold = NULL;
@@ -7586,6 +7590,7 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
newDtd->scaffSize = oldDtd->scaffSize;
newDtd->scaffLevel = oldDtd->scaffLevel;
newDtd->scaffIndex = oldDtd->scaffIndex;
+ newDtd->scaffIndexSize = oldDtd->scaffIndexSize;
return 1;
} /* End dtdCopy */
@@ -8090,6 +8095,7 @@ nextScaffoldPart(XML_Parser parser) {
dtd->scaffIndex = (int *)MALLOC(parser, parser->m_groupSize * sizeof(int));
if (! dtd->scaffIndex)
return -1;
+ dtd->scaffIndexSize = parser->m_groupSize;
dtd->scaffIndex[0] = 0;
}
From af2f86e32624be829ddc0ce7168d18f921bdef4e Mon Sep 17 00:00:00 2001
From: Matthew Fernandez <matthew.fernandez@gmail.com>
Date: Thu, 4 Jun 2026 17:01:02 -0700
Subject: [PATCH 2/5] lib: doProlog: Fix out-of-bound scaffolding index store
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The scaffold backing array is reallocated using the caller parsers
per-parser `m_groupSize`, but the DTD struct (which carries
`scaffIndex`) is shared between a parent parser and any external
parameter-entity sub-parser created via
`XML_ExternalEntityParserCreate(parent, NULL, …)`. A sub-parser whose
group nesting is shallower than the parents can `REALLOC` the shared
`scaffIndex` down to its own size; when the parent resumes and parses a
deeper element content model, its bounds check passes (its private
`m_groupSize` is still large enough), the doubling-grow path is skipped,
and the next write lands past the shrunken buffer.
Anthropic: ANT-2026-00037
Anthropic: ANT-2026-03621
Anthropic: ANT-2026-03867
Co-authored-by: Alessandro Gario <alessandro.gario@trailofbits.com>
Reported-by: Trail of Bits, in collaboration with Anthropic
---
expat/lib/xmlparse.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index 3b5e90b1..317b08e0 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -5830,6 +5830,21 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
if (myindex < 0)
return XML_ERROR_NO_MEMORY;
assert(dtd->scaffIndex != NULL);
+ if ((size_t)dtd->scaffLevel >= dtd->scaffIndexSize) {
+ /* Detect and prevent integer overflow */
+ if (dtd->scaffIndexSize > SIZE_MAX / 2 / sizeof(int)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+ assert(dtd->scaffIndexSize > 0);
+ const size_t new_size = dtd->scaffIndexSize * 2;
+ int *const new_scaff_index
+ = REALLOC(parser, dtd->scaffIndex, new_size * sizeof(int));
+ if (new_scaff_index == NULL) {
+ return XML_ERROR_NO_MEMORY;
+ }
+ dtd->scaffIndex = new_scaff_index;
+ dtd->scaffIndexSize = new_size;
+ }
dtd->scaffIndex[dtd->scaffLevel] = myindex;
dtd->scaffLevel++;
dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
From 8b1debf703fadb5e11074f98f33a8bd10b561f3e Mon Sep 17 00:00:00 2001
From: Matthew Fernandez <matthew.fernandez@gmail.com>
Date: Thu, 4 Jun 2026 17:01:02 -0700
Subject: [PATCH 3/5] tests: Add a test case for scaffolding array limits in
shared DTDs
This test case provokes the bug fixed in the previous commit.
Anthropic: ANT-2026-00037
Anthropic: ANT-2026-03621
Anthropic: ANT-2026-03867
Co-authored-by: Alessandro Gario <alessandro.gario@trailofbits.com>
Reported-by: Trail of Bits, in collaboration with Anthropic
---
expat/tests/runtests.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c
index 659ed030..c760733d 100644
--- a/expat/tests/runtests.c
+++ b/expat/tests/runtests.c
@@ -5681,6 +5681,34 @@ START_TEST(test_skipped_external_entity) {
}
END_TEST
+START_TEST(test_scaff_index_shared_across_external_entity_parser) {
+ const char text[]
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT a "
+ "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((b))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>\n"
+ "<!ENTITY % e SYSTEM 'ext'>\n"
+ "%e;\n"
+ "<!ELEMENT c "
+ "(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((d)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>\n"
+ "]>\n"
+ "<doc/>";
+ ExtOption options[]
+ = {{XCS("ext"),
+ "<!ELEMENT x "
+ "((((((((((((((((((((((((((((((((y))))))))))))))))))))))))))))))))>"},
+ {NULL, NULL}};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, options);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
/* Test a different form of unknown external entity */
typedef struct ext_hdlr_data {
const char *parse_text;
@@ -13988,6 +14016,8 @@ make_suite(void) {
tcase_add_test(tc_basic, test_trailing_cr_in_att_value);
tcase_add_test(tc_basic, test_standalone_internal_entity);
tcase_add_test(tc_basic, test_skipped_external_entity);
+ tcase_add_test__ifdef_xml_dtd(
+ tc_basic, test_scaff_index_shared_across_external_entity_parser);
tcase_add_test(tc_basic, test_skipped_null_loaded_ext_entity);
tcase_add_test(tc_basic, test_skipped_unloaded_ext_entity);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_param_entity_with_trailing_cr);
From 4ab78126be566310e293adef807a9b919e90f8df Mon Sep 17 00:00:00 2001
From: Matthew Fernandez <matthew.fernandez@gmail.com>
Date: Thu, 4 Jun 2026 17:01:02 -0700
Subject: [PATCH 4/5] lib: Remove unnecessary `scaffIndex` expansion
Following the previous changes, all locations that append entries to
`scaffIndex` handle expanding the array if it is not already large
enough. So this extra expansion code is no longer necessary. In some
cases such as processing siblings with alternating scaffolding counts,
this logic would actually _shrink_ the array only to then later
re-expand it.
Anthropic: ANT-2026-00037
Anthropic: ANT-2026-03621
Anthropic: ANT-2026-03867
Co-authored-by: Alessandro Gario <alessandro.gario@trailofbits.com>
---
expat/lib/xmlparse.c | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index 317b08e0..80fcb968 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -5797,24 +5797,6 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
parser->m_groupConnector = new_connector;
}
- if (dtd->scaffIndex) {
- /* Detect and prevent integer overflow.
- * The preprocessor guard addresses the "always false" warning
- * from -Wtype-limits on platforms where
- * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
-#if UINT_MAX >= SIZE_MAX
- if (parser->m_groupSize > (size_t)(-1) / sizeof(int)) {
- return XML_ERROR_NO_MEMORY;
- }
-#endif
-
- int *const new_scaff_index = (int *)REALLOC(
- parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int));
- if (new_scaff_index == NULL)
- return XML_ERROR_NO_MEMORY;
- dtd->scaffIndex = new_scaff_index;
- dtd->scaffIndexSize = parser->m_groupSize;
- }
} else {
parser->m_groupConnector
= (char *)MALLOC(parser, parser->m_groupSize = 32);
From 9a4202e63b9a89e2e1ec14996934ff98697c6721 Mon Sep 17 00:00:00 2001
From: Matthew Fernandez <matthew.fernandez@gmail.com>
Date: Thu, 4 Jun 2026 17:01:02 -0700
Subject: [PATCH 5/5] lib: Remove indented scoping of `new_connector` local
Following the previous change, the lifetime of `new_connector` as
constrained by this introduced scope was identical to the parent scope.
---
expat/lib/xmlparse.c | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index 80fcb968..5c255c00 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -5782,21 +5782,18 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
case XML_ROLE_GROUP_OPEN:
if (parser->m_prologState.level >= parser->m_groupSize) {
if (parser->m_groupSize) {
- {
- /* Detect and prevent integer overflow */
- if (parser->m_groupSize > (unsigned int)(-1) / 2u) {
- return XML_ERROR_NO_MEMORY;
- }
-
- char *const new_connector = (char *)REALLOC(
- parser, parser->m_groupConnector, parser->m_groupSize *= 2);
- if (new_connector == NULL) {
- parser->m_groupSize /= 2;
- return XML_ERROR_NO_MEMORY;
- }
- parser->m_groupConnector = new_connector;
+ /* Detect and prevent integer overflow */
+ if (parser->m_groupSize > (unsigned int)(-1) / 2u) {
+ return XML_ERROR_NO_MEMORY;
}
+ char *const new_connector = (char *)REALLOC(
+ parser, parser->m_groupConnector, parser->m_groupSize *= 2);
+ if (new_connector == NULL) {
+ parser->m_groupSize /= 2;
+ return XML_ERROR_NO_MEMORY;
+ }
+ parser->m_groupConnector = new_connector;
} else {
parser->m_groupConnector
= (char *)MALLOC(parser, parser->m_groupSize = 32);

1
ci.fmf Normal file
View File

@ -0,0 +1 @@
resultsdb-testcase: separate

View File

@ -1,6 +1,6 @@
commit e16f2e3d9c3fa181dcaeed312ea9bc7de8257942
commit a98f5a8fbed712493420fc7d5377f20d7bc6c65a
Author: Tomas Korbar <tkorbar@redhat.com>
Date: Tue Nov 18 13:01:31 2025 +0100
Date: Fri Nov 14 11:06:12 2025 +0100
Fix CVE-2025-59375
@ -235,18 +235,10 @@ index 69b0ba1..6eae1d6 100644
/* Added in Expat 2.6.0. */
diff --git a/expat/lib/internal.h b/expat/lib/internal.h
index e2709c8..1d1e7da 100644
index e2709c8..b1243d5 100644
--- a/expat/lib/internal.h
+++ b/expat/lib/internal.h
@@ -107,6 +107,7 @@
#endif
#include <limits.h> // ULONG_MAX
+#include <stddef.h> // size_t
#if defined(_WIN32) \
&& (! defined(__USE_MINGW_ANSI_STDIO) \
@@ -144,6 +145,16 @@
@@ -144,6 +144,11 @@
100.0f
#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT \
8388608 // 8 MiB, 2^23
@ -254,16 +246,11 @@ index e2709c8..1d1e7da 100644
+#define EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT 100.0f
+#define EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT \
+ 67108864 // 64 MiB, 2^26
+
+// NOTE: If function expat_alloc was user facing, EXPAT_MALLOC_ALIGNMENT would
+// have to take sizeof(long double) into account
+#define EXPAT_MALLOC_ALIGNMENT sizeof(long long) // largest parser (sub)member
+#define EXPAT_MALLOC_PADDING ((EXPAT_MALLOC_ALIGNMENT) - sizeof(size_t))
+
/* NOTE END */
#include "expat.h" // so we can use type XML_Parser below
@@ -163,6 +174,9 @@ const char *unsignedCharToPrintable(unsigned char c);
@@ -163,6 +168,9 @@ const char *unsignedCharToPrintable(unsigned char c);
extern XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c
extern unsigned int g_parseAttempts; // used for testing only
@ -274,7 +261,7 @@ index e2709c8..1d1e7da 100644
#ifdef __cplusplus
}
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index d68d2c8..cba41f4 100644
index d68d2c8..e962048 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -214,7 +214,7 @@ typedef struct {
@ -362,7 +349,7 @@ index d68d2c8..cba41f4 100644
static void parserInit(XML_Parser parser, const XML_Char *encodingName);
@@ -734,14 +739,215 @@ struct XML_ParserStruct {
@@ -734,14 +739,209 @@ struct XML_ParserStruct {
unsigned long m_hash_secret_salt;
#ifdef XML_DTD
ACCOUNTING m_accounting;
@ -429,14 +416,14 @@ index d68d2c8..cba41f4 100644
+
+void *expat_malloc(XML_Parser parser, size_t size, int sourceLine) {
+ // Detect integer overflow
+ if (SIZE_MAX - size < sizeof(size_t) + EXPAT_MALLOC_PADDING) {
+ if (SIZE_MAX - size < sizeof(size_t)) {
+ return NULL;
+ }
+
+ const XML_Parser rootParser = getRootParserOf(parser, NULL);
+ assert(rootParser->m_parentParser == NULL);
+
+ const size_t bytesToAllocate = sizeof(size_t) + EXPAT_MALLOC_PADDING + size;
+ const size_t bytesToAllocate = sizeof(size_t) + size;
+
+ if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated
+ < bytesToAllocate) {
@ -473,7 +460,7 @@ index d68d2c8..cba41f4 100644
+ rootParser->m_alloc_tracker.peakBytesAllocated, sourceLine);
+ }
+
+ return (char *)mallocedPtr + sizeof(size_t) + EXPAT_MALLOC_PADDING;
+ return (char *)mallocedPtr + sizeof(size_t);
+}
+
+void expat_free(XML_Parser parser, void *ptr, int sourceLine) {
@ -488,9 +475,8 @@ index d68d2c8..cba41f4 100644
+
+ // Extract size (to the eyes of malloc_fcn/realloc_fcn) and
+ // the original pointer returned by malloc/realloc
+ void *const mallocedPtr = (char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t);
+ const size_t bytesAllocated
+ = sizeof(size_t) + EXPAT_MALLOC_PADDING + *(size_t *)mallocedPtr;
+ void *const mallocedPtr = (char *)ptr - sizeof(size_t);
+ const size_t bytesAllocated = sizeof(size_t) + *(size_t *)mallocedPtr;
+
+ // Update accounting
+ assert(rootParser->m_alloc_tracker.bytesAllocated >= bytesAllocated);
@ -524,7 +510,7 @@ index d68d2c8..cba41f4 100644
+
+ // Extract original size (to the eyes of the caller) and the original
+ // pointer returned by malloc/realloc
+ void *mallocedPtr = (char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t);
+ void *mallocedPtr = (char *)ptr - sizeof(size_t);
+ const size_t prevSize = *(size_t *)mallocedPtr;
+
+ // Classify upcoming change
@ -539,13 +525,8 @@ index d68d2c8..cba41f4 100644
+ }
+ }
+
+ // NOTE: Integer overflow detection has already been done for us
+ // by expat_heap_increase_tolerable(..) above
+ assert(SIZE_MAX - sizeof(size_t) - EXPAT_MALLOC_PADDING >= size);
+
+ // Actually allocate
+ mallocedPtr = parser->m_mem.realloc_fcn(
+ mallocedPtr, sizeof(size_t) + EXPAT_MALLOC_PADDING + size);
+ mallocedPtr = parser->m_mem.realloc_fcn(mallocedPtr, sizeof(size_t) + size);
+
+ if (mallocedPtr == NULL) {
+ return NULL;
@ -576,12 +557,12 @@ index d68d2c8..cba41f4 100644
+ // Update in-block recorded size
+ *(size_t *)mallocedPtr = size;
+
+ return (char *)mallocedPtr + sizeof(size_t) + EXPAT_MALLOC_PADDING;
+ return (char *)mallocedPtr + sizeof(size_t);
+}
XML_Parser XMLCALL
XML_ParserCreate(const XML_Char *encodingName) {
@@ -1059,19 +1265,34 @@ XML_Parser XMLCALL
@@ -1059,19 +1259,31 @@ XML_Parser XMLCALL
XML_ParserCreate_MM(const XML_Char *encodingName,
const XML_Memory_Handling_Suite *memsuite,
const XML_Char *nameSep) {
@ -597,8 +578,7 @@ index d68d2c8..cba41f4 100644
+ DTD *dtd, XML_Parser parentParser) {
+ XML_Parser parser = NULL;
+
+ const size_t increase
+ = sizeof(size_t) + EXPAT_MALLOC_PADDING + sizeof(struct XML_ParserStruct);
+ const size_t increase = sizeof(size_t) + sizeof(struct XML_ParserStruct);
+
+ if (parentParser != NULL) {
+ const XML_Parser rootParser = getRootParserOf(parentParser, NULL);
@ -611,28 +591,25 @@ index d68d2c8..cba41f4 100644
XML_Memory_Handling_Suite *mtemp;
- parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
- if (parser != NULL) {
+ void *const sizeAndParser
+ = memsuite->malloc_fcn(sizeof(size_t) + EXPAT_MALLOC_PADDING
+ + sizeof(struct XML_ParserStruct));
+ void *const sizeAndParser = memsuite->malloc_fcn(
+ sizeof(size_t) + sizeof(struct XML_ParserStruct));
+ if (sizeAndParser != NULL) {
+ *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct);
+ parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)
+ + EXPAT_MALLOC_PADDING);
+ parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t));
mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
mtemp->malloc_fcn = memsuite->malloc_fcn;
mtemp->realloc_fcn = memsuite->realloc_fcn;
@@ -1079,18 +1300,59 @@ parserCreate(const XML_Char *encodingName,
@@ -1079,18 +1291,58 @@ parserCreate(const XML_Char *encodingName,
}
} else {
XML_Memory_Handling_Suite *mtemp;
- parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
- if (parser != NULL) {
+ void *const sizeAndParser = malloc(sizeof(size_t) + EXPAT_MALLOC_PADDING
+ + sizeof(struct XML_ParserStruct));
+ void *const sizeAndParser
+ = (XML_Parser)malloc(sizeof(size_t) + sizeof(struct XML_ParserStruct));
+ if (sizeAndParser != NULL) {
+ *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct);
+ parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)
+ + EXPAT_MALLOC_PADDING);
+ parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t));
mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
mtemp->malloc_fcn = malloc;
mtemp->realloc_fcn = realloc;
@ -684,7 +661,7 @@ index d68d2c8..cba41f4 100644
parser->m_buffer = NULL;
parser->m_bufferLim = NULL;
@@ -1125,7 +1387,7 @@ parserCreate(const XML_Char *encodingName,
@@ -1125,7 +1377,7 @@ parserCreate(const XML_Char *encodingName,
if (dtd)
parser->m_dtd = dtd;
else {
@ -693,7 +670,7 @@ index d68d2c8..cba41f4 100644
if (parser->m_dtd == NULL) {
FREE(parser, parser->m_dataBuf);
FREE(parser, parser->m_atts);
@@ -1159,8 +1421,8 @@ parserCreate(const XML_Char *encodingName,
@@ -1159,8 +1411,8 @@ parserCreate(const XML_Char *encodingName,
parser->m_protocolEncodingName = NULL;
@ -704,7 +681,7 @@ index d68d2c8..cba41f4 100644
parserInit(parser, encodingName);
if (encodingName && ! parser->m_protocolEncodingName) {
@@ -1192,7 +1454,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
@@ -1192,7 +1444,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
parser->m_processor = prologInitProcessor;
XmlPrologStateInit(&parser->m_prologState);
if (encodingName != NULL) {
@ -713,7 +690,7 @@ index d68d2c8..cba41f4 100644
}
parser->m_curBase = NULL;
XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0);
@@ -1254,7 +1516,6 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
@@ -1254,7 +1506,6 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
parser->m_unknownEncodingMem = NULL;
parser->m_unknownEncodingRelease = NULL;
parser->m_unknownEncodingData = NULL;
@ -721,7 +698,7 @@ index d68d2c8..cba41f4 100644
parser->m_parsingStatus.parsing = XML_INITIALIZED;
// Reentry can only be triggered inside m_processor calls
parser->m_reenter = XML_FALSE;
@@ -1344,7 +1605,7 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
@@ -1344,7 +1595,7 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
FREE(parser, (void *)parser->m_protocolEncodingName);
parser->m_protocolEncodingName = NULL;
parserInit(parser, encodingName);
@ -730,7 +707,7 @@ index d68d2c8..cba41f4 100644
return XML_TRUE;
}
@@ -1380,7 +1641,7 @@ XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) {
@@ -1380,7 +1631,7 @@ XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) {
parser->m_protocolEncodingName = NULL;
else {
/* Copy the new encoding name into allocated memory */
@ -739,7 +716,7 @@ index d68d2c8..cba41f4 100644
if (! parser->m_protocolEncodingName)
return XML_STATUS_ERROR;
}
@@ -1489,9 +1750,10 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
@@ -1489,9 +1740,10 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
*/
if (parser->m_ns) {
XML_Char tmp[2] = {parser->m_namespaceSeparator, 0};
@ -752,7 +729,7 @@ index d68d2c8..cba41f4 100644
}
if (! parser)
@@ -1535,7 +1797,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
@@ -1535,7 +1787,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
parser->m_prologState.inEntityValue = oldInEntityValue;
if (context) {
#endif /* XML_DTD */
@ -761,7 +738,7 @@ index d68d2c8..cba41f4 100644
|| ! setContext(parser, context)) {
XML_ParserFree(parser);
return NULL;
@@ -1647,14 +1909,16 @@ XML_ParserFree(XML_Parser parser) {
@@ -1647,14 +1899,16 @@ XML_ParserFree(XML_Parser parser) {
#else
if (parser->m_dtd)
#endif /* XML_DTD */
@ -781,7 +758,7 @@ index d68d2c8..cba41f4 100644
FREE(parser, parser->m_dataBuf);
FREE(parser, parser->m_nsAtts);
FREE(parser, parser->m_unknownEncodingMem);
@@ -2246,7 +2510,9 @@ XML_GetBuffer(XML_Parser parser, int len) {
@@ -2246,7 +2500,9 @@ XML_GetBuffer(XML_Parser parser, int len) {
parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
@ -792,7 +769,7 @@ index d68d2c8..cba41f4 100644
if (newBuf == 0) {
parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
@@ -2257,7 +2523,10 @@ XML_GetBuffer(XML_Parser parser, int len) {
@@ -2257,7 +2513,10 @@ XML_GetBuffer(XML_Parser parser, int len) {
memcpy(newBuf, &parser->m_bufferPtr[-keep],
EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
+ keep);
@ -804,7 +781,7 @@ index d68d2c8..cba41f4 100644
parser->m_buffer = newBuf;
parser->m_bufferEnd
= parser->m_buffer
@@ -2273,7 +2542,10 @@ XML_GetBuffer(XML_Parser parser, int len) {
@@ -2273,7 +2532,10 @@ XML_GetBuffer(XML_Parser parser, int len) {
if (parser->m_bufferPtr) {
memcpy(newBuf, parser->m_bufferPtr,
EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
@ -816,7 +793,7 @@ index d68d2c8..cba41f4 100644
parser->m_bufferEnd
= newBuf
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
@@ -2451,28 +2723,43 @@ XML_GetCurrentColumnNumber(XML_Parser parser) {
@@ -2451,28 +2713,43 @@ XML_GetCurrentColumnNumber(XML_Parser parser) {
void XMLCALL
XML_FreeContentModel(XML_Parser parser, XML_Content *model) {
@ -866,7 +843,7 @@ index d68d2c8..cba41f4 100644
}
void XMLCALL
@@ -2669,6 +2956,13 @@ XML_GetFeatureList(void) {
@@ -2669,6 +2946,13 @@ XML_GetFeatureList(void) {
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
XML_L("XML_BLAP_ACT_THRES"),
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
@ -880,7 +857,7 @@ index d68d2c8..cba41f4 100644
#endif
{XML_FEATURE_END, NULL, 0}};
@@ -2697,6 +2991,29 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold(
@@ -2697,6 +2981,29 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold(
parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
return XML_TRUE;
}
@ -910,7 +887,7 @@ index d68d2c8..cba41f4 100644
#endif /* XML_DTD */
XML_Bool XMLCALL
@@ -5652,8 +5969,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
@@ -5652,8 +5959,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
case XML_ROLE_CONTENT_EMPTY:
if (dtd->in_eldecl) {
if (parser->m_elementDeclHandler) {
@ -924,7 +901,7 @@ index d68d2c8..cba41f4 100644
if (! content)
return XML_ERROR_NO_MEMORY;
content->quant = XML_CQUANT_NONE;
@@ -7009,19 +7330,19 @@ normalizePublicId(XML_Char *publicId) {
@@ -7009,19 +7320,19 @@ normalizePublicId(XML_Char *publicId) {
}
static DTD *
@ -953,7 +930,7 @@ index d68d2c8..cba41f4 100644
#endif /* XML_DTD */
p->defaultPrefix.name = NULL;
p->defaultPrefix.binding = NULL;
@@ -7041,7 +7362,7 @@ dtdCreate(const XML_Memory_Handling_Suite *ms) {
@@ -7041,7 +7352,7 @@ dtdCreate(const XML_Memory_Handling_Suite *ms) {
}
static void
@ -962,7 +939,7 @@ index d68d2c8..cba41f4 100644
HASH_TABLE_ITER iter;
hashTableIterInit(&iter, &(p->elementTypes));
for (;;) {
@@ -7049,7 +7370,7 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) {
@@ -7049,7 +7360,7 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) {
if (! e)
break;
if (e->allocDefaultAtts != 0)
@ -971,7 +948,7 @@ index d68d2c8..cba41f4 100644
}
hashTableClear(&(p->generalEntities));
#ifdef XML_DTD
@@ -7066,9 +7387,9 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) {
@@ -7066,9 +7377,9 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) {
p->in_eldecl = XML_FALSE;
@ -983,7 +960,7 @@ index d68d2c8..cba41f4 100644
p->scaffold = NULL;
p->scaffLevel = 0;
@@ -7082,7 +7403,7 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) {
@@ -7082,7 +7393,7 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) {
}
static void
@ -992,7 +969,7 @@ index d68d2c8..cba41f4 100644
HASH_TABLE_ITER iter;
hashTableIterInit(&iter, &(p->elementTypes));
for (;;) {
@@ -7090,7 +7411,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) {
@@ -7090,7 +7401,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) {
if (! e)
break;
if (e->allocDefaultAtts != 0)
@ -1001,7 +978,7 @@ index d68d2c8..cba41f4 100644
}
hashTableDestroy(&(p->generalEntities));
#ifdef XML_DTD
@@ -7102,10 +7423,10 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) {
@@ -7102,10 +7413,10 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) {
poolDestroy(&(p->pool));
poolDestroy(&(p->entityValuePool));
if (isDocEntity) {
@ -1015,7 +992,7 @@ index d68d2c8..cba41f4 100644
}
/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise.
@@ -7113,7 +7434,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) {
@@ -7113,7 +7424,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) {
*/
static int
dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
@ -1024,7 +1001,7 @@ index d68d2c8..cba41f4 100644
HASH_TABLE_ITER iter;
/* Copy the prefix table. */
@@ -7194,7 +7515,7 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
@@ -7194,7 +7505,7 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
}
#endif
newE->defaultAtts
@ -1033,7 +1010,7 @@ index d68d2c8..cba41f4 100644
if (! newE->defaultAtts) {
return 0;
}
@@ -7356,7 +7677,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
@@ -7356,7 +7667,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
/* table->size is a power of 2 */
table->size = (size_t)1 << INIT_POWER;
tsize = table->size * sizeof(NAMED *);
@ -1042,7 +1019,7 @@ index d68d2c8..cba41f4 100644
if (! table->v) {
table->size = 0;
return NULL;
@@ -7396,7 +7717,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
@@ -7396,7 +7707,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
}
size_t tsize = newSize * sizeof(NAMED *);
@ -1051,7 +1028,7 @@ index d68d2c8..cba41f4 100644
if (! newV)
return NULL;
memset(newV, 0, tsize);
@@ -7412,7 +7733,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
@@ -7412,7 +7723,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
}
newV[j] = table->v[i];
}
@ -1060,7 +1037,7 @@ index d68d2c8..cba41f4 100644
table->v = newV;
table->power = newPower;
table->size = newSize;
@@ -7425,7 +7746,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
@@ -7425,7 +7736,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
}
}
}
@ -1069,7 +1046,7 @@ index d68d2c8..cba41f4 100644
if (! table->v[i])
return NULL;
memset(table->v[i], 0, createSize);
@@ -7438,7 +7759,7 @@ static void FASTCALL
@@ -7438,7 +7749,7 @@ static void FASTCALL
hashTableClear(HASH_TABLE *table) {
size_t i;
for (i = 0; i < table->size; i++) {
@ -1078,7 +1055,7 @@ index d68d2c8..cba41f4 100644
table->v[i] = NULL;
}
table->used = 0;
@@ -7448,17 +7769,17 @@ static void FASTCALL
@@ -7448,17 +7759,17 @@ static void FASTCALL
hashTableDestroy(HASH_TABLE *table) {
size_t i;
for (i = 0; i < table->size; i++)
@ -1100,7 +1077,7 @@ index d68d2c8..cba41f4 100644
}
static void FASTCALL
@@ -7478,13 +7799,13 @@ hashTableIterNext(HASH_TABLE_ITER *iter) {
@@ -7478,13 +7789,13 @@ hashTableIterNext(HASH_TABLE_ITER *iter) {
}
static void FASTCALL
@ -1116,7 +1093,7 @@ index d68d2c8..cba41f4 100644
}
static void FASTCALL
@@ -7511,13 +7832,13 @@ poolDestroy(STRING_POOL *pool) {
@@ -7511,13 +7822,13 @@ poolDestroy(STRING_POOL *pool) {
BLOCK *p = pool->blocks;
while (p) {
BLOCK *tem = p->next;
@ -1132,7 +1109,7 @@ index d68d2c8..cba41f4 100644
p = tem;
}
}
@@ -7672,8 +7993,8 @@ poolGrow(STRING_POOL *pool) {
@@ -7672,8 +7983,8 @@ poolGrow(STRING_POOL *pool) {
if (bytesToAllocate == 0)
return XML_FALSE;
@ -1143,7 +1120,7 @@ index d68d2c8..cba41f4 100644
if (temp == NULL)
return XML_FALSE;
pool->blocks = temp;
@@ -7713,7 +8034,7 @@ poolGrow(STRING_POOL *pool) {
@@ -7713,7 +8024,7 @@ poolGrow(STRING_POOL *pool) {
if (bytesToAllocate == 0)
return XML_FALSE;
@ -1152,7 +1129,7 @@ index d68d2c8..cba41f4 100644
if (! tem)
return XML_FALSE;
tem->size = blockSize;
@@ -7828,7 +8149,10 @@ build_model(XML_Parser parser) {
@@ -7828,7 +8139,10 @@ build_model(XML_Parser parser) {
const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content)
+ (dtd->contentStringLen * sizeof(XML_Char)));
@ -1164,7 +1141,7 @@ index d68d2c8..cba41f4 100644
if (! ret)
return NULL;
@@ -7949,7 +8273,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
@@ -7949,7 +8263,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
}
static XML_Char *
@ -1173,7 +1150,7 @@ index d68d2c8..cba41f4 100644
size_t charsRequired = 0;
XML_Char *result;
@@ -7961,7 +8285,7 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
@@ -7961,7 +8275,7 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
charsRequired++;
/* Now allocate space for the copy */
@ -1183,7 +1160,7 @@ index d68d2c8..cba41f4 100644
return NULL;
/* Copy the original into place */
diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c
index 5db384d..4a0a2e3 100644
index 5db384d..0be1427 100644
--- a/expat/tests/runtests.c
+++ b/expat/tests/runtests.c
@@ -51,6 +51,9 @@
@ -1207,15 +1184,10 @@ index 5db384d..4a0a2e3 100644
#include "chardata.h"
#include "structdata.h"
#include "internal.h"
@@ -11420,6 +11426,209 @@ START_TEST(test_alloc_reset_after_external_entity_parser_create_fail) {
@@ -11420,6 +11426,190 @@ START_TEST(test_alloc_reset_after_external_entity_parser_create_fail) {
}
END_TEST
+static size_t
+sizeRecordedFor(void *ptr) {
+ return *(size_t *)((char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t));
+}
+
+START_TEST(test_alloc_tracker_size_recorded) {
+ XML_Memory_Handling_Suite memsuite = {malloc, realloc, free};
+
@ -1229,16 +1201,16 @@ index 5db384d..4a0a2e3 100644
+ void *ptr = expat_malloc(parser, 10, -1);
+
+ assert_true(ptr != NULL);
+ assert_true(sizeRecordedFor(ptr) == 10);
+ assert_true(*((size_t *)ptr - 1) == 10);
+
+ assert_true(expat_realloc(parser, ptr, SIZE_MAX / 2, -1) == NULL);
+
+ assert_true(sizeRecordedFor(ptr) == 10); // i.e. unchanged
+ assert_true(*((size_t *)ptr - 1) == 10); // i.e. unchanged
+
+ ptr = expat_realloc(parser, ptr, 20, -1);
+
+ assert_true(ptr != NULL);
+ assert_true(sizeRecordedFor(ptr) == 20);
+ assert_true(*((size_t *)ptr - 1) == 20);
+
+ expat_free(parser, ptr, -1);
+
@ -1247,20 +1219,6 @@ index 5db384d..4a0a2e3 100644
+}
+END_TEST
+
+START_TEST(test_alloc_tracker_pointer_alignment) {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(sizeof(long long) >= sizeof(size_t)); // self-test
+ long long *const ptr
+ = (long long *)expat_malloc(parser, 4 * sizeof(long long), -1);
+ ptr[0] = 0LL;
+ ptr[1] = 1LL;
+ ptr[2] = 2LL;
+ ptr[3] = 3LL;
+ expat_free(parser, ptr, -1);
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_alloc_tracker_maximum_amplification) {
+ if (g_reparseDeferralEnabledDefault == XML_TRUE) {
+ return;
@ -1417,7 +1375,7 @@ index 5db384d..4a0a2e3 100644
static void
nsalloc_setup(void) {
XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
@@ -11820,10 +12029,8 @@ START_TEST(test_nsalloc_realloc_attributes) {
@@ -11820,10 +12010,8 @@ START_TEST(test_nsalloc_realloc_attributes) {
nsalloc_teardown();
nsalloc_setup();
}
@ -1430,12 +1388,11 @@ index 5db384d..4a0a2e3 100644
}
END_TEST
@@ -13694,6 +13901,18 @@ make_suite(void) {
@@ -13694,6 +13882,17 @@ make_suite(void) {
tcase_add_test__ifdef_xml_dtd(
tc_alloc, test_alloc_reset_after_external_entity_parser_create_fail);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_size_recorded);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_pointer_alignment);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc,
+ test_alloc_tracker_maximum_amplification);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_tracker_threshold);

View File

@ -3,7 +3,7 @@
Summary: An XML parser library
Name: expat
Version: %(echo %{unversion} | sed 's/_/./g')
Release: 2%{?dist}.2
Release: 6%{?dist}
Source: https://github.com/libexpat/libexpat/archive/R_%{unversion}.tar.gz#/expat-%{version}.tar.gz
URL: https://libexpat.github.io/
License: MIT
@ -23,17 +23,8 @@ Patch4: expat-2.5.0-CVE-2024-45492.patch
Patch5: expat-2.5.0-CVE-2024-50602.patch
# https://issues.redhat.com/browse/RHEL-57489
Patch6: expat-2.5.0-CVE-2024-8176.patch
# https://issues.redhat.com/browse/RHEL-114618
# https://issues.redhat.com/browse/RHEL-114643
Patch7: expat-2.5.0-CVE-2025-59375.patch
# https://issues.redhat.com/browse/RHEL-177979
# https://github.com/libexpat/libexpat/pull/1216
Patch8: expat-2.5.0-CVE-2026-45186.patch
# https://issues.redhat.com/browse/RHEL-220979
# https://github.com/libexpat/libexpat/pull/1246
Patch9: expat-2.5.0-CVE-2026-50219.patch
# https://issues.redhat.com/browse/RHEL-221012
# https://github.com/libexpat/libexpat/pull/1272
Patch10: expat-2.5.0-CVE-2026-56132.patch
%description
This is expat, the C library for parsing XML, written by James Clark. Expat
@ -70,9 +61,6 @@ pushd ..
%patch5 -p1 -b .CVE-2024-50602
%patch6 -p1 -b .CVE-2024-8176
%patch7 -p1 -b .CVE-2025-59375
%patch8 -p1 -b .CVE-2026-45186
%patch9 -p1 -b .CVE-2026-50219
%patch10 -p1 -b .CVE-2026-56132
popd
sed -i 's/install-data-hook/do-nothing-please/' lib/Makefile.am
@ -82,21 +70,21 @@ sed -i 's/install-data-hook/do-nothing-please/' lib/Makefile.am
export CFLAGS="$RPM_OPT_FLAGS -fPIC"
export DOCBOOK_TO_MAN="xmlto man --skip-validation"
%configure
make %{?_smp_mflags}
%make_build
%install
make install DESTDIR=$RPM_BUILD_ROOT
%make_install
rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
%check
bash -c "for i in {1..500000}; do printf AAAAAAAAAAAAAAAAAAAA >> achars.txt; done"
for testfile in ../testdata/largefiles/aaaaaa_*; do
first_part="$(sed 's/\(.*\)ACHARS.*/\1/g' $testfile)"
second_part="$(sed 's/.*ACHARS\(.*\)/\1/g' $testfile)"
printf "$first_part" > "$testfile"
cat achars.txt >> "$testfile"
printf "$second_part" >> "$testfile"
first_part="$(sed 's/\(.*\)ACHARS.*/\1/g' $testfile)"
second_part="$(sed 's/.*ACHARS\(.*\)/\1/g' $testfile)"
printf "$first_part" > "$testfile"
cat achars.txt >> "$testfile"
printf "$second_part" >> "$testfile"
done
make check
@ -104,7 +92,6 @@ make check
%ldconfig_scriptlets
%files
%{!?_licensedir:%global license %%doc}
%doc AUTHORS Changes
%license COPYING
%{_bindir}/*
@ -122,73 +109,50 @@ make check
%{_libdir}/lib*.a
%changelog
* Fri Jul 31 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.5.0-2.2
- Fix CVE-2026-56132: out-of-bound scaffolding index store in doProlog
- Resolves: RHEL-221012
* Fri Jul 31 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.5.0-2.1
- Fix CVE-2026-50219
- Resolves: RHEL-220979
* Thu May 28 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.5.0-2
- Fix CVE-2026-45186
- Resolves: RHEL-177979
* Wed Nov 19 2025 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-1
- Rebase to version 2.5.0
* Fri Nov 14 2025 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-6
- Fix CVE-2025-59375
- Resolves: RHEL-114618
- Resolves: RHEL-114643
* Mon Apr 07 2025 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-17
* Mon Mar 31 2025 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-5
- Fix CVE-2024-8176
- Resolves: RHEL-57477
- Resolves: RHEL-57489
* Fri Nov 08 2024 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-16
* Thu Nov 07 2024 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-4
- Fix CVE-2024-50602
- Resolves: RHEL-65062
- Resolves: RHEL-65066
* Wed Sep 11 2024 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-15
- Rebuild for test reconfiguration
* Wed Oct 09 2024 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-3
- Fix CVE-2024-45490, CVE-2024-45491, CVE-2024-45492
- Resolves: RHEL-56761
- Resolves: RHEL-57520
- Resolves: RHEL-57511
* Wed Sep 11 2024 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-14
- Fix multiple CVEs
- Fix CVE-2024-45492 integer overflow
- Fix CVE-2024-45491 Integer Overflow or Wraparound
- Fix CVE-2024-45490 Negative Length Parsing Vulnerability
- Resolves: RHEL-57505
- Resolves: RHEL-57493
- Resolves: RHEL-56751
* Tue Feb 13 2024 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-2
- Fix parsing of large tokens
- Reject direct parameter entity recursion
- Resolves: RHEL-29699
- Resolves: RHEL-29696
* Tue Mar 26 2024 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-13
- Fix wrongly exposed variables
- Resolves: RHEL-29321
* Thu Mar 21 2024 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-12
- CVE-2023-52425 expat: parsing large tokens can trigger a denial of service
- Resolves: RHEL-29321
* Mon Nov 14 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-11
- CVE-2022-43680 expat: use-after free caused by overeager destruction of a shared DTD in XML_ExternalEntityParserCreate
* Thu Nov 10 2022 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-1
- Rebase to version 2.5.0
- Resolves: CVE-2022-43680
* Fri Sep 30 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-10
- Ensure raw tagnames are safe exiting internalEntityParser
* Thu Sep 29 2022 Tomas Korbar <tkorbar@redhat.com> - 2.4.9-1
- Rebase to version 2.4.9
- Resolves: CVE-2022-40674
* Fri May 06 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-9
- Fix multiple CVEs
- Resolves: CVE-2022-25314
* Tue Apr 26 2022 Tomas Korbar <tkorbar@redhat.com> - 2.4.7-1
- Rebase to version 2.4.7
- Resolves: rhbz#2067201
- Resolves: CVE-2022-25313
- Resolves: CVE-2022-25314
- Resolves: CVE-2022-25236
* Mon Mar 14 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-8
- Improve patch for CVE-2022-25236
* Mon Mar 14 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-11
- Improve fix for CVE-2022-25236
- Related: CVE-2022-25236
* Fri Mar 04 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-7
- Fix patch for CVE-2022-25235
- Resolves: CVE-2022-25235
* Thu Mar 03 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-6
* Mon Feb 28 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-10
- Fix multiple CVEs
- CVE-2022-25236 expat: namespace-separator characters in "xmlns[:prefix]" attribute values can lead to arbitrary code execution
- CVE-2022-25235 expat: malformed 2- and 3-byte UTF-8 sequences can lead to arbitrary code execution
@ -197,20 +161,25 @@ make check
- Resolves: CVE-2022-25235
- Resolves: CVE-2022-25315
* Fri Feb 14 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-5
- Fix multiple CVEs
* Thu Feb 10 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-9
- CVE-2022-23852 expat: integer overflow in function XML_GetBuffer
- Resolves: CVE-2022-23852
* Thu Feb 10 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-8
- CVE-2021-45960 expat: Large number of prefixed XML attributes on a single tag can crash libexpat
- Resolves: CVE-2021-45960
* Wed Feb 09 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-7
- CVE-2021-46143 expat: Integer overflow in doProlog in xmlparse.c
- Resolves: CVE-2021-46143
* Wed Feb 09 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-6
- CVE-2022-22827 Integer overflow in storeAtts in xmlparse.c
- CVE-2022-22826 Integer overflow in nextScaffoldPart in xmlparse.c
- CVE-2022-22825 Integer overflow in lookup in xmlparse.c
- CVE-2022-22824 Integer overflow in defineAttribute in xmlparse.c
- CVE-2022-22823 Integer overflow in build_model in xmlparse.c
- CVE-2022-22822 Integer overflow in addBinding in xmlparse.c
- Resolves: CVE-2022-23852
- Resolves: CVE-2021-45960
- Resolves: CVE-2021-46143
- Resolves: CVE-2022-22827
- Resolves: CVE-2022-22826
- Resolves: CVE-2022-22825
@ -218,8 +187,46 @@ make check
- Resolves: CVE-2022-22823
- Resolves: CVE-2022-22822
* Fri Apr 24 2020 Joe Orton <jorton@redhat.com> - 2.2.5-4
- add security fixes for CVE-2018-20843, CVE-2019-15903
* Mon Feb 07 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-5
- CVE-2022-23990 expat: integer overflow in the doProlog function
- Resolve: rhbz#2050503
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 2.2.10-4
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Thu Apr 15 2021 Mohan Boddu <mboddu@redhat.com> - 2.2.10-3
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.10-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Fri Nov 13 2020 Joe Orton <jorton@redhat.com> - 2.2.10-1
- update to 2.2.10 (#1884940)
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.8-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.8-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Mon Sep 16 2019 Joe Orton <jorton@redhat.com> - 2.2.8-1
- update to 2.2.8 (#1752167)
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.7-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Thu Jun 27 2019 Joe Orton <jorton@redhat.com> - 2.2.7-1
- update to 2.2.7 (#1723724, #1722224)
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.6-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Wed Aug 15 2018 Joe Orton <jorton@redhat.com> - 2.2.6-1
- update to 2.2.6
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.5-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.5-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild

25
gating.yaml Normal file
View File

@ -0,0 +1,25 @@
--- !Policy
product_versions:
- fedora-*
decision_context: bodhi_update_push_testing
subject_type: koji_build
rules:
- !PassingTestCaseRule {test_case_name: fedora-ci.koji-build./plans/tier1-public.functional}
#Rawhide
--- !Policy
product_versions:
- fedora-*
decision_context: bodhi_update_push_stable
subject_type: koji_build
rules:
- !PassingTestCaseRule {test_case_name: fedora-ci.koji-build./plans/tier1-public.functional}
#gating rhel
--- !Policy
product_versions:
- rhel-*
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: osci.brew-build./plans/tier1-public.functional}
- !PassingTestCaseRule {test_case_name: osci.brew-build./plans/tier1-internal.functional}

36
plans.fmf Normal file
View File

@ -0,0 +1,36 @@
/tier1-internal:
plan:
import:
url: https://src.fedoraproject.org/tests/expat.git
name: /plans/tier1/internal
/tier1-public:
plan:
import:
url: https://src.fedoraproject.org/tests/expat.git
name: /plans/tier1/public
/tier2-tier3-internal:
plan:
import:
url: https://src.fedoraproject.org/tests/expat.git
name: /plans/tier2-tier3/internal
/tier2-tier3-public:
plan:
import:
url: https://src.fedoraproject.org/tests/expat.git
name: /plans/tier2-tier3/public
/others-internal:
plan:
import:
url: https://src.fedoraproject.org/tests/expat.git
name: /plans/others/internal
/others-public:
plan:
import:
url: https://src.fedoraproject.org/tests/expat.git
name: /plans/others/public

1
sources Normal file
View File

@ -0,0 +1 @@
SHA512 (expat-2.5.0.tar.gz) = 779f0d0f3f2d8b33db0fd044864ab5ab1a40f20501f792fe90ad0d18de536c4765c3749f120e21fec11a0e6c89af1dc576d1fe261c871ca44a594f7b61fd1d9e