From 81a114f7eebcd41a6993337128cda337986a26f4 Mon Sep 17 00:00:00 2001 From: Sebastian Pipping Date: Mon, 15 Sep 2025 21:57:07 +0200 Subject: [PATCH] tests: Cover XML_ERROR_ASYNC_ENTITY cases CVE: CVE-2024-8176 Upstream-Status: Backport [https://github.com/libexpat/libexpat/pull/1059] Signed-off-by: Peter Marko --- tests/misc_tests.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 3346bce6..19f41df7 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -621,6 +621,91 @@ START_TEST(test_misc_expected_event_ptr_issue_980) { } END_TEST +START_TEST(test_misc_sync_entity_tolerated) { + const char *const doc = "'>\n" + " two'>\n" + " threefourthree'>\n" + " &b;'>\n" + "]>\n" + "&a;&b;&c;&d;\n"; + XML_Parser parser = XML_ParserCreate(NULL); + + assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), + /*isFinal=*/XML_TRUE) + == XML_STATUS_OK); + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_misc_async_entity_rejected) { + struct test_case { + const char *doc; + enum XML_Status expectedStatusNoGE; + enum XML_Error expectedErrorNoGE; + }; + const struct test_case cases[] = { + // Opened by one entity, closed by another + {"'>\n" + " '>\n" + "]>\n" + "&open;&close;\n", + XML_STATUS_OK, XML_ERROR_NONE}, + // Opened by tag, closed by entity (non-root case) + {"\n" + " '>\n" + "]>\n" + "&g1;\n", + XML_STATUS_ERROR, XML_ERROR_TAG_MISMATCH}, + // Opened by tag, closed by entity (root case) + {"\n" + " '>\n" + "]>\n" + "&g1;\n", + XML_STATUS_ERROR, XML_ERROR_NO_ELEMENTS}, + // Opened by entity, closed by tag <-- regression from 2.7.0 + {"\n" + " &g0;'>\n" + "]>\n" + "&g1;\n", + XML_STATUS_ERROR, XML_ERROR_TAG_MISMATCH}, + // Opened by tag, closed by entity; then the other way around + {"'>\n" + " '>\n" + "]>\n" + "&close;&open;\n", + XML_STATUS_OK, XML_ERROR_NONE}, + }; + + for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { + const struct test_case testCase = cases[i]; + set_subtest("cases[%d]", (int)i); + + const char *const doc = testCase.doc; +#if XML_GE == 1 + const enum XML_Status expectedStatus = XML_STATUS_ERROR; + const enum XML_Error expectedError = XML_ERROR_ASYNC_ENTITY; +#else + const enum XML_Status expectedStatus = testCase.expectedStatusNoGE; + const enum XML_Error expectedError = testCase.expectedErrorNoGE; +#endif + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), + /*isFinal=*/XML_TRUE) + == expectedStatus); + assert_true(XML_GetErrorCode(parser) == expectedError); + XML_ParserFree(parser); + } +} +END_TEST + void make_miscellaneous_test_case(Suite *s) { TCase *tc_misc = tcase_create("miscellaneous tests"); @@ -649,4 +734,6 @@ make_miscellaneous_test_case(Suite *s) { 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); + tcase_add_test(tc_misc, test_misc_sync_entity_tolerated); + tcase_add_test(tc_misc, test_misc_async_entity_rejected); }