Merge pull request #915 from libexpat/stop-resumeparser-from-crashing

[CVE-2024-50602] Stop `XML_ResumeParser` from crashing
This commit is contained in:
Sebastian Pipping 2024-10-28 15:14:02 +01:00 committed by GitHub
commit ef485e96a6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 37 additions and 2 deletions

View file

@ -130,7 +130,9 @@ enum XML_Error {
/* Added in 2.3.0. */
XML_ERROR_NO_BUFFER,
/* Added in 2.4.0. */
XML_ERROR_AMPLIFICATION_LIMIT_BREACH
XML_ERROR_AMPLIFICATION_LIMIT_BREACH,
/* Added in 2.6.4. */
XML_ERROR_NOT_STARTED,
};
enum XML_Content_Type {

View file

@ -2234,6 +2234,9 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) {
if (parser == NULL)
return XML_STATUS_ERROR;
switch (parser->m_parsingStatus.parsing) {
case XML_INITIALIZED:
parser->m_errorCode = XML_ERROR_NOT_STARTED;
return XML_STATUS_ERROR;
case XML_SUSPENDED:
if (resumable) {
parser->m_errorCode = XML_ERROR_SUSPENDED;
@ -2244,7 +2247,7 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) {
case XML_FINISHED:
parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
default:
case XML_PARSING:
if (resumable) {
#ifdef XML_DTD
if (parser->m_isParamEntity) {
@ -2255,6 +2258,9 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) {
parser->m_parsingStatus.parsing = XML_SUSPENDED;
} else
parser->m_parsingStatus.parsing = XML_FINISHED;
break;
default:
assert(0);
}
return XML_STATUS_OK;
}
@ -2519,6 +2525,9 @@ XML_ErrorString(enum XML_Error code) {
case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
return XML_L(
"limit on input amplification factor (from DTD and entities) breached");
/* Added in 2.6.4. */
case XML_ERROR_NOT_STARTED:
return XML_L("parser not started");
}
return NULL;
}

View file

@ -496,6 +496,28 @@ START_TEST(test_misc_char_handler_stop_without_leak) {
}
END_TEST
START_TEST(test_misc_resumeparser_not_crashing) {
XML_Parser parser = XML_ParserCreate(NULL);
XML_GetBuffer(parser, 1);
XML_StopParser(parser, /*resumable=*/XML_TRUE);
XML_ResumeParser(parser); // could crash here, previously
XML_ParserFree(parser);
}
END_TEST
START_TEST(test_misc_stopparser_rejects_unstarted_parser) {
const XML_Bool cases[] = {XML_TRUE, XML_FALSE};
for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
const XML_Bool resumable = cases[i];
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(XML_GetErrorCode(parser) == XML_ERROR_NONE);
assert_true(XML_StopParser(parser, resumable) == XML_STATUS_ERROR);
assert_true(XML_GetErrorCode(parser) == XML_ERROR_NOT_STARTED);
XML_ParserFree(parser);
}
}
END_TEST
void
make_miscellaneous_test_case(Suite *s) {
TCase *tc_misc = tcase_create("miscellaneous tests");
@ -520,4 +542,6 @@ make_miscellaneous_test_case(Suite *s) {
test_misc_create_external_entity_parser_with_null_context);
tcase_add_test(tc_misc, test_misc_general_entities_support);
tcase_add_test(tc_misc, test_misc_char_handler_stop_without_leak);
tcase_add_test(tc_misc, test_misc_resumeparser_not_crashing);
tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser);
}