mirror of
https://git.yoctoproject.org/poky
synced 2026-05-30 12:29:55 +00:00
expat: patch CVE-2026-32778
Pick patches from [1] also mentioned in [2]. [1] https://github.com/libexpat/libexpat/pull/1163 [2] https://security-tracker.debian.org/tracker/CVE-2026-32778 (From OE-Core rev: ea404c36732a4e3882a74707189b10a4a196df07) Signed-off-by: Bruno VERNAY <bruno.vernay@se.com> Signed-off-by: Hugo SIMELIERE <hsimeliere.opensource@witekio.com> Signed-off-by: Fabien Thomas <fabien.thomas@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev>
This commit is contained in:
committed by
Paul Barker
parent
290f91a9c3
commit
6d5cd210ab
@@ -0,0 +1,91 @@
|
||||
From b878628b560a2ba1e11b3a12ff8df0dab7d6b8bb Mon Sep 17 00:00:00 2001
|
||||
From: laserbear <10689391+Laserbear@users.noreply.github.com>
|
||||
Date: Sun, 8 Mar 2026 17:28:06 -0700
|
||||
Subject: [PATCH 1/2] copy prefix name to pool before lookup
|
||||
|
||||
.. so that we cannot end up with a zombie PREFIX in the pool
|
||||
that has NULL for a name.
|
||||
|
||||
CVE: CVE-2026-32778
|
||||
Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/576b61e42feeea704253cb7c7bedb2eeb3754387]
|
||||
|
||||
Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
|
||||
(cherry picked from commit 576b61e42feeea704253cb7c7bedb2eeb3754387)
|
||||
Signed-off-by: Hugo SIMELIERE <simeliere.hugo@non.se.com>
|
||||
---
|
||||
lib/xmlparse.c | 43 +++++++++++++++++++++++++++++++++++--------
|
||||
1 file changed, 35 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index bfb8ac58..9bc67f38 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -590,6 +590,8 @@ static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
|
||||
static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
|
||||
static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool,
|
||||
const XML_Char *s);
|
||||
+static const XML_Char *FASTCALL poolCopyStringNoFinish(STRING_POOL *pool,
|
||||
+ const XML_Char *s);
|
||||
static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s,
|
||||
int n);
|
||||
static const XML_Char *FASTCALL poolAppendString(STRING_POOL *pool,
|
||||
@@ -7443,16 +7445,24 @@ setContext(XML_Parser parser, const XML_Char *context) {
|
||||
else {
|
||||
if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
|
||||
return XML_FALSE;
|
||||
- prefix
|
||||
- = (PREFIX *)lookup(parser, &dtd->prefixes,
|
||||
- poolStart(&parser->m_tempPool), sizeof(PREFIX));
|
||||
- if (! prefix)
|
||||
+ const XML_Char *const prefixName = poolCopyStringNoFinish(
|
||||
+ &dtd->pool, poolStart(&parser->m_tempPool));
|
||||
+ if (! prefixName) {
|
||||
return XML_FALSE;
|
||||
- if (prefix->name == poolStart(&parser->m_tempPool)) {
|
||||
- prefix->name = poolCopyString(&dtd->pool, prefix->name);
|
||||
- if (! prefix->name)
|
||||
- return XML_FALSE;
|
||||
}
|
||||
+
|
||||
+ prefix = (PREFIX *)lookup(parser, &dtd->prefixes, prefixName,
|
||||
+ sizeof(PREFIX));
|
||||
+
|
||||
+ const bool prefixNameUsed = prefix && prefix->name == prefixName;
|
||||
+ if (prefixNameUsed)
|
||||
+ poolFinish(&dtd->pool);
|
||||
+ else
|
||||
+ poolDiscard(&dtd->pool);
|
||||
+
|
||||
+ if (! prefix)
|
||||
+ return XML_FALSE;
|
||||
+
|
||||
poolDiscard(&parser->m_tempPool);
|
||||
}
|
||||
for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0');
|
||||
@@ -8041,6 +8051,23 @@ poolCopyString(STRING_POOL *pool, const XML_Char *s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
+// A version of `poolCopyString` that does not call `poolFinish`
|
||||
+// and reverts any partial advancement upon failure.
|
||||
+static const XML_Char *FASTCALL
|
||||
+poolCopyStringNoFinish(STRING_POOL *pool, const XML_Char *s) {
|
||||
+ const XML_Char *const original = s;
|
||||
+ do {
|
||||
+ if (! poolAppendChar(pool, *s)) {
|
||||
+ // Revert any previously successful advancement
|
||||
+ const ptrdiff_t advancedBy = s - original;
|
||||
+ if (advancedBy > 0)
|
||||
+ pool->ptr -= advancedBy;
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ } while (*s++);
|
||||
+ return pool->start;
|
||||
+}
|
||||
+
|
||||
static const XML_Char *
|
||||
poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) {
|
||||
if (! pool->ptr && ! poolGrow(pool)) {
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
From c26728576de3850258c7762c036dd0eb7783ea15 Mon Sep 17 00:00:00 2001
|
||||
From: laserbear <10689391+Laserbear@users.noreply.github.com>
|
||||
Date: Sun, 8 Mar 2026 17:28:06 -0700
|
||||
Subject: [PATCH 2/2] test that we do not end up with a zombie PREFIX in the
|
||||
pool
|
||||
|
||||
CVE: CVE-2026-32778
|
||||
Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/d5fa769b7a7290a7e2c4a0b2287106dec9b3c030]
|
||||
|
||||
(cherry picked from commit d5fa769b7a7290a7e2c4a0b2287106dec9b3c030)
|
||||
Signed-off-by: Hugo SIMELIERE <simeliere.hugo@non.se.com>
|
||||
---
|
||||
tests/nsalloc_tests.c | 27 +++++++++++++++++++++++++++
|
||||
1 file changed, 27 insertions(+)
|
||||
|
||||
diff --git a/tests/nsalloc_tests.c b/tests/nsalloc_tests.c
|
||||
index a8f5718d..d284a58a 100644
|
||||
--- a/tests/nsalloc_tests.c
|
||||
+++ b/tests/nsalloc_tests.c
|
||||
@@ -1505,6 +1505,32 @@ START_TEST(test_nsalloc_prefixed_element) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
+/* Verify that retry after OOM in setContext() does not crash.
|
||||
+ */
|
||||
+START_TEST(test_nsalloc_setContext_zombie) {
|
||||
+ const char *text = "<doc>Hello</doc>";
|
||||
+ unsigned int i;
|
||||
+ const unsigned int max_alloc_count = 30;
|
||||
+
|
||||
+ for (i = 0; i < max_alloc_count; i++) {
|
||||
+ g_allocation_count = (int)i;
|
||||
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
+ != XML_STATUS_ERROR)
|
||||
+ break;
|
||||
+ /* Retry on the same parser — must not crash */
|
||||
+ g_allocation_count = ALLOC_ALWAYS_SUCCEED;
|
||||
+ XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE);
|
||||
+
|
||||
+ nsalloc_teardown();
|
||||
+ nsalloc_setup();
|
||||
+ }
|
||||
+ if (i == 0)
|
||||
+ fail("Parsing worked despite failing allocations");
|
||||
+ else if (i == max_alloc_count)
|
||||
+ fail("Parsing failed even at maximum allocation count");
|
||||
+}
|
||||
+END_TEST
|
||||
+
|
||||
void
|
||||
make_nsalloc_test_case(Suite *s) {
|
||||
TCase *tc_nsalloc = tcase_create("namespace allocation tests");
|
||||
@@ -1539,4 +1565,5 @@ make_nsalloc_test_case(Suite *s) {
|
||||
tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_long_default_in_ext);
|
||||
tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
|
||||
tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
|
||||
+ tcase_add_test(tc_nsalloc, test_nsalloc_setContext_zombie);
|
||||
}
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -49,6 +49,8 @@ SRC_URI = "${GITHUB_BASE_URI}/download/R_${VERSION_TAG}/expat-${PV}.tar.bz2 \
|
||||
file://CVE-2026-32776.patch \
|
||||
file://CVE-2026-32777-01.patch \
|
||||
file://CVE-2026-32777-02.patch \
|
||||
file://CVE-2026-32778-01.patch \
|
||||
file://CVE-2026-32778-02.patch \
|
||||
"
|
||||
|
||||
GITHUB_BASE_URI = "https://github.com/libexpat/libexpat/releases/"
|
||||
|
||||
Reference in New Issue
Block a user