Backport patch to fix CVE-2026-56131. References: https://nvd.nist.gov/vuln/detail/CVE-2026-56131
Upstream fix: https://github.com/libexpat/libexpat/commit/d5a654b4881f450827af5b3b7b72370a3bbf9a8f Signed-off-by: Jakub Szczudlo <[email protected]> --- .../expat/expat/CVE-2026-56131.patch | 124 ++++++++++++++++++ meta/recipes-core/expat/expat_2.7.5.bb | 1 + 2 files changed, 125 insertions(+) create mode 100644 meta/recipes-core/expat/expat/CVE-2026-56131.patch diff --git a/meta/recipes-core/expat/expat/CVE-2026-56131.patch b/meta/recipes-core/expat/expat/CVE-2026-56131.patch new file mode 100644 index 0000000000..8691f98f89 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2026-56131.patch @@ -0,0 +1,124 @@ +From 29dfca6ad4d2a9dfd5ce72efd72e1b67d598ab4c Mon Sep 17 00:00:00 2001 +From: netliomax25-code <[email protected]> +Date: Sat, 6 Jun 2026 20:03:53 +0530 +Subject: [PATCH] lib: protect XML_ResumeParser from being called from a + handler + +The handler-reentrancy guards from CVE-2026-50219 cover XML_Parse, XML_ParseBuffer, XML_GetBuffer, XML_ParserFree and XML_ParserReset but not XML_ResumeParser, which drives the parser through callProcessor in the same way. + +(cherry picked from commit d5a654b4881f450827af5b3b7b72370a3bbf9a8f) + +CVE: CVE-2026-56131 +Upstream-Status: Backport [https://github.com/libexpat/libexpat/pull/1267/commits/d5a654b4881f450827af5b3b7b72370a3bbf9a8f] +Signed-off-by: Jakub Szczudlo <[email protected]> +--- + lib/xmlparse.c | 2 +- + tests/handlers.c | 24 ++++++++++++++++++++++++ + tests/handlers.h | 9 +++++++++ + tests/misc_tests.c | 20 ++++++++++++++++++++ + 4 files changed, 54 insertions(+), 1 deletion(-) + +diff --git a/lib/xmlparse.c b/lib/xmlparse.c +index cc1d550..a5fa256 100644 +--- a/lib/xmlparse.c ++++ b/lib/xmlparse.c +@@ -2778,7 +2778,7 @@ enum XML_Status XMLCALL + XML_ResumeParser(XML_Parser parser) { + enum XML_Status result = XML_STATUS_OK; + +- if (parser == NULL) ++ if ((parser == NULL) || isCalledFromInsideHandler(parser)) + return XML_STATUS_ERROR; + if (parser->m_parsingStatus.parsing != XML_SUSPENDED) { + parser->m_errorCode = XML_ERROR_NOT_SUSPENDED; +diff --git a/tests/handlers.c b/tests/handlers.c +index c7d6578..5a85f6d 100644 +--- a/tests/handlers.c ++++ b/tests/handlers.c +@@ -2015,3 +2015,27 @@ forbidden_calls_character_handler(void *userData, const XML_Char *s, int len) { + + assert_true(XML_GetErrorCode(parser) == XML_ERROR_NONE); + } ++ ++void XMLCALL ++suspend_then_resume_character_handler(void *userData, const XML_Char *s, ++ int len) { ++ UNUSED_P(s); ++ UNUSED_P(len); ++ ResumeFromHandlerData *const data = (ResumeFromHandlerData *)userData; ++ ++ data->callCount++; ++ if (data->callCount > 1) { ++ // Reached only if the guard under test is missing: XML_ResumeParser would ++ // then have driven the parser re-entrantly and called us again. Bail out ++ // so the test fails by assertion below rather than recursing without bound. ++ return; ++ } ++ ++ // Put the parser into XML_SUSPENDED so that, without the guard, ++ // XML_ResumeParser would proceed into a re-entrant parse. ++ assert_true(XML_StopParser(data->parser, /*resumable=*/XML_TRUE) ++ == XML_STATUS_OK); ++ ++ // Resuming the parser from inside a handler must be rejected. ++ assert_true(XML_ResumeParser(data->parser) == XML_STATUS_ERROR); ++} +diff --git a/tests/handlers.h b/tests/handlers.h +index de28392..507ad8b 100644 +--- a/tests/handlers.h ++++ b/tests/handlers.h +@@ -616,6 +616,15 @@ extern void XMLCALL forbidden_calls_character_handler(void *userData, + const XML_Char *s, + int len); + ++typedef struct { ++ XML_Parser parser; ++ int callCount; ++} ResumeFromHandlerData; ++ ++extern void XMLCALL suspend_then_resume_character_handler(void *userData, ++ const XML_Char *s, ++ int len); ++ + #endif /* XML_HANDLERS_H */ + + #ifdef __cplusplus +diff --git a/tests/misc_tests.c b/tests/misc_tests.c +index b9053fe..265e7cb 100644 +--- a/tests/misc_tests.c ++++ b/tests/misc_tests.c +@@ -815,6 +815,25 @@ START_TEST(test_misc_calls_forbidden_from_handlers) { + } + END_TEST + ++START_TEST(test_misc_resume_parser_forbidden_from_handler) { ++ const char *const doc = "<doc>Hello world!</doc>"; ++ ++ XML_Parser parser = XML_ParserCreate(NULL); ++ ResumeFromHandlerData data = {parser, 0}; ++ XML_SetUserData(parser, &data); ++ XML_SetCharacterDataHandler(parser, suspend_then_resume_character_handler); ++ ++ // The handler suspends the parser, so the top-level parse reports suspension ++ // rather than completion. The handler also asserts that resuming from inside ++ // itself is rejected. ++ assert_true(XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_TRUE) ++ == XML_STATUS_SUSPENDED); ++ assert_true(data.callCount == 1); ++ ++ XML_ParserFree(parser); ++} ++END_TEST ++ + void + make_miscellaneous_test_case(Suite *s) { + TCase *tc_misc = tcase_create("miscellaneous tests"); +@@ -847,4 +866,5 @@ make_miscellaneous_test_case(Suite *s) { + tcase_add_test(tc_misc, test_misc_async_entity_rejected); + tcase_add_test(tc_misc, test_misc_no_infinite_loop_issue_1161); + tcase_add_test(tc_misc, test_misc_calls_forbidden_from_handlers); ++ tcase_add_test(tc_misc, test_misc_resume_parser_forbidden_from_handler); + } +-- +2.34.1 + diff --git a/meta/recipes-core/expat/expat_2.7.5.bb b/meta/recipes-core/expat/expat_2.7.5.bb index 7f00c6f90b..78e35243c5 100644 --- a/meta/recipes-core/expat/expat_2.7.5.bb +++ b/meta/recipes-core/expat/expat_2.7.5.bb @@ -68,6 +68,7 @@ SRC_URI = "${GITHUB_BASE_URI}/download/R_${VERSION_TAG}/expat-${PV}.tar.bz2 \ file://CVE-2026-50219-30.patch \ file://CVE-2026-50219-31.patch \ file://CVE-2026-50219-32.patch \ + file://CVE-2026-56131.patch \ " GITHUB_BASE_URI = "https://github.com/libexpat/libexpat/releases/" -- 2.34.1
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#244128): https://lists.openembedded.org/g/openembedded-core/message/244128 Mute This Topic: https://lists.openembedded.org/mt/120905064/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
