Toshaan Bharvani
2 years ago
commit
4701e607b0
11 changed files with 1783 additions and 0 deletions
@ -0,0 +1,281 @@ |
|||||||
|
From ee2a5b50e7d1940ba8745715b62ceb9efd3a96da Mon Sep 17 00:00:00 2001 |
||||||
|
From: Sebastian Pipping <sebastian@pipping.org> |
||||||
|
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 <sebastian@pipping.org> |
||||||
|
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 <sebastian@pipping.org> |
||||||
|
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 <sebastian@pipping.org> |
||||||
|
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><!--", atNameStart[j] ? "" : "a", cases[i].tagName); |
||||||
|
+ XML_Parser parser = XML_ParserCreate(NULL); |
||||||
|
+ |
||||||
|
+ const enum XML_Status status |
||||||
|
+ = XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_FALSE); |
||||||
|
+ |
||||||
|
+ bool success = true; |
||||||
|
+ if ((status == XML_STATUS_OK) != expectedSuccess) { |
||||||
|
+ success = false; |
||||||
|
+ } |
||||||
|
+ if ((status == XML_STATUS_ERROR) |
||||||
|
+ && (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)) { |
||||||
|
+ success = false; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
+ if (! success) { |
||||||
|
+ fprintf( |
||||||
|
+ stderr, |
||||||
|
+ "FAIL case %2u (%sat name start, %u-byte sequence, error code %d)\n", |
||||||
|
+ (unsigned)i + 1u, atNameStart[j] ? " " : "not ", |
||||||
|
+ (unsigned)strlen(cases[i].tagName), XML_GetErrorCode(parser)); |
||||||
|
+ failCount++; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
+ XML_ParserFree(parser); |
||||||
|
+ } |
||||||
|
+ } |
||||||
|
+ |
||||||
|
+ if (failCount > 0) { |
||||||
|
+ fail("UTF-8 regression detected"); |
||||||
|
+ } |
||||||
|
+} |
||||||
|
+END_TEST |
||||||
|
+ |
||||||
|
/* Test trailing spaces in elements are accepted */ |
||||||
|
static void XMLCALL |
||||||
|
record_element_end_handler(void *userData, const XML_Char *name) { |
||||||
|
@@ -6175,6 +6274,14 @@ START_TEST(test_bad_doctype) { |
||||||
|
} |
||||||
|
END_TEST |
||||||
|
|
||||||
|
+START_TEST(test_bad_doctype_utf8) { |
||||||
|
+ const char *text = "<!DOCTYPE \xDB\x25" |
||||||
|
+ "doc><doc/>"; // [1101 1011] [<0>010 0101] |
||||||
|
+ expect_failure(text, XML_ERROR_INVALID_TOKEN, |
||||||
|
+ "Invalid UTF-8 in DOCTYPE not faulted"); |
||||||
|
+} |
||||||
|
+END_TEST |
||||||
|
+ |
||||||
|
START_TEST(test_bad_doctype_utf16) { |
||||||
|
const char text[] = |
||||||
|
/* <!DOCTYPE doc [ \x06f2 ]><doc/> |
||||||
|
@@ -11870,6 +11977,7 @@ make_suite(void) { |
||||||
|
tcase_add_test(tc_basic, test_ext_entity_utf8_non_bom); |
||||||
|
tcase_add_test(tc_basic, test_utf8_in_cdata_section); |
||||||
|
tcase_add_test(tc_basic, test_utf8_in_cdata_section_2); |
||||||
|
+ tcase_add_test(tc_basic, test_utf8_in_start_tags); |
||||||
|
tcase_add_test(tc_basic, test_trailing_spaces_in_elements); |
||||||
|
tcase_add_test(tc_basic, test_utf16_attribute); |
||||||
|
tcase_add_test(tc_basic, test_utf16_second_attr); |
||||||
|
@@ -11878,6 +11986,7 @@ make_suite(void) { |
||||||
|
tcase_add_test(tc_basic, test_bad_attr_desc_keyword); |
||||||
|
tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16); |
||||||
|
tcase_add_test(tc_basic, test_bad_doctype); |
||||||
|
+ tcase_add_test(tc_basic, test_bad_doctype_utf8); |
||||||
|
tcase_add_test(tc_basic, test_bad_doctype_utf16); |
||||||
|
tcase_add_test(tc_basic, test_bad_doctype_plus); |
||||||
|
tcase_add_test(tc_basic, test_bad_doctype_star); |
||||||
|
|
@ -0,0 +1,62 @@ |
|||||||
|
diff --git a/lib/xmlparse.c b/lib/xmlparse.c |
||||||
|
index d54af683..5ce31402 100644 |
||||||
|
--- a/lib/xmlparse.c |
||||||
|
+++ b/lib/xmlparse.c |
||||||
|
@@ -2067,6 +2067,11 @@ XML_GetBuffer(XML_Parser parser, int len) { |
||||||
|
keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer); |
||||||
|
if (keep > XML_CONTEXT_BYTES) |
||||||
|
keep = XML_CONTEXT_BYTES; |
||||||
|
+ /* Detect and prevent integer overflow */ |
||||||
|
+ if (keep > INT_MAX - neededSize) { |
||||||
|
+ parser->m_errorCode = XML_ERROR_NO_MEMORY; |
||||||
|
+ return NULL; |
||||||
|
+ } |
||||||
|
neededSize += keep; |
||||||
|
#endif /* defined XML_CONTEXT_BYTES */ |
||||||
|
if (neededSize |
||||||
|
diff --git a/tests/runtests.c b/tests/runtests.c |
||||||
|
index e89e8220..579dad1a 100644 |
||||||
|
--- a/tests/runtests.c |
||||||
|
+++ b/tests/runtests.c |
||||||
|
@@ -3847,6 +3847,30 @@ START_TEST(test_get_buffer_2) { |
||||||
|
} |
||||||
|
END_TEST |
||||||
|
|
||||||
|
+/* Test for signed integer overflow CVE-2022-23852 */ |
||||||
|
+#if defined(XML_CONTEXT_BYTES) |
||||||
|
+START_TEST(test_get_buffer_3_overflow) { |
||||||
|
+ XML_Parser parser = XML_ParserCreate(NULL); |
||||||
|
+ assert(parser != NULL); |
||||||
|
+ |
||||||
|
+ const char *const text = "\n"; |
||||||
|
+ const int expectedKeepValue = (int)strlen(text); |
||||||
|
+ |
||||||
|
+ // After this call, variable "keep" in XML_GetBuffer will |
||||||
|
+ // have value expectedKeepValue |
||||||
|
+ if (XML_Parse(parser, text, (int)strlen(text), XML_FALSE /* isFinal */) |
||||||
|
+ == XML_STATUS_ERROR) |
||||||
|
+ xml_failure(parser); |
||||||
|
+ |
||||||
|
+ assert(expectedKeepValue > 0); |
||||||
|
+ if (XML_GetBuffer(parser, INT_MAX - expectedKeepValue + 1) != NULL) |
||||||
|
+ fail("enlarging buffer not failed"); |
||||||
|
+ |
||||||
|
+ XML_ParserFree(parser); |
||||||
|
+} |
||||||
|
+END_TEST |
||||||
|
+#endif // defined(XML_CONTEXT_BYTES) |
||||||
|
+ |
||||||
|
/* Test position information macros */ |
||||||
|
START_TEST(test_byte_info_at_end) { |
||||||
|
const char *text = "<doc></doc>"; |
||||||
|
@@ -11731,6 +11755,9 @@ make_suite(void) { |
||||||
|
tcase_add_test(tc_basic, test_empty_parse); |
||||||
|
tcase_add_test(tc_basic, test_get_buffer_1); |
||||||
|
tcase_add_test(tc_basic, test_get_buffer_2); |
||||||
|
+#if defined(XML_CONTEXT_BYTES) |
||||||
|
+ tcase_add_test(tc_basic, test_get_buffer_3_overflow); |
||||||
|
+#endif |
||||||
|
tcase_add_test(tc_basic, test_byte_info_at_end); |
||||||
|
tcase_add_test(tc_basic, test_byte_info_at_error); |
||||||
|
tcase_add_test(tc_basic, test_byte_info_at_cdata); |
||||||
|
|
@ -0,0 +1,59 @@ |
|||||||
|
From 0adcb34c49bee5b19bd29b16a578c510c23597ea Mon Sep 17 00:00:00 2001 |
||||||
|
From: Sebastian Pipping <sebastian@pipping.org> |
||||||
|
Date: Mon, 27 Dec 2021 20:15:02 +0100 |
||||||
|
Subject: [PATCH] lib: Detect and prevent troublesome left shifts in function |
||||||
|
storeAtts (CVE-2021-45960) |
||||||
|
|
||||||
|
--- |
||||||
|
expat/lib/xmlparse.c | 31 +++++++++++++++++++++++++++++-- |
||||||
|
1 file changed, 29 insertions(+), 2 deletions(-) |
||||||
|
|
||||||
|
diff --git a/lib/xmlparse.c b/lib/xmlparse.c |
||||||
|
index d730f41c3..b47c31b05 100644 |
||||||
|
--- a/lib/xmlparse.c |
||||||
|
+++ b/lib/xmlparse.c |
||||||
|
@@ -3414,7 +3414,13 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, |
||||||
|
if (nPrefixes) { |
||||||
|
int j; /* hash table index */ |
||||||
|
unsigned long version = parser->m_nsAttsVersion; |
||||||
|
- int nsAttsSize = (int)1 << parser->m_nsAttsPower; |
||||||
|
+ |
||||||
|
+ /* Detect and prevent invalid shift */ |
||||||
|
+ if (parser->m_nsAttsPower >= sizeof(unsigned int) * 8 /* bits per byte */) { |
||||||
|
+ return XML_ERROR_NO_MEMORY; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
+ unsigned int nsAttsSize = 1u << parser->m_nsAttsPower; |
||||||
|
unsigned char oldNsAttsPower = parser->m_nsAttsPower; |
||||||
|
/* size of hash table must be at least 2 * (# of prefixed attributes) */ |
||||||
|
if ((nPrefixes << 1) |
||||||
|
@@ -3425,7 +3431,28 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, |
||||||
|
; |
||||||
|
if (parser->m_nsAttsPower < 3) |
||||||
|
parser->m_nsAttsPower = 3; |
||||||
|
- nsAttsSize = (int)1 << parser->m_nsAttsPower; |
||||||
|
+ |
||||||
|
+ /* Detect and prevent invalid shift */ |
||||||
|
+ if (parser->m_nsAttsPower >= sizeof(nsAttsSize) * 8 /* bits per byte */) { |
||||||
|
+ /* Restore actual size of memory in m_nsAtts */ |
||||||
|
+ parser->m_nsAttsPower = oldNsAttsPower; |
||||||
|
+ return XML_ERROR_NO_MEMORY; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
+ nsAttsSize = 1u << parser->m_nsAttsPower; |
||||||
|
+ |
||||||
|
+ /* 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 (nsAttsSize > (size_t)(-1) / sizeof(NS_ATT)) { |
||||||
|
+ /* Restore actual size of memory in m_nsAtts */ |
||||||
|
+ parser->m_nsAttsPower = oldNsAttsPower; |
||||||
|
+ return XML_ERROR_NO_MEMORY; |
||||||
|
+ } |
||||||
|
+#endif |
||||||
|
+ |
||||||
|
temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts, |
||||||
|
nsAttsSize * sizeof(NS_ATT)); |
||||||
|
if (! temp) { |
@ -0,0 +1,14 @@ |
|||||||
|
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 */ |
||||||
|
|
@ -0,0 +1,139 @@ |
|||||||
|
From eb0362808b4f9f1e2345a0cf203b8cc196d776d9 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Samanta Navarro <ferivoz@riseup.net> |
||||||
|
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 <a>. 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 <err.h> |
||||||
|
#include <expat.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
#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 '<a><' | 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) |
||||||
|
|
@ -0,0 +1,43 @@ |
|||||||
|
From 85ae9a2d7d0e9358f356b33977b842df8ebaec2b Mon Sep 17 00:00:00 2001 |
||||||
|
From: Sebastian Pipping <sebastian@pipping.org> |
||||||
|
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) |
@ -0,0 +1,250 @@ |
|||||||
|
From 9f93e8036e842329863bf20395b8fb8f73834d9e Mon Sep 17 00:00:00 2001 |
||||||
|
From: Sebastian Pipping <sebastian@pipping.org> |
||||||
|
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) |
@ -0,0 +1,255 @@ |
|||||||
|
commit 37b45d8ff0f92a7ea0491dd61a0bceb951af332e |
||||||
|
Author: Tomas Korbar <tkorbar@redhat.com> |
||||||
|
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 = "<!DOCTYPE foo [\n" |
||||||
|
+ "<!ELEMENT junk ((bar|foo|xyz+), zebra*)>\n" |
||||||
|
+ "]>\n" |
||||||
|
+ "<foo/>"; |
||||||
|
+ |
||||||
|
+ 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 = "<?xml version='1.0' encoding='us-ascii'?>\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); |
@ -0,0 +1,228 @@ |
|||||||
|
commit 5c47ae80738d0985babf06a023b3845169682064 |
||||||
|
Author: Tomas Korbar <tkorbar@redhat.com> |
||||||
|
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, "<doc xmlns='one_two' />", XCS('\n')}, |
||||||
|
+ {XML_STATUS_ERROR, "<doc xmlns='one
two' />", XCS('\n')}, |
||||||
|
+ {XML_STATUS_OK, "<doc xmlns='one:two' />", 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); |
@ -0,0 +1,42 @@ |
|||||||
|
From ede41d1e186ed2aba88a06e84cac839b770af3a1 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Sebastian Pipping <sebastian@pipping.org> |
||||||
|
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; |
||||||
|
} |
@ -0,0 +1,410 @@ |
|||||||
|
%global unversion 2_2_10 |
||||||
|
|
||||||
|
Summary: An XML parser library |
||||||
|
Name: expat |
||||||
|
Version: %(echo %{unversion} | sed 's/_/./g') |
||||||
|
Release: 12%{?dist}.2 |
||||||
|
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 |
||||||
|
|
||||||
|
%description |
||||||
|
This is expat, the C library for parsing XML, written by James Clark. Expat |
||||||
|
is a stream oriented XML parser. This means that you register handlers with |
||||||
|
the parser prior to starting the parse. These handlers are called when the |
||||||
|
parser discovers the associated structures in the document being parsed. A |
||||||
|
start tag is an example of the kind of structures for which you may |
||||||
|
register handlers. |
||||||
|
|
||||||
|
%package devel |
||||||
|
Summary: Libraries and header files to develop applications using expat |
||||||
|
Requires: expat%{?_isa} = %{version}-%{release} |
||||||
|
|
||||||
|
%description devel |
||||||
|
The expat-devel package contains the libraries, include files and documentation |
||||||
|
to develop XML applications with expat. |
||||||
|
|
||||||
|
%package static |
||||||
|
Summary: expat XML parser static library |
||||||
|
Requires: expat-devel%{?_isa} = %{version}-%{release} |
||||||
|
|
||||||
|
%description static |
||||||
|
The expat-static package contains the static version of the expat library. |
||||||
|
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 |
||||||
|
|
||||||
|
sed -i 's/install-data-hook/do-nothing-please/' lib/Makefile.am |
||||||
|
./buildconf.sh |
||||||
|
|
||||||
|
%build |
||||||
|
export CFLAGS="$RPM_OPT_FLAGS -fPIC" |
||||||
|
export DOCBOOK_TO_MAN="xmlto man --skip-validation" |
||||||
|
%configure |
||||||
|
%make_build |
||||||
|
|
||||||
|
%install |
||||||
|
%make_install |
||||||
|
|
||||||
|
rm -f $RPM_BUILD_ROOT%{_libdir}/*.la |
||||||
|
|
||||||
|
%check |
||||||
|
make check |
||||||
|
|
||||||
|
%ldconfig_scriptlets |
||||||
|
|
||||||
|
%files |
||||||
|
%doc AUTHORS Changes |
||||||
|
%license COPYING |
||||||
|
%{_bindir}/* |
||||||
|
%{_libdir}/lib*.so.* |
||||||
|
%{_mandir}/*/* |
||||||
|
|
||||||
|
%files devel |
||||||
|
%doc doc/reference.html doc/*.png doc/*.css examples/*.c |
||||||
|
%{_libdir}/lib*.so |
||||||
|
%{_libdir}/pkgconfig/*.pc |
||||||
|
%{_includedir}/*.h |
||||||
|
|
||||||
|
%files static |
||||||
|
%{_libdir}/lib*.a |
||||||
|
|
||||||
|
%changelog |
||||||
|
* Tue May 03 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-12.2 |
||||||
|
- Improve fix for CVE-2022-25313 |
||||||
|
- Related: CVE-2022-25313 |
||||||
|
|
||||||
|
* Tue Apr 26 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-12.1 |
||||||
|
- Fix multiple CVEs |
||||||
|
- Resolves: CVE-2022-25314 |
||||||
|
- Resolves: CVE-2022-25313 |
||||||
|
|
||||||
|
* Wed Mar 16 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-12 |
||||||
|
- Build fix for CVE-2022-25236 in rhel-9.0.0 |
||||||
|
- Related: 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 |
||||||
|
|
||||||
|
* 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 |
||||||
|
- CVE-2022-25315 expat: integer overflow in storeRawNames() |
||||||
|
- Resolves: CVE-2022-25236 |
||||||
|
- Resolves: CVE-2022-25235 |
||||||
|
- Resolves: CVE-2022-25315 |
||||||
|
|
||||||
|
* 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-22827 |
||||||
|
- Resolves: CVE-2022-22826 |
||||||
|
- Resolves: CVE-2022-22825 |
||||||
|
- Resolves: CVE-2022-22824 |
||||||
|
- Resolves: CVE-2022-22823 |
||||||
|
- Resolves: CVE-2022-22822 |
||||||
|
|
||||||
|
* 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 |
||||||
|
|
||||||
|
* Sat Feb 03 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 2.2.5-2 |
||||||
|
- Switch to %%ldconfig_scriptlets |
||||||
|
|
||||||
|
* Thu Nov 2 2017 Joe Orton <jorton@redhat.com> - 2.2.5-1 |
||||||
|
- update to 2.2.5 (#1508667) |
||||||
|
|
||||||
|
* Mon Aug 21 2017 Joe Orton <jorton@redhat.com> - 2.2.4-1 |
||||||
|
- update to 2.2.4 (#1483359) |
||||||
|
|
||||||
|
* Fri Aug 4 2017 Joe Orton <jorton@redhat.com> - 2.2.3-1 |
||||||
|
- fix tests with unsigned char (upstream PR 109) |
||||||
|
- update to 2.2.3 (#1473266) |
||||||
|
|
||||||
|
* Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.2-4 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild |
||||||
|
|
||||||
|
* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.2-3 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild |
||||||
|
|
||||||
|
* Fri Jul 14 2017 Joe Orton <jorton@redhat.com> - 2.2.2-2 |
||||||
|
- update to 2.2.2 (#1470891) |
||||||
|
|
||||||
|
* Fri Jul 7 2017 Joe Orton <jorton@redhat.com> - 2.2.1-2 |
||||||
|
- trim unnecessary doc, examples content |
||||||
|
|
||||||
|
* Mon Jun 19 2017 Joe Orton <jorton@redhat.com> - 2.2.1-1 |
||||||
|
- update to 2.2.1 (#1462474) |
||||||
|
|
||||||
|
* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.0-2 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild |
||||||
|
|
||||||
|
* Tue Jun 21 2016 Joe Orton <jorton@redhat.com> - 2.2.0-1 |
||||||
|
- update to 2.2.0 (#1247348) |
||||||
|
|
||||||
|
* Thu Jun 16 2016 Joe Orton <jorton@redhat.com> - 2.1.1-2 |
||||||
|
- add security fixes for CVE-2016-0718, CVE-2012-6702, CVE-2016-5300, |
||||||
|
CVE-2016-4472 |
||||||
|
|
||||||
|
* Mon Apr 18 2016 David Tardon <dtardon@redhat.com> - 2.1.1-1 |
||||||
|
- new upstream release |
||||||
|
|
||||||
|
* Wed Feb 03 2016 Fedora Release Engineering <releng@fedoraproject.org> - 2.1.0-13 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild |
||||||
|
|
||||||
|
* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.1.0-12 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild |
||||||
|
|
||||||
|
* Sat Feb 21 2015 Till Maas <opensource@till.name> - 2.1.0-11 |
||||||
|
- Rebuilt for Fedora 23 Change |
||||||
|
https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code |
||||||
|
|
||||||
|
* Sat Aug 16 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.1.0-10 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild |
||||||
|
|
||||||
|
* Sat Jul 12 2014 Tom Callaway <spot@fedoraproject.org> - 2.1.0-9 |
||||||
|
- fix license handling |
||||||
|
|
||||||
|
* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.1.0-8 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild |
||||||
|
|
||||||
|
* Sat Aug 03 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.1.0-7 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild |
||||||
|
|
||||||
|
* Mon Jun 17 2013 Joe Orton <jorton@redhat.com> - 2.1.0-6 |
||||||
|
- fix "xmlwf -h" output (#948534) |
||||||
|
|
||||||
|
* Wed Feb 13 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.1.0-5 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild |
||||||
|
|
||||||
|
* Thu Jul 19 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.1.0-4 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild |
||||||
|
|
||||||
|
* Fri Apr 13 2012 Joe Orton <jorton@redhat.com> - 2.1.0-3 |
||||||
|
- add -static subpackage (#722647) |
||||||
|
|
||||||
|
* Fri Mar 30 2012 Joe Orton <jorton@redhat.com> - 2.1.0-1 |
||||||
|
- ship .pc file, move library back to libdir (#808399) |
||||||
|
|
||||||
|
* Mon Mar 26 2012 Joe Orton <jorton@redhat.com> - 2.1.0-1 |
||||||
|
- update to 2.1.0 (#806602) |
||||||
|
|
||||||
|
* Fri Jan 13 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.1-12 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild |
||||||
|
|
||||||
|
* Tue Feb 08 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.1-11 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild |
||||||
|
|
||||||
|
* Mon Feb 8 2010 Joe Orton <jorton@redhat.com> - 2.0.1-10 |
||||||
|
- revised fix for CVE-2009-3560 regression (#544996) |
||||||
|
|
||||||
|
* Sun Jan 31 2010 Joe Orton <jorton@redhat.com> - 2.0.1-9 |
||||||
|
- drop static libraries (#556046) |
||||||
|
- add fix for regression in CVE-2009-3560 patch (#544996) |
||||||
|
|
||||||
|
* Tue Dec 1 2009 Joe Orton <jorton@redhat.com> - 2.0.1-8 |
||||||
|
- add security fix for CVE-2009-3560 (#533174) |
||||||
|
- add security fix for CVE-2009-3720 (#531697) |
||||||
|
- run the test suite |
||||||
|
|
||||||
|
* Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.1-7 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild |
||||||
|
|
||||||
|
* Tue Feb 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.1-6 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild |
||||||
|
|
||||||
|
* Tue Feb 19 2008 Fedora Release Engineering <rel-eng@fedoraproject.org> - 2.0.1-5 |
||||||
|
- Autorebuild for GCC 4.3 |
||||||
|
|
||||||
|
* Wed Jan 23 2008 Joe Orton <jorton@redhat.com> 2.0.1-4 |
||||||
|
- chmod 644 even more documentation (#429806) |
||||||
|
|
||||||
|
* Tue Jan 8 2008 Joe Orton <jorton@redhat.com> 2.0.1-3 |
||||||
|
- chmod 644 the documentation (#427950) |
||||||
|
|
||||||
|
* Wed Aug 22 2007 Joe Orton <jorton@redhat.com> 2.0.1-2 |
||||||
|
- rebuild |
||||||
|
|
||||||
|
* Wed Aug 8 2007 Joe Orton <jorton@redhat.com> 2.0.1-1 |
||||||
|
- update to 2.0.1 |
||||||
|
- fix the License tag |
||||||
|
- drop the .la file |
||||||
|
|
||||||
|
* Sun Feb 4 2007 Joe Orton <jorton@redhat.com> 1.95.8-10 |
||||||
|
- remove trailing dot in Summary (#225742) |
||||||
|
- use preferred BuildRoot per packaging guidelines (#225742) |
||||||
|
|
||||||
|
* Tue Jan 30 2007 Joe Orton <jorton@redhat.com> 1.95.8-9 |
||||||
|
- regenerate configure/libtool correctly (#199361) |
||||||
|
- strip DSP files from examples (#186889) |
||||||
|
- fix expat.h compilation with g++ -pedantic (#190244) |
||||||
|
|
||||||
|
* Wed Jul 12 2006 Jesse Keating <jkeating@redhat.com> - 1.95.8-8.2.1 |
||||||
|
- rebuild |
||||||
|
|
||||||
|
* Fri Feb 10 2006 Jesse Keating <jkeating@redhat.com> - 1.95.8-8.2 |
||||||
|
- bump again for double-long bug on ppc(64) |
||||||
|
|
||||||
|
* Tue Feb 07 2006 Jesse Keating <jkeating@redhat.com> - 1.95.8-8.1 |
||||||
|
- rebuilt for new gcc4.1 snapshot and glibc changes |
||||||
|
|
||||||
|
* Tue Jan 31 2006 Joe Orton <jorton@redhat.com> 1.95.8-8 |
||||||
|
- restore .la file for apr-util |
||||||
|
|
||||||
|
* Mon Jan 30 2006 Joe Orton <jorton@redhat.com> 1.95.8-7 |
||||||
|
- move library to /lib (#178743) |
||||||
|
- omit .la file (#170031) |
||||||
|
|
||||||
|
* Fri Dec 09 2005 Jesse Keating <jkeating@redhat.com> |
||||||
|
- rebuilt |
||||||
|
|
||||||
|
* Tue Mar 8 2005 Joe Orton <jorton@redhat.com> 1.95.8-6 |
||||||
|
- rebuild |
||||||
|
|
||||||
|
* Thu Nov 25 2004 Ivana Varekova <varekova@redhat.com> 1.95.8 |
||||||
|
- update to 1.95.8 |
||||||
|
|
||||||
|
* Wed Jun 16 2004 Jeff Johnson <jbj@jbj.org> 1.95.7-4 |
||||||
|
- add -fPIC (#125586). |
||||||
|
|
||||||
|
* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com> |
||||||
|
- rebuilt |
||||||
|
|
||||||
|
* Fri Jun 11 2004 Jeff Johnson <jbj@jbj.org> 1.95.7-2 |
||||||
|
- fix: malloc failure from dbus test suite (#124747). |
||||||
|
|
||||||
|
* Tue Mar 02 2004 Elliot Lee <sopwith@redhat.com> |
||||||
|
- rebuilt |
||||||
|
|
||||||
|
* Sun Feb 22 2004 Joe Orton <jorton@redhat.com> 1.95.7-1 |
||||||
|
- update to 1.95.7, include COPYING file in main package |
||||||
|
|
||||||
|
* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com> |
||||||
|
- rebuilt |
||||||
|
|
||||||
|
* Wed Sep 17 2003 Matt Wilson <msw@redhat.com> 1.95.5-6 |
||||||
|
- rebuild again for #91211 |
||||||
|
|
||||||
|
* Tue Sep 16 2003 Matt Wilson <msw@redhat.com> 1.95.5-5 |
||||||
|
- rebuild to fix gzip'ed file md5sums (#91211) |
||||||
|
|
||||||
|
* Tue Jun 17 2003 Jeff Johnson <jbj@redhat.com> 1.95.5-4 |
||||||
|
- rebuilt because of crt breakage on ppc64. |
||||||
|
|
||||||
|
* Wed Jun 04 2003 Elliot Lee <sopwith@redhat.com> |
||||||
|
- rebuilt |
||||||
|
|
||||||
|
* Wed Jan 22 2003 Tim Powers <timp@redhat.com> |
||||||
|
- rebuilt |
||||||
|
|
||||||
|
* Mon Nov 11 2002 Jeff Johnson <jbj@redhat.com> 1.95.5-1 |
||||||
|
- update to 1.95.5. |
||||||
|
|
||||||
|
* Mon Aug 19 2002 Trond Eivind Glomsrød <teg@redhat.com> 1,95.4-1 |
||||||
|
- 1.95.4. 1.95.3 was withdrawn by the expat developers. |
||||||
|
|
||||||
|
* Fri Jun 21 2002 Tim Powers <timp@redhat.com> |
||||||
|
- automated rebuild |
||||||
|
|
||||||
|
* Thu Jun 6 2002 Trond Eivind Glomsrød <teg@redhat.com> 1,95.3-1 |
||||||
|
- 1.95.3 |
||||||
|
|
||||||
|
* Thu May 23 2002 Tim Powers <timp@redhat.com> |
||||||
|
- automated rebuild |
||||||
|
|
||||||
|
* Fri Mar 22 2002 Trond Eivind Glomsrød <teg@redhat.com> |
||||||
|
- Change a prereq in -devel on main package to a req |
||||||
|
- License from MIT/X11 to BSD |
||||||
|
|
||||||
|
* Mon Mar 11 2002 Trond Eivind Glomsrød <teg@redhat.com> |
||||||
|
- 1.95.2 |
||||||
|
|
||||||
|
* Sun Jun 24 2001 Elliot Lee <sopwith@redhat.com> |
||||||
|
- Bump release + rebuild. |
||||||
|
|
||||||
|
* Tue Oct 24 2000 Jeff Johnson <jbj@redhat.com> |
||||||
|
- update to 1.95.1 |
||||||
|
|
||||||
|
* Sun Oct 8 2000 Jeff Johnson <jbj@redhat.com> |
||||||
|
- Create. |
Loading…
Reference in new issue