mirror of
git://git.yoctoproject.org/poky.git
synced 2025-07-19 12:59:02 +02:00
expat: patch CVE-2024-8176
Backport https://github.com/libexpat/libexpat/pull/973 Patch created by: git diff 2fc36833334340ff7ddca374d86daa8744c1dfa3..99529768b4a722f46c69b04b874c1d45b3eb819c Additional backport (containing changes in tests only) was needed to apply it cleanly. Additional backport https://github.com/libexpat/libexpat/pull/989 which has fixed regression of the first fix. Patch created by: git diff 91ca72e913af94ed44ef2a80a9dd542be3e5766c..308c31ed647f2c6aebe33ca3a4fa9e1436f461e2 (From OE-Core rev: 3ece58813faaf4e5f66c7b52f736e84615ccfef6) Signed-off-by: Peter Marko <peter.marko@siemens.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
This commit is contained in:
parent
2af52d4819
commit
5ceb4646d2
|
@ -0,0 +1,103 @@
|
|||
From 3d5fdbb44e80ed789e4f6510542d77d6284fbd0e Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Sat, 23 Nov 2024 14:20:21 +0100
|
||||
Subject: [PATCH] tests: Cover indirect entity recursion
|
||||
|
||||
Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/3d5fdbb44e80ed789e4f6510542d77d6284fbd0e]
|
||||
Signed-off-by: Peter Marko <peter.marko@siemens.com>
|
||||
---
|
||||
expat/tests/basic_tests.c | 74 +++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 74 insertions(+)
|
||||
|
||||
diff --git a/expat/tests/basic_tests.c b/expat/tests/basic_tests.c
|
||||
index d38b8fd1..d2306772 100644
|
||||
--- a/expat/tests/basic_tests.c
|
||||
+++ b/expat/tests/basic_tests.c
|
||||
@@ -1202,6 +1202,79 @@ START_TEST(test_wfc_no_recursive_entity_refs) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
+START_TEST(test_no_indirectly_recursive_entity_refs) {
|
||||
+ struct TestCase {
|
||||
+ const char *doc;
|
||||
+ bool usesParameterEntities;
|
||||
+ };
|
||||
+
|
||||
+ const struct TestCase cases[] = {
|
||||
+ // general entity + character data
|
||||
+ {"<!DOCTYPE a [\n"
|
||||
+ " <!ENTITY e1 '&e2;'>\n"
|
||||
+ " <!ENTITY e2 '&e1;'>\n"
|
||||
+ "]><a>&e2;</a>\n",
|
||||
+ false},
|
||||
+
|
||||
+ // general entity + attribute value
|
||||
+ {"<!DOCTYPE a [\n"
|
||||
+ " <!ENTITY e1 '&e2;'>\n"
|
||||
+ " <!ENTITY e2 '&e1;'>\n"
|
||||
+ "]><a k1='&e2;' />\n",
|
||||
+ false},
|
||||
+
|
||||
+ // parameter entity
|
||||
+ {"<!DOCTYPE doc [\n"
|
||||
+ " <!ENTITY % p1 '%p2;'>\n"
|
||||
+ " <!ENTITY % p2 '%p1;'>\n"
|
||||
+ " <!ENTITY % define_g \"<!ENTITY g '%p2;'>\">\n"
|
||||
+ " %define_g;\n"
|
||||
+ "]>\n"
|
||||
+ "<doc/>\n",
|
||||
+ true},
|
||||
+ };
|
||||
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
|
||||
+ const char *const doc = cases[i].doc;
|
||||
+ const bool usesParameterEntities = cases[i].usesParameterEntities;
|
||||
+
|
||||
+ set_subtest("[%i] %s", (int)i, doc);
|
||||
+
|
||||
+#ifdef XML_DTD // both GE and DTD
|
||||
+ const bool rejection_expected = true;
|
||||
+#elif XML_GE == 1 // GE but not DTD
|
||||
+ const bool rejection_expected = ! usesParameterEntities;
|
||||
+#else // neither DTD nor GE
|
||||
+ const bool rejection_expected = false;
|
||||
+#endif
|
||||
+
|
||||
+ XML_Parser parser = XML_ParserCreate(NULL);
|
||||
+
|
||||
+#ifdef XML_DTD
|
||||
+ if (usesParameterEntities) {
|
||||
+ assert_true(
|
||||
+ XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)
|
||||
+ == 1);
|
||||
+ }
|
||||
+#else
|
||||
+ UNUSED_P(usesParameterEntities);
|
||||
+#endif // XML_DTD
|
||||
+
|
||||
+ const enum XML_Status status
|
||||
+ = _XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
|
||||
+ /*isFinal*/ XML_TRUE);
|
||||
+
|
||||
+ if (rejection_expected) {
|
||||
+ assert_true(status == XML_STATUS_ERROR);
|
||||
+ assert_true(XML_GetErrorCode(parser) == XML_ERROR_RECURSIVE_ENTITY_REF);
|
||||
+ } else {
|
||||
+ assert_true(status == XML_STATUS_OK);
|
||||
+ }
|
||||
+
|
||||
+ XML_ParserFree(parser);
|
||||
+ }
|
||||
+}
|
||||
+END_TEST
|
||||
+
|
||||
START_TEST(test_recursive_external_parameter_entity_2) {
|
||||
struct TestCase {
|
||||
const char *doc;
|
||||
@@ -5969,6 +6042,7 @@ make_basic_test_case(Suite *s) {
|
||||
tcase_add_test(tc_basic, test_not_standalone_handler_reject);
|
||||
tcase_add_test(tc_basic, test_not_standalone_handler_accept);
|
||||
tcase_add_test__if_xml_ge(tc_basic, test_wfc_no_recursive_entity_refs);
|
||||
+ tcase_add_test(tc_basic, test_no_indirectly_recursive_entity_refs);
|
||||
tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_invalid_parse);
|
||||
tcase_add_test__if_xml_ge(tc_basic, test_dtd_default_handling);
|
||||
tcase_add_test(tc_basic, test_dtd_attr_handling);
|
1477
meta/recipes-core/expat/expat/CVE-2024-8176-01.patch
Normal file
1477
meta/recipes-core/expat/expat/CVE-2024-8176-01.patch
Normal file
File diff suppressed because it is too large
Load Diff
248
meta/recipes-core/expat/expat/CVE-2024-8176-02.patch
Normal file
248
meta/recipes-core/expat/expat/CVE-2024-8176-02.patch
Normal file
|
@ -0,0 +1,248 @@
|
|||
From 5f7af592557495a99e7badaf5c03362a20650156 Mon Sep 17 00:00:00 2001
|
||||
From: Peter Marko <peter.marko@siemens.com>
|
||||
Date: Thu, 27 Mar 2025 20:28:26 +0100
|
||||
Subject: [PATCH] Stop updating event pointer on exit for reentry (fixes #980)
|
||||
#989
|
||||
|
||||
Fixes #980
|
||||
|
||||
CVE: CVE-2024-8176
|
||||
Upstream-Status: Backport [https://github.com/libexpat/libexpat/pull/989]
|
||||
Signed-off-by: Peter Marko <peter.marko@siemens.com>
|
||||
---
|
||||
expat/Changes | 15 ++++++++++++
|
||||
expat/lib/xmlparse.c | 12 ++++++---
|
||||
expat/tests/common.c | 25 +++++++++++++++++++
|
||||
expat/tests/common.h | 2 ++
|
||||
expat/tests/misc_tests.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
5 files changed, 112 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/expat/Changes b/expat/Changes
|
||||
index 8c5db88c..7ba33497 100644
|
||||
--- a/expat/Changes
|
||||
+++ b/expat/Changes
|
||||
@@ -30,6 +30,21 @@
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
Patches:
|
||||
+ Bug fixes:
|
||||
+ #980 #989 Restore event pointer behavior from Expat 2.6.4
|
||||
+ (that the fix to CVE-2024-8176 changed in 2.7.0);
|
||||
+ affected API functions are:
|
||||
+ - XML_GetCurrentByteCount
|
||||
+ - XML_GetCurrentByteIndex
|
||||
+ - XML_GetCurrentColumnNumber
|
||||
+ - XML_GetCurrentLineNumber
|
||||
+ - XML_GetInputContext
|
||||
+
|
||||
+ Special thanks to:
|
||||
+ Berkay Eren Ürün
|
||||
+ and
|
||||
+ Perl XML::Parser
|
||||
+
|
||||
Security fixes:
|
||||
#893 #??? CVE-2024-8176 -- Fix crash from chaining a large number
|
||||
of entities caused by stack overflow by resolving use of
|
||||
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
|
||||
index 473c791d..c6085d38 100644
|
||||
--- a/expat/lib/xmlparse.c
|
||||
+++ b/expat/lib/xmlparse.c
|
||||
@@ -3402,12 +3402,13 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
||||
break;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
- *eventPP = s = next;
|
||||
switch (parser->m_parsingStatus.parsing) {
|
||||
case XML_SUSPENDED:
|
||||
+ *eventPP = next;
|
||||
*nextPtr = next;
|
||||
return XML_ERROR_NONE;
|
||||
case XML_FINISHED:
|
||||
+ *eventPP = next;
|
||||
return XML_ERROR_ABORTED;
|
||||
case XML_PARSING:
|
||||
if (parser->m_reenter) {
|
||||
@@ -3416,6 +3417,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
||||
}
|
||||
/* Fall through */
|
||||
default:;
|
||||
+ *eventPP = s = next;
|
||||
}
|
||||
}
|
||||
/* not reached */
|
||||
@@ -4332,12 +4334,13 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
- *eventPP = s = next;
|
||||
switch (parser->m_parsingStatus.parsing) {
|
||||
case XML_SUSPENDED:
|
||||
+ *eventPP = next;
|
||||
*nextPtr = next;
|
||||
return XML_ERROR_NONE;
|
||||
case XML_FINISHED:
|
||||
+ *eventPP = next;
|
||||
return XML_ERROR_ABORTED;
|
||||
case XML_PARSING:
|
||||
if (parser->m_reenter) {
|
||||
@@ -4345,6 +4348,7 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
||||
}
|
||||
/* Fall through */
|
||||
default:;
|
||||
+ *eventPP = s = next;
|
||||
}
|
||||
}
|
||||
/* not reached */
|
||||
@@ -5951,12 +5955,13 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
|
||||
default:
|
||||
return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
|
||||
}
|
||||
- parser->m_eventPtr = s = next;
|
||||
switch (parser->m_parsingStatus.parsing) {
|
||||
case XML_SUSPENDED:
|
||||
+ parser->m_eventPtr = next;
|
||||
*nextPtr = next;
|
||||
return XML_ERROR_NONE;
|
||||
case XML_FINISHED:
|
||||
+ parser->m_eventPtr = next;
|
||||
return XML_ERROR_ABORTED;
|
||||
case XML_PARSING:
|
||||
if (parser->m_reenter) {
|
||||
@@ -5964,6 +5969,7 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
|
||||
}
|
||||
/* Fall through */
|
||||
default:;
|
||||
+ parser->m_eventPtr = s = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/expat/tests/common.c b/expat/tests/common.c
|
||||
index 3aea8d74..b267dbb3 100644
|
||||
--- a/expat/tests/common.c
|
||||
+++ b/expat/tests/common.c
|
||||
@@ -42,6 +42,8 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
+#include <errno.h>
|
||||
+#include <stdint.h> // for SIZE_MAX
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -294,3 +296,26 @@ duff_reallocator(void *ptr, size_t size) {
|
||||
g_reallocation_count--;
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
+
|
||||
+// Portable remake of strndup(3) for C99; does not care about space efficiency
|
||||
+char *
|
||||
+portable_strndup(const char *s, size_t n) {
|
||||
+ if ((s == NULL) || (n == SIZE_MAX)) {
|
||||
+ errno = EINVAL;
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ char *const buffer = (char *)malloc(n + 1);
|
||||
+ if (buffer == NULL) {
|
||||
+ errno = ENOMEM;
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ errno = 0;
|
||||
+
|
||||
+ memcpy(buffer, s, n);
|
||||
+
|
||||
+ buffer[n] = '\0';
|
||||
+
|
||||
+ return buffer;
|
||||
+}
|
||||
diff --git a/expat/tests/common.h b/expat/tests/common.h
|
||||
index bc4c7da6..88711308 100644
|
||||
--- a/expat/tests/common.h
|
||||
+++ b/expat/tests/common.h
|
||||
@@ -146,6 +146,8 @@ extern void *duff_allocator(size_t size);
|
||||
|
||||
extern void *duff_reallocator(void *ptr, size_t size);
|
||||
|
||||
+extern char *portable_strndup(const char *s, size_t n);
|
||||
+
|
||||
#endif /* XML_COMMON_H */
|
||||
|
||||
#ifdef __cplusplus
|
||||
diff --git a/expat/tests/misc_tests.c b/expat/tests/misc_tests.c
|
||||
index f9a78f66..2b9f793b 100644
|
||||
--- a/expat/tests/misc_tests.c
|
||||
+++ b/expat/tests/misc_tests.c
|
||||
@@ -561,6 +561,66 @@ START_TEST(test_renter_loop_finite_content) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
+// Inspired by function XML_OriginalString of Perl's XML::Parser
|
||||
+static char *
|
||||
+dup_original_string(XML_Parser parser) {
|
||||
+ const int byte_count = XML_GetCurrentByteCount(parser);
|
||||
+
|
||||
+ assert_true(byte_count >= 0);
|
||||
+
|
||||
+ int offset = -1;
|
||||
+ int size = -1;
|
||||
+
|
||||
+ const char *const context = XML_GetInputContext(parser, &offset, &size);
|
||||
+
|
||||
+#if XML_CONTEXT_BYTES > 0
|
||||
+ assert_true(context != NULL);
|
||||
+ assert_true(offset >= 0);
|
||||
+ assert_true(size >= 0);
|
||||
+ return portable_strndup(context + offset, byte_count);
|
||||
+#else
|
||||
+ assert_true(context == NULL);
|
||||
+ return NULL;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+on_characters_issue_980(void *userData, const XML_Char *s, int len) {
|
||||
+ (void)s;
|
||||
+ (void)len;
|
||||
+ XML_Parser parser = (XML_Parser)userData;
|
||||
+
|
||||
+ char *const original_string = dup_original_string(parser);
|
||||
+
|
||||
+#if XML_CONTEXT_BYTES > 0
|
||||
+ assert_true(original_string != NULL);
|
||||
+ assert_true(strcmp(original_string, "&draft.day;") == 0);
|
||||
+ free(original_string);
|
||||
+#else
|
||||
+ assert_true(original_string == NULL);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+START_TEST(test_misc_expected_event_ptr_issue_980) {
|
||||
+ // NOTE: This is a tiny subset of sample "REC-xml-19980210.xml"
|
||||
+ // from Perl's XML::Parser
|
||||
+ const char *const doc = "<!DOCTYPE day [\n"
|
||||
+ " <!ENTITY draft.day '10'>\n"
|
||||
+ "]>\n"
|
||||
+ "<day>&draft.day;</day>\n";
|
||||
+
|
||||
+ XML_Parser parser = XML_ParserCreate(NULL);
|
||||
+ XML_SetUserData(parser, parser);
|
||||
+ XML_SetCharacterDataHandler(parser, on_characters_issue_980);
|
||||
+
|
||||
+ assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
|
||||
+ /*isFinal=*/XML_TRUE)
|
||||
+ == XML_STATUS_OK);
|
||||
+
|
||||
+ XML_ParserFree(parser);
|
||||
+}
|
||||
+END_TEST
|
||||
+
|
||||
void
|
||||
make_miscellaneous_test_case(Suite *s) {
|
||||
TCase *tc_misc = tcase_create("miscellaneous tests");
|
||||
@@ -588,4 +648,5 @@ make_miscellaneous_test_case(Suite *s) {
|
||||
tcase_add_test(tc_misc, test_misc_resumeparser_not_crashing);
|
||||
tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser);
|
||||
tcase_add_test__if_xml_ge(tc_misc, test_renter_loop_finite_content);
|
||||
+ tcase_add_test(tc_misc, test_misc_expected_event_ptr_issue_980);
|
||||
}
|
|
@ -10,6 +10,9 @@ VERSION_TAG = "${@d.getVar('PV').replace('.', '_')}"
|
|||
|
||||
SRC_URI = "${GITHUB_BASE_URI}/download/R_${VERSION_TAG}/expat-${PV}.tar.bz2 \
|
||||
file://run-ptest \
|
||||
file://0001-tests-Cover-indirect-entity-recursion.patch;striplevel=2 \
|
||||
file://CVE-2024-8176-01.patch;striplevel=2 \
|
||||
file://CVE-2024-8176-02.patch;striplevel=2 \
|
||||
"
|
||||
|
||||
GITHUB_BASE_URI = "https://github.com/libexpat/libexpat/releases/"
|
||||
|
|
Loading…
Reference in New Issue
Block a user