diff --git a/.expat.metadata b/.expat.metadata index eb70785..2c088e1 100644 --- a/.expat.metadata +++ b/.expat.metadata @@ -1 +1 @@ -a2a0f172dd3346b520918331b7480d4d30557439 SOURCES/expat-2.2.10.tar.gz +71bc4b192e54040b41d98e5a49aca5e18e27485b SOURCES/expat-2.4.9.tar.gz diff --git a/.gitignore b/.gitignore index b5e40bd..37fcacc 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/expat-2.2.10.tar.gz +SOURCES/expat-2.4.9.tar.gz diff --git a/SOURCES/expat-2.2.10-Add-missing-validation-of-encoding.patch b/SOURCES/expat-2.2.10-Add-missing-validation-of-encoding.patch deleted file mode 100644 index 2d526c2..0000000 --- a/SOURCES/expat-2.2.10-Add-missing-validation-of-encoding.patch +++ /dev/null @@ -1,281 +0,0 @@ -From ee2a5b50e7d1940ba8745715b62ceb9efd3a96da Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Tue, 8 Feb 2022 17:37:14 +0100 -Subject: [PATCH 1/5] lib: Drop unused macro UTF8_GET_NAMING - ---- - expat/lib/xmltok.c | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/lib/xmltok.c b/lib/xmltok.c -index a72200e8..3bddf125 100644 ---- a/lib/xmltok.c -+++ b/lib/xmltok.c -@@ -98,11 +98,6 @@ - + ((((byte)[1]) & 3) << 1) + ((((byte)[2]) >> 5) & 1)] \ - & (1u << (((byte)[2]) & 0x1F))) - --#define UTF8_GET_NAMING(pages, p, n) \ -- ((n) == 2 \ -- ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \ -- : ((n) == 3 ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) : 0)) -- - /* Detection of invalid UTF-8 sequences is based on Table 3.1B - of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/ - with the additional restriction of not allowing the Unicode - -From 3f0a0cb644438d4d8e3294cd0b1245d0edb0c6c6 Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Tue, 8 Feb 2022 04:32:20 +0100 -Subject: [PATCH 2/5] lib: Add missing validation of encoding (CVE-2022-25235) - ---- - expat/lib/xmltok_impl.c | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/lib/xmltok_impl.c b/lib/xmltok_impl.c -index 0430591b..64a3b2c1 100644 ---- a/lib/xmltok_impl.c -+++ b/lib/xmltok_impl.c -@@ -69,7 +69,7 @@ - case BT_LEAD##n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ -- if (! IS_NAME_CHAR(enc, ptr, n)) { \ -+ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NAME_CHAR(enc, ptr, n)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; \ - } \ -@@ -98,7 +98,7 @@ - case BT_LEAD##n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ -- if (! IS_NMSTRT_CHAR(enc, ptr, n)) { \ -+ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NMSTRT_CHAR(enc, ptr, n)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; \ - } \ -@@ -1142,6 +1142,10 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, - case BT_LEAD##n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ -+ if (IS_INVALID_CHAR(enc, ptr, n)) { \ -+ *nextTokPtr = ptr; \ -+ return XML_TOK_INVALID; \ -+ } \ - if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ - ptr += n; \ - tok = XML_TOK_NAME; \ - -From c85a3025e7a1be086dc34e7559fbc543914d047f Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Wed, 9 Feb 2022 01:00:38 +0100 -Subject: [PATCH 3/5] lib: Add comments to BT_LEAD* cases where encoding has - already been validated - ---- - expat/lib/xmltok_impl.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/lib/xmltok_impl.c b/lib/xmltok_impl.c -index 64a3b2c1..84ff35f9 100644 ---- a/lib/xmltok_impl.c -+++ b/lib/xmltok_impl.c -@@ -1274,7 +1274,7 @@ PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end, - switch (BYTE_TYPE(enc, ptr)) { - # define LEAD_CASE(n) \ - case BT_LEAD##n: \ -- ptr += n; \ -+ ptr += n; /* NOTE: The encoding has already been validated. */ \ - break; - LEAD_CASE(2) - LEAD_CASE(3) -@@ -1343,7 +1343,7 @@ PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end, - switch (BYTE_TYPE(enc, ptr)) { - # define LEAD_CASE(n) \ - case BT_LEAD##n: \ -- ptr += n; \ -+ ptr += n; /* NOTE: The encoding has already been validated. */ \ - break; - LEAD_CASE(2) - LEAD_CASE(3) -@@ -1522,7 +1522,7 @@ PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax, - state = inName; \ - } - # define LEAD_CASE(n) \ -- case BT_LEAD##n: \ -+ case BT_LEAD##n: /* NOTE: The encoding has already been validated. */ \ - START_NAME ptr += (n - MINBPC(enc)); \ - break; - LEAD_CASE(2) -@@ -1734,7 +1734,7 @@ PREFIX(nameLength)(const ENCODING *enc, const char *ptr) { - switch (BYTE_TYPE(enc, ptr)) { - # define LEAD_CASE(n) \ - case BT_LEAD##n: \ -- ptr += n; \ -+ ptr += n; /* NOTE: The encoding has already been validated. */ \ - break; - LEAD_CASE(2) - LEAD_CASE(3) -@@ -1779,7 +1779,7 @@ PREFIX(updatePosition)(const ENCODING *enc, const char *ptr, const char *end, - switch (BYTE_TYPE(enc, ptr)) { - # define LEAD_CASE(n) \ - case BT_LEAD##n: \ -- ptr += n; \ -+ ptr += n; /* NOTE: The encoding has already been validated. */ \ - pos->columnNumber++; \ - break; - LEAD_CASE(2) - -From 6a5510bc6b7efe743356296724e0b38300f05379 Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Tue, 8 Feb 2022 04:06:21 +0100 -Subject: [PATCH 4/5] tests: Cover missing validation of encoding - (CVE-2022-25235) - ---- - expat/tests/runtests.c | 109 +++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 109 insertions(+) - -diff --git a/tests/runtests.c b/tests/runtests.c -index bc5344b1..9b155b82 100644 ---- a/tests/runtests.c -+++ b/tests/runtests.c -@@ -5998,6 +5998,105 @@ START_TEST(test_utf8_in_cdata_section_2) { - } - END_TEST - -+START_TEST(test_utf8_in_start_tags) { -+ struct test_case { -+ bool goodName; -+ bool goodNameStart; -+ const char *tagName; -+ }; -+ -+ // The idea with the tests below is this: -+ // We want to cover 1-, 2- and 3-byte sequences, 4-byte sequences -+ // go to isNever and are hence not a concern. -+ // -+ // We start with a character that is a valid name character -+ // (or even name-start character, see XML 1.0r4 spec) and then we flip -+ // single bits at places where (1) the result leaves the UTF-8 encoding space -+ // and (2) we stay in the same n-byte sequence family. -+ // -+ // The flipped bits are highlighted in angle brackets in comments, -+ // e.g. "[<1>011 1001]" means we had [0011 1001] but we now flipped -+ // the most significant bit to 1 to leave UTF-8 encoding space. -+ struct test_case cases[] = { -+ // 1-byte UTF-8: [0xxx xxxx] -+ {true, true, "\x3A"}, // [0011 1010] = ASCII colon ':' -+ {false, false, "\xBA"}, // [<1>011 1010] -+ {true, false, "\x39"}, // [0011 1001] = ASCII nine '9' -+ {false, false, "\xB9"}, // [<1>011 1001] -+ -+ // 2-byte UTF-8: [110x xxxx] [10xx xxxx] -+ {true, true, "\xDB\xA5"}, // [1101 1011] [1010 0101] = -+ // Arabic small waw U+06E5 -+ {false, false, "\x9B\xA5"}, // [1<0>01 1011] [1010 0101] -+ {false, false, "\xDB\x25"}, // [1101 1011] [<0>010 0101] -+ {false, false, "\xDB\xE5"}, // [1101 1011] [1<1>10 0101] -+ {true, false, "\xCC\x81"}, // [1100 1100] [1000 0001] = -+ // combining char U+0301 -+ {false, false, "\x8C\x81"}, // [1<0>00 1100] [1000 0001] -+ {false, false, "\xCC\x01"}, // [1100 1100] [<0>000 0001] -+ {false, false, "\xCC\xC1"}, // [1100 1100] [1<1>00 0001] -+ -+ // 3-byte UTF-8: [1110 xxxx] [10xx xxxx] [10xxxxxx] -+ {true, true, "\xE0\xA4\x85"}, // [1110 0000] [1010 0100] [1000 0101] = -+ // Devanagari Letter A U+0905 -+ {false, false, "\xA0\xA4\x85"}, // [1<0>10 0000] [1010 0100] [1000 0101] -+ {false, false, "\xE0\x24\x85"}, // [1110 0000] [<0>010 0100] [1000 0101] -+ {false, false, "\xE0\xE4\x85"}, // [1110 0000] [1<1>10 0100] [1000 0101] -+ {false, false, "\xE0\xA4\x05"}, // [1110 0000] [1010 0100] [<0>000 0101] -+ {false, false, "\xE0\xA4\xC5"}, // [1110 0000] [1010 0100] [1<1>00 0101] -+ {true, false, "\xE0\xA4\x81"}, // [1110 0000] [1010 0100] [1000 0001] = -+ // combining char U+0901 -+ {false, false, "\xA0\xA4\x81"}, // [1<0>10 0000] [1010 0100] [1000 0001] -+ {false, false, "\xE0\x24\x81"}, // [1110 0000] [<0>010 0100] [1000 0001] -+ {false, false, "\xE0\xE4\x81"}, // [1110 0000] [1<1>10 0100] [1000 0001] -+ {false, false, "\xE0\xA4\x01"}, // [1110 0000] [1010 0100] [<0>000 0001] -+ {false, false, "\xE0\xA4\xC1"}, // [1110 0000] [1010 0100] [1<1>00 0001] -+ }; -+ const bool atNameStart[] = {true, false}; -+ -+ size_t i = 0; -+ char doc[1024]; -+ size_t failCount = 0; -+ -+ for (; i < sizeof(cases) / sizeof(cases[0]); i++) { -+ size_t j = 0; -+ for (; j < sizeof(atNameStart) / sizeof(atNameStart[0]); j++) { -+ const bool expectedSuccess -+ = atNameStart[j] ? cases[i].goodNameStart : cases[i].goodName; -+ sprintf(doc, "<%s%s>a'>]>&e;\n" -+ "<" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -+ "/>" -+ ""; -+ const size_t firstChunkSizeBytes = 54; -+ -+ XML_Parser parser = XML_ParserCreate(NULL); -+ XML_SetUserData(parser, parser); -+ XML_SetCommentHandler(parser, suspending_comment_handler); -+ -+ if (XML_Parse(parser, text, (int)firstChunkSizeBytes, XML_FALSE) -+ != XML_STATUS_SUSPENDED) -+ xml_failure(parser); -+ if (XML_ResumeParser(parser) != XML_STATUS_OK) -+ xml_failure(parser); -+ if (XML_Parse(parser, text + firstChunkSizeBytes, -+ (int)(strlen(text) - firstChunkSizeBytes), XML_TRUE) -+ != XML_STATUS_OK) -+ xml_failure(parser); -+ XML_ParserFree(parser); -+} -+END_TEST -+ - /* Test suspending and resuming in a parameter entity substitution */ - static void XMLCALL - element_decl_suspender(void *userData, const XML_Char *name, -@@ -11629,6 +11701,8 @@ make_suite(void) { - tcase_add_test(tc_basic, test_partial_char_in_epilog); - tcase_add_test(tc_basic, test_hash_collision); - tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_internal_entity); -+ tcase_add_test__ifdef_xml_dtd(tc_basic, -+ test_suspend_resume_internal_entity_issue_629); - tcase_add_test__ifdef_xml_dtd(tc_basic, test_resume_entity_with_syntax_error); - tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_parameter_entity); - tcase_add_test(tc_basic, test_restart_on_error); diff --git a/SOURCES/expat-2.2.10-Prevent-integer-overflow-in-copyString.patch b/SOURCES/expat-2.2.10-Prevent-integer-overflow-in-copyString.patch deleted file mode 100644 index 9c9a640..0000000 --- a/SOURCES/expat-2.2.10-Prevent-integer-overflow-in-copyString.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index 4b43e6132..a39377c23 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -7412,7 +7412,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, - - static XML_Char * - copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { -- int charsRequired = 0; -+ size_t charsRequired = 0; - XML_Char *result; - - /* First determine how long the string is */ - diff --git a/SOURCES/expat-2.2.10-Prevent-integer-overflow-in-storeRawNames.patch b/SOURCES/expat-2.2.10-Prevent-integer-overflow-in-storeRawNames.patch deleted file mode 100644 index 31e35fa..0000000 --- a/SOURCES/expat-2.2.10-Prevent-integer-overflow-in-storeRawNames.patch +++ /dev/null @@ -1,139 +0,0 @@ -From eb0362808b4f9f1e2345a0cf203b8cc196d776d9 Mon Sep 17 00:00:00 2001 -From: Samanta Navarro -Date: Tue, 15 Feb 2022 11:55:46 +0000 -Subject: [PATCH] Prevent integer overflow in storeRawNames - -It is possible to use an integer overflow in storeRawNames for out of -boundary heap writes. Default configuration is affected. If compiled -with XML_UNICODE then the attack does not work. Compiling with --fsanitize=address confirms the following proof of concept. - -The problem can be exploited by abusing the m_buffer expansion logic. -Even though the initial size of m_buffer is a power of two, eventually -it can end up a little bit lower, thus allowing allocations very close -to INT_MAX (since INT_MAX/2 can be surpassed). This means that tag -names can be parsed which are almost INT_MAX in size. - -Unfortunately (from an attacker point of view) INT_MAX/2 is also a -limitation in string pools. Having a tag name of INT_MAX/2 characters -or more is not possible. - -Expat can convert between different encodings. UTF-16 documents which -contain only ASCII representable characters are twice as large as their -ASCII encoded counter-parts. - -The proof of concept works by taking these three considerations into -account: - -1. Move the m_buffer size slightly below a power of two by having a - short root node . This allows the m_buffer to grow very close - to INT_MAX. -2. The string pooling forbids tag names longer than or equal to - INT_MAX/2, so keep the attack tag name smaller than that. -3. To be able to still overflow INT_MAX even though the name is - limited at INT_MAX/2-1 (nul byte) we use UTF-16 encoding and a tag - which only contains ASCII characters. UTF-16 always stores two - bytes per character while the tag name is converted to using only - one. Our attack node byte count must be a bit higher than - 2/3 INT_MAX so the converted tag name is around INT_MAX/3 which - in sum can overflow INT_MAX. - -Thanks to our small root node, m_buffer can handle 2/3 INT_MAX bytes -without running into INT_MAX boundary check. The string pooling is -able to store INT_MAX/3 as tag name because the amount is below -INT_MAX/2 limitation. And creating the sum of both eventually overflows -in storeRawNames. - -Proof of Concept: - -1. Compile expat with -fsanitize=address. - -2. Create Proof of Concept binary which iterates through input - file 16 MB at once for better performance and easier integer - calculations: - -``` -cat > poc.c << EOF - #include - #include - #include - #include - - #define CHUNK (16 * 1024 * 1024) - int main(int argc, char *argv[]) { - XML_Parser parser; - FILE *fp; - char *buf; - int i; - - if (argc != 2) - errx(1, "usage: poc file.xml"); - if ((parser = XML_ParserCreate(NULL)) == NULL) - errx(1, "failed to create expat parser"); - if ((fp = fopen(argv[1], "r")) == NULL) { - XML_ParserFree(parser); - err(1, "failed to open file"); - } - if ((buf = malloc(CHUNK)) == NULL) { - fclose(fp); - XML_ParserFree(parser); - err(1, "failed to allocate buffer"); - } - i = 0; - while (fread(buf, CHUNK, 1, fp) == 1) { - printf("iteration %d: XML_Parse returns %d\n", ++i, - XML_Parse(parser, buf, CHUNK, XML_FALSE)); - } - free(buf); - fclose(fp); - XML_ParserFree(parser); - return 0; - } -EOF -gcc -fsanitize=address -lexpat -o poc poc.c -``` - -3. Construct specially prepared UTF-16 XML file: - -``` -dd if=/dev/zero bs=1024 count=794624 | tr '\0' 'a' > poc-utf8.xml -echo -n '<' | dd conv=notrunc of=poc-utf8.xml -echo -n '><' | dd conv=notrunc of=poc-utf8.xml bs=1 seek=805306368 -iconv -f UTF-8 -t UTF-16LE poc-utf8.xml > poc-utf16.xml -``` - -4. Run proof of concept: - -``` -./poc poc-utf16.xml -``` ---- - expat/lib/xmlparse.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index 4b43e613..f34d6ab5 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -2563,6 +2563,7 @@ storeRawNames(XML_Parser parser) { - while (tag) { - int bufSize; - int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); -+ size_t rawNameLen; - char *rawNameBuf = tag->buf + nameLen; - /* Stop if already stored. Since m_tagStack is a stack, we can stop - at the first entry that has already been copied; everything -@@ -2574,7 +2575,11 @@ storeRawNames(XML_Parser parser) { - /* For re-use purposes we need to ensure that the - size of tag->buf is a multiple of sizeof(XML_Char). - */ -- bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)); -+ rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char)); -+ /* Detect and prevent integer overflow. */ -+ if (rawNameLen > (size_t)INT_MAX - nameLen) -+ return XML_FALSE; -+ bufSize = nameLen + (int)rawNameLen; - if (bufSize > tag->bufEnd - tag->buf) { - char *temp = (char *)REALLOC(parser, tag->buf, bufSize); - if (temp == NULL) - diff --git a/SOURCES/expat-2.2.10-Prevent-integer-overflow-on-m_groupSize-in-function.patch b/SOURCES/expat-2.2.10-Prevent-integer-overflow-on-m_groupSize-in-function.patch deleted file mode 100644 index 17d192f..0000000 --- a/SOURCES/expat-2.2.10-Prevent-integer-overflow-on-m_groupSize-in-function.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 85ae9a2d7d0e9358f356b33977b842df8ebaec2b Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Sat, 25 Dec 2021 20:52:08 +0100 -Subject: [PATCH] lib: Prevent integer overflow on m_groupSize in function - doProlog (CVE-2021-46143) - ---- - expat/lib/xmlparse.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index b47c31b0..8f243126 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -5046,6 +5046,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, - 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) { -@@ -5056,6 +5061,16 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, - } - - 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) diff --git a/SOURCES/expat-2.2.10-Prevent-more-integer-overflows.patch b/SOURCES/expat-2.2.10-Prevent-more-integer-overflows.patch deleted file mode 100644 index 63b5d2f..0000000 --- a/SOURCES/expat-2.2.10-Prevent-more-integer-overflows.patch +++ /dev/null @@ -1,250 +0,0 @@ -From 9f93e8036e842329863bf20395b8fb8f73834d9e Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Thu, 30 Dec 2021 22:46:03 +0100 -Subject: [PATCH] lib: Prevent integer overflow at multiple places - (CVE-2022-22822 to CVE-2022-22827) - -The involved functions are: -- addBinding (CVE-2022-22822) -- build_model (CVE-2022-22823) -- defineAttribute (CVE-2022-22824) -- lookup (CVE-2022-22825) -- nextScaffoldPart (CVE-2022-22826) -- storeAtts (CVE-2022-22827) ---- - expat/lib/xmlparse.c | 153 ++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 151 insertions(+), 2 deletions(-) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index 8f243126..575e73ee 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -3261,13 +3261,38 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, - - /* get the attributes from the tokenizer */ - n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts); -+ -+ /* Detect and prevent integer overflow */ -+ if (n > INT_MAX - nDefaultAtts) { -+ return XML_ERROR_NO_MEMORY; -+ } -+ - if (n + nDefaultAtts > parser->m_attsSize) { - int oldAttsSize = parser->m_attsSize; - ATTRIBUTE *temp; - #ifdef XML_ATTR_INFO - XML_AttrInfo *temp2; - #endif -+ -+ /* Detect and prevent integer overflow */ -+ if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE) -+ || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) { -+ return XML_ERROR_NO_MEMORY; -+ } -+ - parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; -+ -+ /* 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 ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) { -+ parser->m_attsSize = oldAttsSize; -+ return XML_ERROR_NO_MEMORY; -+ } -+#endif -+ - temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts, - parser->m_attsSize * sizeof(ATTRIBUTE)); - if (temp == NULL) { -@@ -3276,6 +3301,17 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, - } - parser->m_atts = temp; - #ifdef XML_ATTR_INFO -+ /* 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 ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) { -+ parser->m_attsSize = oldAttsSize; -+ return XML_ERROR_NO_MEMORY; -+ } -+# endif -+ - temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo, - parser->m_attsSize * sizeof(XML_AttrInfo)); - if (temp2 == NULL) { -@@ -3610,9 +3646,31 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, - tagNamePtr->prefixLen = prefixLen; - for (i = 0; localPart[i++];) - ; /* i includes null terminator */ -+ -+ /* Detect and prevent integer overflow */ -+ if (binding->uriLen > INT_MAX - prefixLen -+ || i > INT_MAX - (binding->uriLen + prefixLen)) { -+ return XML_ERROR_NO_MEMORY; -+ } -+ - n = i + binding->uriLen + prefixLen; - if (n > binding->uriAlloc) { - TAG *p; -+ -+ /* Detect and prevent integer overflow */ -+ if (n > INT_MAX - EXPAND_SPARE) { -+ return XML_ERROR_NO_MEMORY; -+ } -+ /* 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 ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { -+ return XML_ERROR_NO_MEMORY; -+ } -+#endif -+ - uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char)); - if (! uri) - return XML_ERROR_NO_MEMORY; -@@ -3708,6 +3766,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, - if (parser->m_freeBindingList) { - b = parser->m_freeBindingList; - if (len > b->uriAlloc) { -+ /* Detect and prevent integer overflow */ -+ if (len > INT_MAX - EXPAND_SPARE) { -+ return XML_ERROR_NO_MEMORY; -+ } -+ -+ /* 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 ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { -+ return XML_ERROR_NO_MEMORY; -+ } -+#endif -+ - XML_Char *temp = (XML_Char *)REALLOC( - parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); - if (temp == NULL) -@@ -3720,6 +3793,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, - b = (BINDING *)MALLOC(parser, sizeof(BINDING)); - if (! b) - return XML_ERROR_NO_MEMORY; -+ -+ /* Detect and prevent integer overflow */ -+ if (len > INT_MAX - EXPAND_SPARE) { -+ return XML_ERROR_NO_MEMORY; -+ } -+ /* 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 ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { -+ return XML_ERROR_NO_MEMORY; -+ } -+#endif -+ - b->uri - = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE)); - if (! b->uri) { -@@ -6141,7 +6229,24 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, - } - } else { - DEFAULT_ATTRIBUTE *temp; -+ -+ /* Detect and prevent integer overflow */ -+ if (type->allocDefaultAtts > INT_MAX / 2) { -+ return 0; -+ } -+ - int count = type->allocDefaultAtts * 2; -+ -+ /* 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 ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) { -+ return 0; -+ } -+#endif -+ - temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts, - (count * sizeof(DEFAULT_ATTRIBUTE))); - if (temp == NULL) -@@ -6792,8 +6897,20 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { - /* check for overflow (table is half full) */ - if (table->used >> (table->power - 1)) { - unsigned char newPower = table->power + 1; -+ -+ /* Detect and prevent invalid shift */ -+ if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) { -+ return NULL; -+ } -+ - size_t newSize = (size_t)1 << newPower; - unsigned long newMask = (unsigned long)newSize - 1; -+ -+ /* Detect and prevent integer overflow */ -+ if (newSize > (size_t)(-1) / sizeof(NAMED *)) { -+ return NULL; -+ } -+ - size_t tsize = newSize * sizeof(NAMED *); - NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize); - if (! newV) -@@ -7143,6 +7260,20 @@ nextScaffoldPart(XML_Parser parser) { - if (dtd->scaffCount >= dtd->scaffSize) { - CONTENT_SCAFFOLD *temp; - if (dtd->scaffold) { -+ /* Detect and prevent integer overflow */ -+ if (dtd->scaffSize > UINT_MAX / 2u) { -+ return -1; -+ } -+ /* 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 (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) { -+ return -1; -+ } -+#endif -+ - temp = (CONTENT_SCAFFOLD *)REALLOC( - parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); - if (temp == NULL) -@@ -7212,8 +7343,26 @@ build_model(XML_Parser parser) { - XML_Content *ret; - XML_Content *cpos; - XML_Char *str; -- int allocsize = (dtd->scaffCount * sizeof(XML_Content) -- + (dtd->contentStringLen * sizeof(XML_Char))); -+ -+ /* 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 (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) { -+ return NULL; -+ } -+ if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) { -+ return NULL; -+ } -+#endif -+ if (dtd->scaffCount * sizeof(XML_Content) -+ > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) { -+ return NULL; -+ } -+ -+ const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content) -+ + (dtd->contentStringLen * sizeof(XML_Char))); - - ret = (XML_Content *)MALLOC(parser, allocsize); - if (! ret) diff --git a/SOURCES/expat-2.2.10-Prevent-stack-exhaustion-in-build_model.patch b/SOURCES/expat-2.2.10-Prevent-stack-exhaustion-in-build_model.patch deleted file mode 100644 index cfa7c1b..0000000 --- a/SOURCES/expat-2.2.10-Prevent-stack-exhaustion-in-build_model.patch +++ /dev/null @@ -1,255 +0,0 @@ -commit 37b45d8ff0f92a7ea0491dd61a0bceb951af332e -Author: Tomas Korbar -Date: Tue May 3 09:57:53 2022 +0200 - - Fix CVE-2022-25313 - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index 0948906..8e84b5a 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -7138,44 +7138,15 @@ nextScaffoldPart(XML_Parser parser) { - return next; - } - --static void --build_node(XML_Parser parser, int src_node, XML_Content *dest, -- XML_Content **contpos, XML_Char **strpos) { -- DTD *const dtd = parser->m_dtd; /* save one level of indirection */ -- dest->type = dtd->scaffold[src_node].type; -- dest->quant = dtd->scaffold[src_node].quant; -- if (dest->type == XML_CTYPE_NAME) { -- const XML_Char *src; -- dest->name = *strpos; -- src = dtd->scaffold[src_node].name; -- for (;;) { -- *(*strpos)++ = *src; -- if (! *src) -- break; -- src++; -- } -- dest->numchildren = 0; -- dest->children = NULL; -- } else { -- unsigned int i; -- int cn; -- dest->numchildren = dtd->scaffold[src_node].childcnt; -- dest->children = *contpos; -- *contpos += dest->numchildren; -- for (i = 0, cn = dtd->scaffold[src_node].firstchild; i < dest->numchildren; -- i++, cn = dtd->scaffold[cn].nextsib) { -- build_node(parser, cn, &(dest->children[i]), contpos, strpos); -- } -- dest->name = NULL; -- } --} -- - static XML_Content * - build_model(XML_Parser parser) { -+ /* Function build_model transforms the existing parser->m_dtd->scaffold -+ * array of CONTENT_SCAFFOLD tree nodes into a new array of -+ * XML_Content tree nodes followed by a gapless list of zero-terminated -+ * strings. */ - DTD *const dtd = parser->m_dtd; /* save one level of indirection */ - XML_Content *ret; -- XML_Content *cpos; -- XML_Char *str; -+ XML_Char *str; /* the current string writing location */ - - /* Detect and prevent integer overflow. - * The preprocessor guard addresses the "always false" warning -@@ -7201,10 +7172,96 @@ build_model(XML_Parser parser) { - if (! ret) - return NULL; - -- str = (XML_Char *)(&ret[dtd->scaffCount]); -- cpos = &ret[1]; -+ /* What follows is an iterative implementation (of what was previously done -+ * recursively in a dedicated function called "build_node". The old recursive -+ * build_node could be forced into stack exhaustion from input as small as a -+ * few megabyte, and so that was a security issue. Hence, a function call -+ * stack is avoided now by resolving recursion.) -+ * -+ * The iterative approach works as follows: -+ * -+ * - We have two writing pointers, both walking up the result array; one does -+ * the work, the other creates "jobs" for its colleague to do, and leads -+ * the way: -+ * -+ * - The faster one, pointer jobDest, always leads and writes "what job -+ * to do" by the other, once they reach that place in the -+ * array: leader "jobDest" stores the source node array index (relative -+ * to array dtd->scaffold) in field "numchildren". -+ * -+ * - The slower one, pointer dest, looks at the value stored in the -+ * "numchildren" field (which actually holds a source node array index -+ * at that time) and puts the real data from dtd->scaffold in. -+ * -+ * - Before the loop starts, jobDest writes source array index 0 -+ * (where the root node is located) so that dest will have something to do -+ * when it starts operation. -+ * -+ * - Whenever nodes with children are encountered, jobDest appends -+ * them as new jobs, in order. As a result, tree node siblings are -+ * adjacent in the resulting array, for example: -+ * -+ * [0] root, has two children -+ * [1] first child of 0, has three children -+ * [3] first child of 1, does not have children -+ * [4] second child of 1, does not have children -+ * [5] third child of 1, does not have children -+ * [2] second child of 0, does not have children -+ * -+ * Or (the same data) presented in flat array view: -+ * -+ * [0] root, has two children -+ * -+ * [1] first child of 0, has three children -+ * [2] second child of 0, does not have children -+ * -+ * [3] first child of 1, does not have children -+ * [4] second child of 1, does not have children -+ * [5] third child of 1, does not have children -+ * -+ * - The algorithm repeats until all target array indices have been processed. -+ */ -+ XML_Content *dest = ret; /* tree node writing location, moves upwards */ -+ XML_Content *const destLimit = &ret[dtd->scaffCount]; -+ XML_Content *jobDest = ret; /* next free writing location in target array */ -+ str = (XML_Char *)&ret[dtd->scaffCount]; -+ -+ /* Add the starting job, the root node (index 0) of the source tree */ -+ (jobDest++)->numchildren = 0; -+ -+ for (; dest < destLimit; dest++) { -+ /* Retrieve source tree array index from job storage */ -+ const int src_node = (int)dest->numchildren; -+ -+ /* Convert item */ -+ dest->type = dtd->scaffold[src_node].type; -+ dest->quant = dtd->scaffold[src_node].quant; -+ if (dest->type == XML_CTYPE_NAME) { -+ const XML_Char *src; -+ dest->name = str; -+ src = dtd->scaffold[src_node].name; -+ for (;;) { -+ *str++ = *src; -+ if (! *src) -+ break; -+ src++; -+ } -+ dest->numchildren = 0; -+ dest->children = NULL; -+ } else { -+ unsigned int i; -+ int cn; -+ dest->name = NULL; -+ dest->numchildren = dtd->scaffold[src_node].childcnt; -+ dest->children = jobDest; -+ -+ /* Append scaffold indices of children to array */ -+ for (i = 0, cn = dtd->scaffold[src_node].firstchild; -+ i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib) -+ (jobDest++)->numchildren = (unsigned int)cn; -+ } -+ } - -- build_node(parser, 0, ret, &cpos, &str); - return ret; - } - -diff --git a/tests/runtests.c b/tests/runtests.c -index 7293d46..05f3083 100644 ---- a/tests/runtests.c -+++ b/tests/runtests.c -@@ -2677,6 +2677,82 @@ START_TEST(test_dtd_elements) { - } - END_TEST - -+static void XMLCALL -+element_decl_check_model(void *userData, const XML_Char *name, -+ XML_Content *model) { -+ UNUSED_P(userData); -+ uint32_t errorFlags = 0; -+ -+ /* Expected model array structure is this: -+ * [0] (type 6, quant 0) -+ * [1] (type 5, quant 0) -+ * [3] (type 4, quant 0, name "bar") -+ * [4] (type 4, quant 0, name "foo") -+ * [5] (type 4, quant 3, name "xyz") -+ * [2] (type 4, quant 2, name "zebra") -+ */ -+ errorFlags |= ((xcstrcmp(name, XCS("junk")) == 0) ? 0 : (1u << 0)); -+ errorFlags |= ((model != NULL) ? 0 : (1u << 1)); -+ -+ errorFlags |= ((model[0].type == XML_CTYPE_SEQ) ? 0 : (1u << 2)); -+ errorFlags |= ((model[0].quant == XML_CQUANT_NONE) ? 0 : (1u << 3)); -+ errorFlags |= ((model[0].numchildren == 2) ? 0 : (1u << 4)); -+ errorFlags |= ((model[0].children == &model[1]) ? 0 : (1u << 5)); -+ errorFlags |= ((model[0].name == NULL) ? 0 : (1u << 6)); -+ -+ errorFlags |= ((model[1].type == XML_CTYPE_CHOICE) ? 0 : (1u << 7)); -+ errorFlags |= ((model[1].quant == XML_CQUANT_NONE) ? 0 : (1u << 8)); -+ errorFlags |= ((model[1].numchildren == 3) ? 0 : (1u << 9)); -+ errorFlags |= ((model[1].children == &model[3]) ? 0 : (1u << 10)); -+ errorFlags |= ((model[1].name == NULL) ? 0 : (1u << 11)); -+ -+ errorFlags |= ((model[2].type == XML_CTYPE_NAME) ? 0 : (1u << 12)); -+ errorFlags |= ((model[2].quant == XML_CQUANT_REP) ? 0 : (1u << 13)); -+ errorFlags |= ((model[2].numchildren == 0) ? 0 : (1u << 14)); -+ errorFlags |= ((model[2].children == NULL) ? 0 : (1u << 15)); -+ errorFlags |= ((xcstrcmp(model[2].name, XCS("zebra")) == 0) ? 0 : (1u << 16)); -+ -+ errorFlags |= ((model[3].type == XML_CTYPE_NAME) ? 0 : (1u << 17)); -+ errorFlags |= ((model[3].quant == XML_CQUANT_NONE) ? 0 : (1u << 18)); -+ errorFlags |= ((model[3].numchildren == 0) ? 0 : (1u << 19)); -+ errorFlags |= ((model[3].children == NULL) ? 0 : (1u << 20)); -+ errorFlags |= ((xcstrcmp(model[3].name, XCS("bar")) == 0) ? 0 : (1u << 21)); -+ -+ errorFlags |= ((model[4].type == XML_CTYPE_NAME) ? 0 : (1u << 22)); -+ errorFlags |= ((model[4].quant == XML_CQUANT_NONE) ? 0 : (1u << 23)); -+ errorFlags |= ((model[4].numchildren == 0) ? 0 : (1u << 24)); -+ errorFlags |= ((model[4].children == NULL) ? 0 : (1u << 25)); -+ errorFlags |= ((xcstrcmp(model[4].name, XCS("foo")) == 0) ? 0 : (1u << 26)); -+ -+ errorFlags |= ((model[5].type == XML_CTYPE_NAME) ? 0 : (1u << 27)); -+ errorFlags |= ((model[5].quant == XML_CQUANT_PLUS) ? 0 : (1u << 28)); -+ errorFlags |= ((model[5].numchildren == 0) ? 0 : (1u << 29)); -+ errorFlags |= ((model[5].children == NULL) ? 0 : (1u << 30)); -+ errorFlags |= ((xcstrcmp(model[5].name, XCS("xyz")) == 0) ? 0 : (1u << 31)); -+ -+ XML_SetUserData(g_parser, (void *)(uintptr_t)errorFlags); -+ XML_FreeContentModel(g_parser, model); -+} -+ -+START_TEST(test_dtd_elements_nesting) { -+ // Payload inspired by a test in Perl's XML::Parser -+ const char *text = "\n" -+ "]>\n" -+ ""; -+ -+ XML_SetUserData(g_parser, (void *)(uintptr_t)-1); -+ -+ XML_SetElementDeclHandler(g_parser, element_decl_check_model); -+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) -+ == XML_STATUS_ERROR) -+ xml_failure(g_parser); -+ -+ if ((uint32_t)(uintptr_t)XML_GetUserData(g_parser) != 0) -+ fail("Element declaration model regression detected"); -+} -+END_TEST -+ - /* Test foreign DTD handling */ - START_TEST(test_set_foreign_dtd) { - const char *text1 = "\n"; -@@ -11487,6 +11563,7 @@ make_suite(void) { - tcase_add_test(tc_basic, test_memory_allocation); - tcase_add_test(tc_basic, test_default_current); - tcase_add_test(tc_basic, test_dtd_elements); -+ tcase_add_test(tc_basic, test_dtd_elements_nesting); - tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd); - tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_not_standalone); - tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_foreign_dtd); diff --git a/SOURCES/expat-2.2.10-Protect-against-malicious-namespace-declarations.patch b/SOURCES/expat-2.2.10-Protect-against-malicious-namespace-declarations.patch deleted file mode 100644 index 9f68836..0000000 --- a/SOURCES/expat-2.2.10-Protect-against-malicious-namespace-declarations.patch +++ /dev/null @@ -1,228 +0,0 @@ -commit 5c47ae80738d0985babf06a023b3845169682064 -Author: Tomas Korbar -Date: Mon Mar 14 10:22:37 2022 +0100 - - Protect against malicious namespace declarations - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index 5c3f573..901abbf 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -638,8 +638,7 @@ XML_ParserCreate(const XML_Char *encodingName) { - - XML_Parser XMLCALL - XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) { -- XML_Char tmp[2]; -- *tmp = nsSep; -+ XML_Char tmp[2] = {nsSep, 0}; - return XML_ParserCreate_MM(encodingName, NULL, tmp); - } - -@@ -1253,8 +1252,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, - would be otherwise. - */ - if (parser->m_ns) { -- XML_Char tmp[2]; -- *tmp = parser->m_namespaceSeparator; -+ XML_Char tmp[2] = {parser->m_namespaceSeparator, 0}; - parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); - } else { - parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); -@@ -3526,6 +3524,117 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, - return XML_ERROR_NONE; - } - -+static XML_Bool -+is_rfc3986_uri_char(XML_Char candidate) { -+ // For the RFC 3986 ANBF grammar see -+ // https://datatracker.ietf.org/doc/html/rfc3986#appendix-A -+ -+ switch (candidate) { -+ // From rule "ALPHA" (uppercase half) -+ case 'A': -+ case 'B': -+ case 'C': -+ case 'D': -+ case 'E': -+ case 'F': -+ case 'G': -+ case 'H': -+ case 'I': -+ case 'J': -+ case 'K': -+ case 'L': -+ case 'M': -+ case 'N': -+ case 'O': -+ case 'P': -+ case 'Q': -+ case 'R': -+ case 'S': -+ case 'T': -+ case 'U': -+ case 'V': -+ case 'W': -+ case 'X': -+ case 'Y': -+ case 'Z': -+ -+ // From rule "ALPHA" (lowercase half) -+ case 'a': -+ case 'b': -+ case 'c': -+ case 'd': -+ case 'e': -+ case 'f': -+ case 'g': -+ case 'h': -+ case 'i': -+ case 'j': -+ case 'k': -+ case 'l': -+ case 'm': -+ case 'n': -+ case 'o': -+ case 'p': -+ case 'q': -+ case 'r': -+ case 's': -+ case 't': -+ case 'u': -+ case 'v': -+ case 'w': -+ case 'x': -+ case 'y': -+ case 'z': -+ -+ // From rule "DIGIT" -+ case '0': -+ case '1': -+ case '2': -+ case '3': -+ case '4': -+ case '5': -+ case '6': -+ case '7': -+ case '8': -+ case '9': -+ -+ // From rule "pct-encoded" -+ case '%': -+ -+ // From rule "unreserved" -+ case '-': -+ case '.': -+ case '_': -+ case '~': -+ -+ // From rule "gen-delims" -+ case ':': -+ case '/': -+ case '?': -+ case '#': -+ case '[': -+ case ']': -+ case '@': -+ -+ // From rule "sub-delims" -+ case '!': -+ case '$': -+ case '&': -+ case '\'': -+ case '(': -+ case ')': -+ case '*': -+ case '+': -+ case ',': -+ case ';': -+ case '=': -+ return XML_TRUE; -+ -+ default: -+ return XML_FALSE; -+ } -+} -+ - /* addBinding() overwrites the value of prefix->binding without checking. - Therefore one must keep track of the old value outside of addBinding(). - */ -@@ -3581,6 +3690,29 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, - if (! mustBeXML && isXMLNS - && (len > xmlnsLen || uri[len] != xmlnsNamespace[len])) - isXMLNS = XML_FALSE; -+ -+ // NOTE: While Expat does not validate namespace URIs against RFC 3986 -+ // today (and is not REQUIRED to do so with regard to the XML 1.0 -+ // namespaces specification) we have to at least make sure, that -+ // the application on top of Expat (that is likely splitting expanded -+ // element names ("qualified names") of form -+ // "[uri sep] local [sep prefix] '\0'" back into 1, 2 or 3 pieces -+ // in its element handler code) cannot be confused by an attacker -+ // putting additional namespace separator characters into namespace -+ // declarations. That would be ambiguous and not to be expected. -+ // -+ // While the HTML API docs of function XML_ParserCreateNS have been -+ // advising against use of a namespace separator character that can -+ // appear in a URI for >20 years now, some widespread applications -+ // are using URI characters (':' (colon) in particular) for a -+ // namespace separator, in practice. To keep these applications -+ // functional, we only reject namespaces URIs containing the -+ // application-chosen namespace separator if the chosen separator -+ // is a non-URI character with regard to RFC 3986. -+ if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator) -+ && ! is_rfc3986_uri_char(uri[len])) { -+ return XML_ERROR_SYNTAX; -+ } - } - isXML = isXML && len == xmlLen; - isXMLNS = isXMLNS && len == xmlnsLen; -diff --git a/tests/runtests.c b/tests/runtests.c -index f03e008..40172d2 100644 ---- a/tests/runtests.c -+++ b/tests/runtests.c -@@ -7233,6 +7233,37 @@ START_TEST(test_ns_double_colon_doctype) { - } - END_TEST - -+START_TEST(test_ns_separator_in_uri) { -+ struct test_case { -+ enum XML_Status expectedStatus; -+ const char *doc; -+ XML_Char namesep; -+ }; -+ struct test_case cases[] = { -+ {XML_STATUS_OK, "", XCS('\n')}, -+ {XML_STATUS_ERROR, "", XCS('\n')}, -+ {XML_STATUS_OK, "", XCS(':')}, -+ }; -+ -+ size_t i = 0; -+ size_t failCount = 0; -+ for (; i < sizeof(cases) / sizeof(cases[0]); i++) { -+ XML_Parser parser = XML_ParserCreateNS(NULL, cases[i].namesep); -+ XML_SetElementHandler(parser, dummy_start_element, dummy_end_element); -+ if (XML_Parse(parser, cases[i].doc, (int)strlen(cases[i].doc), -+ /*isFinal*/ XML_TRUE) -+ != cases[i].expectedStatus) { -+ failCount++; -+ } -+ XML_ParserFree(parser); -+ } -+ -+ if (failCount) { -+ fail("Namespace separator handling is broken"); -+ } -+} -+END_TEST -+ - /* Control variable; the number of times duff_allocator() will successfully - * allocate */ - #define ALLOC_ALWAYS_SUCCEED (-1) -@@ -11527,6 +11558,7 @@ make_suite(void) { - tcase_add_test(tc_namespace, test_ns_utf16_doctype); - tcase_add_test(tc_namespace, test_ns_invalid_doctype); - tcase_add_test(tc_namespace, test_ns_double_colon_doctype); -+ tcase_add_test(tc_namespace, test_ns_separator_in_uri); - - suite_add_tcase(s, tc_misc); - tcase_add_checked_fixture(tc_misc, NULL, basic_teardown); diff --git a/SOURCES/expat-2.2.10-prevent-integer-overflow-in-doProlog.patch b/SOURCES/expat-2.2.10-prevent-integer-overflow-in-doProlog.patch deleted file mode 100644 index af9c73c..0000000 --- a/SOURCES/expat-2.2.10-prevent-integer-overflow-in-doProlog.patch +++ /dev/null @@ -1,42 +0,0 @@ -From ede41d1e186ed2aba88a06e84cac839b770af3a1 Mon Sep 17 00:00:00 2001 -From: Sebastian Pipping -Date: Wed, 26 Jan 2022 02:36:43 +0100 -Subject: [PATCH 1/2] lib: Prevent integer overflow in doProlog - (CVE-2022-23990) - -The change from "int nameLen" to "size_t nameLen" -addresses the overflow on "nameLen++" in code -"for (; name[nameLen++];)" right above the second -change in the patch. ---- - expat/lib/xmlparse.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/lib/xmlparse.c b/lib/xmlparse.c -index 5ce31402..d1d17005 100644 ---- a/lib/xmlparse.c -+++ b/lib/xmlparse.c -@@ -5372,7 +5372,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, - if (dtd->in_eldecl) { - ELEMENT_TYPE *el; - const XML_Char *name; -- int nameLen; -+ size_t nameLen; - const char *nxt - = (quant == XML_CQUANT_NONE ? next : next - enc->minBytesPerChar); - int myindex = nextScaffoldPart(parser); -@@ -5388,7 +5388,13 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, - nameLen = 0; - for (; name[nameLen++];) - ; -- dtd->contentStringLen += nameLen; -+ -+ /* Detect and prevent integer overflow */ -+ if (nameLen > UINT_MAX - dtd->contentStringLen) { -+ return XML_ERROR_NO_MEMORY; -+ } -+ -+ dtd->contentStringLen += (unsigned)nameLen; - if (parser->m_elementDeclHandler) - handleDefault = XML_FALSE; - } diff --git a/SPECS/expat.spec b/SPECS/expat.spec index 7508f94..cc03718 100644 --- a/SPECS/expat.spec +++ b/SPECS/expat.spec @@ -1,25 +1,14 @@ -%global unversion 2_2_10 +%global unversion 2_4_9 Summary: An XML parser library Name: expat Version: %(echo %{unversion} | sed 's/_/./g') -Release: 12%{?dist}.3 +Release: 1%{?dist} Source: https://github.com/libexpat/libexpat/archive/R_%{unversion}.tar.gz#/expat-%{version}.tar.gz URL: https://libexpat.github.io/ License: MIT BuildRequires: autoconf, libtool, xmlto, gcc-c++ BuildRequires: make -Patch0: expat-2.2.10-prevent-integer-overflow-in-doProlog.patch -Patch1: expat-2.2.10-Prevent-more-integer-overflows.patch -Patch2: expat-2.2.10-Prevent-integer-overflow-on-m_groupSize-in-function.patch -Patch3: expat-2.2.10-Detect-and-prevent-troublesome-left-shifts.patch -Patch4: expat-2.2.10-Detect-and-prevent-integer-overflow-in-XML_GetBuffer.patch -Patch5: expat-2.2.10-Protect-against-malicious-namespace-declarations.patch -Patch6: expat-2.2.10-Add-missing-validation-of-encoding.patch -Patch7: expat-2.2.10-Prevent-integer-overflow-in-storeRawNames.patch -Patch8: expat-2.2.10-Prevent-integer-overflow-in-copyString.patch -Patch9: expat-2.2.10-Prevent-stack-exhaustion-in-build_model.patch -Patch10: expat-2.2.10-Ensure-raw-tagnames-are-safe-exiting-internalEntityParser.patch %description This is expat, the C library for parsing XML, written by James Clark. Expat @@ -47,17 +36,6 @@ Install it if you need to link statically with expat. %prep %setup -q -n libexpat-R_%{unversion}/expat -%patch0 -p1 -b .CVE-2022-23990 -%patch1 -p1 -b .CVE-2022-22822-CVE-2022-22827 -%patch2 -p1 -b .CVE-2021-46143 -%patch3 -p1 -b .CVE-2021-45960 -%patch4 -p1 -b .CVE-2022-23852 -%patch5 -p1 -b .CVE-2022-25236 -%patch6 -p1 -b .CVE-2022-25235 -%patch7 -p1 -b .CVE-2022-25315 -%patch8 -p1 -b .CVE-2022-25314 -%patch9 -p1 -b .CVE-2022-25313 -%patch10 -p1 -b .CVE-2022-40674 sed -i 's/install-data-hook/do-nothing-please/' lib/Makefile.am ./buildconf.sh @@ -86,31 +64,26 @@ make check %{_mandir}/*/* %files devel -%doc doc/reference.html doc/*.png doc/*.css examples/*.c +%doc doc/reference.html doc/*.css examples/*.c %{_libdir}/lib*.so %{_libdir}/pkgconfig/*.pc %{_includedir}/*.h +%{_libdir}/cmake/expat-%{version} %files static %{_libdir}/lib*.a %changelog -* Thu Sep 29 2022 Tomas Korbar - 2.2.10-12.3 -- Ensure raw tagnames are safe exiting internalEntityParser +* Thu Sep 29 2022 Tomas Korbar - 2.4.9-1 +- Rebase to version 2.4.9 - Resolves: CVE-2022-40674 -* Tue May 03 2022 Tomas Korbar - 2.2.10-12.2 -- Improve fix for CVE-2022-25313 -- Related: CVE-2022-25313 - -* Tue Apr 26 2022 Tomas Korbar - 2.2.10-12.1 -- Fix multiple CVEs -- Resolves: CVE-2022-25314 +* Tue Apr 26 2022 Tomas Korbar - 2.4.7-1 +- Rebase to version 2.4.7 +- Resolves: rhbz#2067201 - Resolves: CVE-2022-25313 - -* Wed Mar 16 2022 Tomas Korbar - 2.2.10-12 -- Build fix for CVE-2022-25236 in rhel-9.0.0 -- Related: CVE-2022-25236 +- Resolves: CVE-2022-25314 +- Resolves: CVE-2022-25236 * Mon Mar 14 2022 Tomas Korbar - 2.2.10-11 - Improve fix for CVE-2022-25236