commit a739613cfb5ee60919bd5ad545a5582fa8a6dad9 Author: Tomas Korbar Date: Mon Nov 14 12:37:16 2022 +0100 Fix CVE-2022-43680 diff --git a/lib/xmlparse.c b/lib/xmlparse.c index 0cc24f6..3f765f7 100644 --- a/lib/xmlparse.c +++ b/lib/xmlparse.c @@ -1016,6 +1016,14 @@ parserCreate(const XML_Char *encodingName, parserInit(parser, encodingName); if (encodingName && !parser->m_protocolEncodingName) { + if (dtd) { + // We need to stop the upcoming call to XML_ParserFree from happily + // destroying parser->m_dtd because the DTD is shared with the parent + // parser and the only guard that keeps XML_ParserFree from destroying + // parser->m_dtd is parser->m_isParamEntity but it will be set to + // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all). + parser->m_dtd = NULL; + } XML_ParserFree(parser); return NULL; } diff --git a/tests/runtests.c b/tests/runtests.c index f3ebbd7..f58f794 100644 --- a/tests/runtests.c +++ b/tests/runtests.c @@ -10819,6 +10819,48 @@ START_TEST(test_alloc_long_notation) } END_TEST +static int XMLCALL +external_entity_parser_create_alloc_fail_handler(XML_Parser parser, + const XML_Char *context, + const XML_Char *UNUSED_P(base), + const XML_Char *UNUSED_P(systemId), + const XML_Char *UNUSED_P(publicId)) { + if (context != NULL) + fail("Unexpected non-NULL context"); + + // The following number intends to fail the upcoming allocation in line + // "parser->m_protocolEncodingName = copyString(encodingName, + // &(parser->m_mem));" in function parserInit. + allocation_count = 3; + + const XML_Char *const encodingName = XCS("UTF-8"); // needs something non-NULL + const XML_Parser ext_parser + = XML_ExternalEntityParserCreate(parser, context, encodingName); + if (ext_parser != NULL) + fail( + "Call to XML_ExternalEntityParserCreate was expected to fail out-of-memory"); + + allocation_count = ALLOC_ALWAYS_SUCCEED; + return XML_STATUS_ERROR; +} + +START_TEST(test_alloc_reset_after_external_entity_parser_create_fail) { + const char *const text = ""; + + XML_SetExternalEntityRefHandler( + parser, external_entity_parser_create_alloc_fail_handler); + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + + if (XML_Parse(parser, text, (int)strlen(text), XML_TRUE) + != XML_STATUS_ERROR) + fail("Call to parse was expected to fail"); + + if (XML_GetErrorCode(parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING) + fail("Call to parse was expected to fail from the external entity handler"); + + XML_ParserReset(parser, NULL); +} +END_TEST static void nsalloc_setup(void) @@ -12653,6 +12695,10 @@ make_suite(void) tcase_add_test(tc_alloc, test_alloc_long_entity_value); tcase_add_test(tc_alloc, test_alloc_long_notation); + #ifdef XML_DTD + tcase_add_test(tc_alloc, + test_alloc_reset_after_external_entity_parser_create_fail); + #endif suite_add_tcase(s, tc_nsalloc); tcase_add_checked_fixture(tc_nsalloc, nsalloc_setup, nsalloc_teardown); tcase_add_test(tc_nsalloc, test_nsalloc_xmlns);