diff options
author | Sebastian Pipping <sebastian@pipping.org> | 2022-10-24 16:34:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-24 16:34:19 +0200 |
commit | 56967f83d68d5fc750f9e66a9a76756c94c7c173 (patch) | |
tree | 627ca92b49d7de0d2b2d0708fc14bee4522a6d6d | |
parent | 5ac714074d2639e0b8bb82aa73ef51c4f7498d29 (diff) | |
parent | eedc5f6de8e219130032c8ff2ff17580e18bd0c1 (diff) | |
download | libexpat-git-56967f83d68d5fc750f9e66a9a76756c94c7c173.tar.gz |
Merge pull request #650 from libexpat/issue-649-fix-overeager-dtd-destruction
[CVE-2022-43680] Fix overeager DTD destruction (fixes #649)
-rw-r--r-- | expat/Changes | 5 | ||||
-rw-r--r-- | expat/lib/xmlparse.c | 8 | ||||
-rw-r--r-- | expat/tests/runtests.c | 49 |
3 files changed, 62 insertions, 0 deletions
diff --git a/expat/Changes b/expat/Changes index ea7d7e4c..6985707e 100644 --- a/expat/Changes +++ b/expat/Changes @@ -3,6 +3,11 @@ NOTE: We are looking for help with a few things: If you can help, please get in touch. Thanks! Release x.x.x xxx xxxxxxxxxxxx xx xxxx + Security fixes: + #616 #649 #650 CVE-2022-43680 -- Fix heap use-after-free after overeager + destruction of a shared DTD in function + XML_ExternalEntityParserCreate in out-of-memory situations + Bug fixes: #612 #645 Fix curruption from undefined entities #613 #654 Fix case when parsing was suspended while processing nested diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c index aacd6e7f..57bf103c 100644 --- a/expat/lib/xmlparse.c +++ b/expat/lib/xmlparse.c @@ -1068,6 +1068,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/expat/tests/runtests.c b/expat/tests/runtests.c index 245fe9bd..acb744dd 100644 --- a/expat/tests/runtests.c +++ b/expat/tests/runtests.c @@ -10208,6 +10208,53 @@ 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 *base, + const XML_Char *systemId, + const XML_Char *publicId) { + UNUSED_P(base); + UNUSED_P(systemId); + 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 = "<!DOCTYPE doc SYSTEM 'foo'><doc/>"; + + XML_SetExternalEntityRefHandler( + g_parser, external_entity_parser_create_alloc_fail_handler); + XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + + if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) + != XML_STATUS_ERROR) + fail("Call to parse was expected to fail"); + + if (XML_GetErrorCode(g_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING) + fail("Call to parse was expected to fail from the external entity handler"); + + XML_ParserReset(g_parser, NULL); +} +END_TEST + static void nsalloc_setup(void) { XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free}; @@ -12401,6 +12448,8 @@ make_suite(void) { tcase_add_test(tc_alloc, test_alloc_long_public_id); tcase_add_test(tc_alloc, test_alloc_long_entity_value); tcase_add_test(tc_alloc, test_alloc_long_notation); + tcase_add_test__ifdef_xml_dtd( + tc_alloc, test_alloc_reset_after_external_entity_parser_create_fail); suite_add_tcase(s, tc_nsalloc); tcase_add_checked_fixture(tc_nsalloc, nsalloc_setup, nsalloc_teardown); |