From patchwork Mon Jul 6 12:04:12 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Amaury Couderc X-Patchwork-Id: 91805 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 636E8C43458 for ; Mon, 6 Jul 2026 12:04:48 +0000 (UTC) Received: from MRWPR03CU001.outbound.protection.outlook.com (MRWPR03CU001.outbound.protection.outlook.com [40.107.130.64]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.149493.1783339484291106105 for ; Mon, 06 Jul 2026 05:04:44 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: body hash did not verify" header.i=@est.tech header.s=selector1 header.b=kgx5syMY; spf=pass (domain: est.tech, ip: 40.107.130.64, mailfrom: amaury.couderc@est.tech) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=sBvrvmVzsAO4bCRozB+hIyF3ThjrX29J2JZSe4ZFjekosaIqRSLEey3lyKOQYq5x6DXaQFGtx+86V4/0X+VOrRKUB2aQdsr7qT1i2eoJediThLKBjSVyhKmRo/Xgy3MwYLy/9xGyKI7zayCRGuOHnN7ZKNBvpqJ3unTBBWPhcaYMi8x3pDVk9F0IM0PhNVCk2KxBa/R6eZrY8hmN7gyiW38mHDz07knJmrM1kSkezPKwB9Bpu56KfNsXBENbSjoPNCSU5hcCCwEWpG1HVHFm9Ma80DDEnZ6cHHxkLKLmGM9fjJ5DRr7Y9gtID3b63uYpBshlNaB9kOILNh54B4EMqQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=qYod/6gpdkEy4Saiy26AkdSX0KC77exdOTOQhuXwH6E=; b=AvPb1/0sqUF8jXolh9fxLvHAzfqIQwygPgnt3B4gruNJhfIAkMnqD7rz6qjtFtlPi71e9iBKmTemw809myEbyuUraHjHyt7Mf/0wnzmu6B7A2ap2YT/yh1qxUV8MCzvPlRfKhnwEooX9EO++iYeawtN7FmYUW1P7ablOm5AOG6g/KX1qlW4NRwNxcUjKQvwJT12i35AMWkXjimRaVsE2BGmNKdH7Q1/M5HNNqcgNFYY5zjGZGfs9MhMigJpRtjWZ3tNLlxLO5PMBMkgFjrVrgJo0YowujQ13NaJAxX17fTHsVBDLNUcwasl4+3gpwxv0snLmGRieT2aOkiy+xF4YfA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=est.tech; dmarc=pass action=none header.from=est.tech; dkim=pass header.d=est.tech; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=est.tech; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=qYod/6gpdkEy4Saiy26AkdSX0KC77exdOTOQhuXwH6E=; b=kgx5syMYzT5R0lZHrx+opJ7M2aVHyGoUoP5+QY/iszBvL0lY/+LB85i6NfHd8aPakSVTz55hoKupjfMi6i0olEGN1/yAvFPnFlByElAVaHJGKHpDVyE5NZYs8FCihfipPCQc3bhM43H1fowIKMeFS5nkNpy/sWhQ8CmW0EYl1vrc12RmUro7sT0LMVi8UzWyxTx6HgMe558gKgtuiZRZjT0X9VZdYsJaNEcIyiGAObSdwkHH8LlzkkeLlGKvHxpZ6yx9VahM0I+fnlvMvtmkCAsIRoMGloLmY/USPsi+kknC5Oy8xOmGgT/cmK2C6tp3MHusi6FPKQFt2emHszqrTA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=est.tech; Received: from AMBP189MB3196.EURP189.PROD.OUTLOOK.COM (2603:10a6:20b:6ad::11) by GV2P189MB2453.EURP189.PROD.OUTLOOK.COM (2603:10a6:150:d3::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.181.11; Mon, 6 Jul 2026 12:04:38 +0000 Received: from AMBP189MB3196.EURP189.PROD.OUTLOOK.COM ([fe80::1afd:f059:542:3d95]) by AMBP189MB3196.EURP189.PROD.OUTLOOK.COM ([fe80::1afd:f059:542:3d95%4]) with mapi id 15.21.0181.008; Mon, 6 Jul 2026 12:04:38 +0000 From: amaury.couderc@est.tech To: openembedded-core@lists.openembedded.org Subject: [PATCH 1/2][wrynose] expat: fix CVE-2026-41080 Date: Mon, 6 Jul 2026 14:04:12 +0200 Message-ID: <20260706120430.37403-1-amaury.couderc@est.tech> X-Mailer: git-send-email 2.43.0 X-ClientProxiedBy: DU2P250CA0020.EURP250.PROD.OUTLOOK.COM (2603:10a6:10:231::25) To AMBP189MB3196.EURP189.PROD.OUTLOOK.COM (2603:10a6:20b:6ad::11) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AMBP189MB3196:EE_|GV2P189MB2453:EE_ X-MS-Office365-Filtering-Correlation-Id: eca2f79a-6672-45b1-74b1-08dedb56c095 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|23010399003|18002099003|56012099006|11063799006|5023799004|6133799003|13003099007; X-Microsoft-Antispam-Message-Info: DmXiZ/M6vTjI67j2Ruhbx3+wXlnjdfRJACkO7Zo8djrQ48L3pSyUP8xgAZdhEE3mgMz9OBNNupeQP2WvqePE2d0YCUhTVQ8jOmG+xC2izqoJWggbNVrwsYU68xl8n0C2vewBRr9UUCNtP11XgFiElaR029mMMfsJQMsltvjUFXwrDoABQ4/rzsVZG9hJl6EZjlIgsiEFTdCwGLXfz320tEgmRHf6nuafRjDQzpKKDi/gTEq1rgLG4dRpvJEO+6rCPv6u2u3oHg/2edAm+cOFzJthad1Q02f8tLq4YPjFE+oP8PHZ2DmQGiXpnNzTO8rR8QKKL5az3qwj9LjLf9YxBD/2v6MCu4G8xwpSEV56mwatdCKLlihMXwKgrHFgUYWaKccs92dgHuA8Dzhuc1k8EK5y4NpiHeyBQv/4LG2vKg08hxgjzEU9K/fGrt/hCuGf0U7woIBJ/Jph1SvomI+gBnZtX818mNj0tRNS7OIxyKpNj4IY4ZFs76fIs5f54Wun4/cBs6r9ENW7BFbjkvyiahCkIVT4djy4mq1PLffYoZNFUB4tg5hMUYHTLY8rsZg7mHhQ+7mYexyG1VJ1ZjUoaBKUeGWqK0mvJc27X9v5U1gB+VLWVV7c6mesP0Fkh/E+gC+lDg5uYorxqMHsFL43jHt4XnMJmWL6TXsxn3MIhII= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:AMBP189MB3196.EURP189.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(366016)(1800799024)(23010399003)(18002099003)(56012099006)(11063799006)(5023799004)(6133799003)(13003099007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 102hq1HNPiXMHmWrQmHLQg/GkYITbdRMnGUFXlV2oxrlb1NuAEf1rpV9MeVihkOIcpLZnPATQaC8gTEvGYkhX8VKnAiN0mw6Ru76glkCTPgCxQ4Sh7gm11+jxG4zJj90utsaTGqMO+WDWA5E/HnlUcPxgR6Ncs02x4uIpNv9/WvA29oFzIJylbejC7RoivO3c5AXm4Buh9LeWC561Xknhqkh8j+40RoFLjdxVO3QIWwsXSoy/Y4eR9VbT2qpqjEi/1nlUqdoAtGGr9qI3lYiCcLSAW4G8vCnm4f5QkIMSZ8X+GbBumvhi5zuFT/A6diApaTFKAos/x8rxZBTZfArtBIQEbg4+9RkG2YEd+8sJ549ypW0EmcHYAKl4dBQ81BwJum4tRu2E+HC2GVw0eJVM+hTA+E1YkU/ojgiVWiIcQrGxWoOghZSbqXCmhr4XYPdFQv3otzjox3Wa5Wyg0Fa5p+z1PdO3j/c7XMcdbrYwaC1vPADgIjVT6/mUUd2dEPny2k2FmJ0+hhfTuIH3MAVoxTv71RK9VuEsUk3r3aV81qERLs7LoUoJ/g+/HhDzRyRUmIMQRh67DYQAzVhaf4mcyt4OrWBLBhBzrhMhmF0u5iSc6b94FwAKnUxlLdhMqbXhcPW+eYtxASC9NU03zPhtI0rkW7stUbu09VFKBoSj+6kVLbCsDth0w/NyM+Z9aLQyLT8iUOYfXKLUs5JOR2n1yaLyy+MFmv4QJKoa+pM2IMo6xslFOKag5Uc2SAR3GgnHcRZNhbAorNhvy32zhZmmIyKLW3hz8YMdKrZkI92mqM1s+DHaX3ZfKPyXLHktNselOXeac7lt7xHEfCsTYbSoEi2oOumJcSgBH18GeJoc+nu1aZFnQGcalukgvVXMUXQkLUzRomY806Iwd1g+/HE7aksvPJVq5vq8ragms2NAcB4+S/YwWRiw9iwkFOGGxVM7D9TGl42ttz4euMQDmGfnahUhRY6MabZmadq1PpMNjD7XSnQZexPiXKxFrM5GhyNWwnIi4gvKjG1L00PU0XgHSWJJ8tkEshbSt8OC4BKrbLMwxeAohU2JJrp74zNNSwuPxHbl2YIvwOvay2GqVpcfUehvsxHAe82eHOzWw9+2Xq29rT5WlU6Yts1NK8oE6Sx8XBT/o/8AskyvBPkb5lJ8Bu6igi2AU1hxtxv6fQ9+6qowllu1DVG7WOE1DIrU+R2GyIHG7fzR4PcVUYedD/eZ6hG/rIEfhwd+alHFvkruuGKaPgj/E9oCheHlt6MtkDCe7f2vPuz6nHAOiKvK1Q3Qkl2TwfiO7Iz50jHnYCK5ICzYvfsSZ94QpkWTKK2KKBU88fwkp0P2id2UED4sGwe/WAX3yB6X7OdS7nCTZPZZseX39QTC95SNKLj6hnbbiSh03opEuarV3cAFaCytMJJIcGVKpBRlC7lndjyGR92Z59Awf8gpA/xBsaUbg1aauxJtDPnMKU4YqN3geMNzUYB4XtBtgPhLClAke5Ee4qufzxC0/W2iok31jWROyeNd0MWBvIjIsLS0vpYGcGxjzZZpQxNnHxxuw4zqVP0ZMOyoj+0DCeODuogJxTnNQxMzeiyVYvIEjYXgyBdlJviPyloB5c2YJofnxSabNSRq2cUH+7bmRaZL0wkikXXLBCEYeLjXyeTiHrXAh+JPTkD9+TwSqBVtf8Uxq6yCWDzT3+TQHPSZ5aAHG7D/exU0B8yg5vnQh5QO/AhbiX7czcNPYEO1A== X-OriginatorOrg: est.tech X-MS-Exchange-CrossTenant-Network-Message-Id: eca2f79a-6672-45b1-74b1-08dedb56c095 X-MS-Exchange-CrossTenant-AuthSource: AMBP189MB3196.EURP189.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 06 Jul 2026 12:04:37.9583 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: d2585e63-66b9-44b6-a76e-4f4b217d97fd X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: tjTbyDZk7migq5m76sKqaKGIr+9W1MWK/DmGqIzgxL1NpO7IeaTPJSOz+Fn/9Fd4b8wG94QHZLuu1m3v3c3tHQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GV2P189MB2453 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 06 Jul 2026 12:04:48 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/240261 From: Amaury Couderc The existing hash flooding protection (based on SipHash) only used 4 to 8 bytes of entropy for a salt, when 16 bytes of salt are supported by the implementation of SipHash used by Expat. Now full 16 bytes of entropy are used to improve protection against hash flooding attacks. Introduces new API function XML_SetHashSalt16Bytes and deprecates the legacy XML_SetHashSalt which is limited to 4-8 bytes. The fix is split into 3 patches for reviewability: 1. Core entropy changes: migrates hash salt storage to struct sipkey, extracts 16 bytes of entropy, and introduces m_hash_secret_salt_set. 2. New API: adds XML_SetHashSalt16Bytes, deprecates XML_SetHashSalt, updates documentation, symbol exports, and tests. 3. Windows/cmake: adds the missing .def export for the new symbol. Backport patch to fix CVE-2026-41080 https://nvd.nist.gov/vuln/detail/CVE-2026-41080 Upstream fix: https://github.com/libexpat/libexpat/pull/1183 CVE: CVE-2026-41080 Signed-off-by: Amaury Couderc --- .../expat/expat/CVE-2026-41080-1.patch | 251 ++++++++++++++ .../expat/expat/CVE-2026-41080-2.patch | 310 ++++++++++++++++++ .../expat/expat/CVE-2026-41080-3.patch | 32 ++ meta/recipes-core/expat/expat_2.7.5.bb | 3 + 4 files changed, 596 insertions(+) create mode 100644 meta/recipes-core/expat/expat/CVE-2026-41080-1.patch create mode 100644 meta/recipes-core/expat/expat/CVE-2026-41080-2.patch create mode 100644 meta/recipes-core/expat/expat/CVE-2026-41080-3.patch diff --git a/meta/recipes-core/expat/expat/CVE-2026-41080-1.patch b/meta/recipes-core/expat/expat/CVE-2026-41080-1.patch new file mode 100644 index 0000000000..d2a957a5e8 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2026-41080-1.patch @@ -0,0 +1,251 @@ +From 944f825b0119257fee3aed0841e44a6d1c674f80 Mon Sep 17 00:00:00 2001 +From: Amaury Couderc +Date: Thu, 2 Jul 2026 09:10:07 +0000 +Subject: [PATCH 1/3] expat: fix CVE-2026-41080 use 16 bytes of entropy for hash salt + +The existing hash flooding protection in libexpat (based on SipHash) +only used 4 to 8 bytes of entropy for a salt, when 16 bytes are +supported by the SipHash implementation. This allows attackers to more +feasibly guess the hash salt and craft inputs that cause hash +collisions, leading to denial of service. + +Backport upstream changes that: +- Drop unused parameter from generate_hash_secret_salt +- Migrate hash salt storage to larger struct sipkey (128-bit) +- Drop unneeded void * casts in generate_hash_secret_salt +- Extract 16 bytes of entropy for hash flooding protection +- Introduce internal flag m_hash_secret_salt_set +- Update get_hash_secret_salt to return from the new 128-bit struct + +Squashed backport of upstream commits 909201a8, bc193afc, 08697a9b, +f5eacefb, and fa1ebd60. + +Based on upstream PR: https://github.com/libexpat/libexpat/pull/1183 + +CVE: CVE-2026-41080 +Upstream-Status: Backport [https://github.com/libexpat/libexpat/pull/1183/commits/fa1ebd60bfcc6d32f329803e5e837251e2387ed1] + +Signed-off-by: Sebastian Pipping +Signed-off-by: Amaury Couderc +--- + lib/internal.h | 2 ++ + lib/xmlparse.c | 80 +++++++++++++++++++++++++++++++------------------- + 2 files changed, 52 insertions(+), 30 deletions(-) + +diff --git a/lib/internal.h b/lib/internal.h +index 61266ebb..1995c17b 100644 +--- a/lib/internal.h ++++ b/lib/internal.h +@@ -113,6 +113,7 @@ + #if defined(_WIN32) \ + && (! defined(__USE_MINGW_ANSI_STDIO) \ + || (1 - __USE_MINGW_ANSI_STDIO - 1 == 0)) ++# define EXPAT_FMT_LLX(midpart) "%" midpart "I64x" + # define EXPAT_FMT_ULL(midpart) "%" midpart "I64u" + # if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW + # define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d" +@@ -122,6 +123,7 @@ + # define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u" + # endif + #else ++# define EXPAT_FMT_LLX(midpart) "%" midpart "llx" + # define EXPAT_FMT_ULL(midpart) "%" midpart "llu" + # if ! defined(ULONG_MAX) + # error Compiler did not define ULONG_MAX for us +diff --git a/lib/xmlparse.c b/lib/xmlparse.c +index 0248b665..59235c85 100644 +--- a/lib/xmlparse.c ++++ b/lib/xmlparse.c +@@ -604,7 +604,7 @@ static ELEMENT_TYPE *getElementType(XML_Parser parser, const ENCODING *enc, + + static XML_Char *copyString(const XML_Char *s, XML_Parser parser); + +-static unsigned long generate_hash_secret_salt(XML_Parser parser); ++static struct sipkey generate_hash_secret_salt(void); + static XML_Bool startParsing(XML_Parser parser); + + static XML_Parser parserCreate(const XML_Char *encodingName, +@@ -777,7 +777,8 @@ struct XML_ParserStruct { + XML_Bool m_useForeignDTD; + enum XML_ParamEntityParsing m_paramEntityParsing; + #endif +- unsigned long m_hash_secret_salt; ++ struct sipkey m_hash_secret_salt_128; ++ XML_Bool m_hash_secret_salt_set; + #if XML_GE == 1 + ACCOUNTING m_accounting; + MALLOC_TRACKER m_alloc_tracker; +@@ -1192,57 +1193,61 @@ gather_time_entropy(void) { + + #endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */ + +-static unsigned long +-ENTROPY_DEBUG(const char *label, unsigned long entropy) { ++static struct sipkey ++ENTROPY_DEBUG(const char *label, struct sipkey entropy_128) { + if (getDebugLevel("EXPAT_ENTROPY_DEBUG", 0) >= 1u) { +- fprintf(stderr, "expat: Entropy: %s --> 0x%0*lx (%lu bytes)\n", label, +- (int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy)); ++ fprintf(stderr, ++ "expat: Entropy: %s --> [0x" EXPAT_FMT_LLX( ++ "016") ", 0x" EXPAT_FMT_LLX("016") "] (16 bytes)\n", ++ label, (unsigned long long)entropy_128.k[0], ++ (unsigned long long)entropy_128.k[1]); + } +- return entropy; ++ return entropy_128; + } + +-static unsigned long +-generate_hash_secret_salt(XML_Parser parser) { +- unsigned long entropy; +- (void)parser; ++static struct sipkey ++generate_hash_secret_salt(void) { ++ struct sipkey entropy; + + /* "Failproof" high quality providers: */ + #if defined(HAVE_ARC4RANDOM_BUF) + arc4random_buf(&entropy, sizeof(entropy)); + return ENTROPY_DEBUG("arc4random_buf", entropy); + #elif defined(HAVE_ARC4RANDOM) +- writeRandomBytes_arc4random((void *)&entropy, sizeof(entropy)); ++ writeRandomBytes_arc4random(&entropy, sizeof(entropy)); + return ENTROPY_DEBUG("arc4random", entropy); + #else + /* Try high quality providers first .. */ + # ifdef _WIN32 +- if (writeRandomBytes_rand_s((void *)&entropy, sizeof(entropy))) { ++ if (writeRandomBytes_rand_s(&entropy, sizeof(entropy))) { + return ENTROPY_DEBUG("rand_s", entropy); + } + # elif defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) +- if (writeRandomBytes_getrandom_nonblock((void *)&entropy, sizeof(entropy))) { ++ if (writeRandomBytes_getrandom_nonblock(&entropy, sizeof(entropy))) { + return ENTROPY_DEBUG("getrandom", entropy); + } + # endif + # if ! defined(_WIN32) && defined(XML_DEV_URANDOM) +- if (writeRandomBytes_dev_urandom((void *)&entropy, sizeof(entropy))) { ++ if (writeRandomBytes_dev_urandom(&entropy, sizeof(entropy))) { + return ENTROPY_DEBUG("/dev/urandom", entropy); + } + # endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */ + /* .. and self-made low quality for backup: */ + +- entropy = gather_time_entropy(); ++ entropy.k[0] = 0; ++ entropy.k[1] = gather_time_entropy(); + # if ! defined(__wasi__) + /* Process ID is 0 bits entropy if attacker has local access */ +- entropy ^= getpid(); ++ entropy.k[1] ^= getpid(); + # endif + + /* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */ + if (sizeof(unsigned long) == 4) { +- return ENTROPY_DEBUG("fallback(4)", entropy * 2147483647); ++ entropy.k[1] *= 2147483647; ++ return ENTROPY_DEBUG("fallback(4)", entropy); + } else { +- return ENTROPY_DEBUG("fallback(8)", +- entropy * (unsigned long)2305843009213693951ULL); ++ entropy.k[1] *= 2305843009213693951ULL; ++ return ENTROPY_DEBUG("fallback(8)", entropy); + } + #endif + } +@@ -1252,7 +1257,7 @@ get_hash_secret_salt(XML_Parser parser) { + const XML_Parser rootParser = getRootParserOf(parser, NULL); + assert(! rootParser->m_parentParser); + +- return rootParser->m_hash_secret_salt; ++ return rootParser->m_hash_secret_salt_128.k[1]; + } + + static enum XML_Error +@@ -1323,8 +1328,10 @@ callProcessor(XML_Parser parser, const char *start, const char *end, + static XML_Bool /* only valid for root parser */ + startParsing(XML_Parser parser) { + /* hash functions must be initialized before setContext() is called */ +- if (parser->m_hash_secret_salt == 0) +- parser->m_hash_secret_salt = generate_hash_secret_salt(parser); ++ if (parser->m_hash_secret_salt_set != XML_TRUE) { ++ parser->m_hash_secret_salt_128 = generate_hash_secret_salt(); ++ parser->m_hash_secret_salt_set = XML_TRUE; ++ } + if (parser->m_ns) { + /* implicit context only set for root parser, since child + parsers (i.e. external entity parsers) will inherit it +@@ -1612,7 +1619,9 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) { + parser->m_useForeignDTD = XML_FALSE; + parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; + #endif +- parser->m_hash_secret_salt = 0; ++ parser->m_hash_secret_salt_128.k[0] = 0; ++ parser->m_hash_secret_salt_128.k[1] = 0; ++ parser->m_hash_secret_salt_set = XML_FALSE; + + #if XML_GE == 1 + memset(&parser->m_accounting, 0, sizeof(ACCOUNTING)); +@@ -1779,7 +1788,8 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ +- unsigned long oldhash_secret_salt; ++ struct sipkey oldhash_secret_salt_128; ++ XML_Bool oldhash_secret_salt_set; + XML_Bool oldReparseDeferralEnabled; + + /* Validate the oldParser parameter before we pull everything out of it */ +@@ -1825,7 +1835,8 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ +- oldhash_secret_salt = parser->m_hash_secret_salt; ++ oldhash_secret_salt_128 = parser->m_hash_secret_salt_128; ++ oldhash_secret_salt_set = parser->m_hash_secret_salt_set; + oldReparseDeferralEnabled = parser->m_reparseDeferralEnabled; + + #ifdef XML_DTD +@@ -1880,7 +1891,8 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, + parser->m_externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; + parser->m_defaultExpandInternalEntities = oldDefaultExpandInternalEntities; + parser->m_ns_triplets = oldns_triplets; +- parser->m_hash_secret_salt = oldhash_secret_salt; ++ parser->m_hash_secret_salt_128 = oldhash_secret_salt_128; ++ parser->m_hash_secret_salt_set = oldhash_secret_salt_set; + parser->m_reparseDeferralEnabled = oldReparseDeferralEnabled; + parser->m_parentParser = oldParser; + #ifdef XML_DTD +@@ -2335,7 +2347,13 @@ XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) { + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (parserBusy(rootParser)) + return 0; +- rootParser->m_hash_secret_salt = hash_salt; ++ ++ rootParser->m_hash_secret_salt_128.k[0] = 0; ++ rootParser->m_hash_secret_salt_128.k[1] = hash_salt; ++ ++ if (hash_salt != 0) // to remain backwards compatible ++ rootParser->m_hash_secret_salt_set = XML_TRUE; ++ + return 1; + } + +@@ -7842,8 +7860,10 @@ keylen(KEY s) { + + static void + copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key) { +- key->k[0] = 0; +- key->k[1] = get_hash_secret_salt(parser); ++ const XML_Parser rootParser = getRootParserOf(parser, NULL); ++ assert(! rootParser->m_parentParser); ++ ++ *key = rootParser->m_hash_secret_salt_128; + } + + static unsigned long FASTCALL +-- +2.34.1 + diff --git a/meta/recipes-core/expat/expat/CVE-2026-41080-2.patch b/meta/recipes-core/expat/expat/CVE-2026-41080-2.patch new file mode 100644 index 0000000000..a52d61e611 --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2026-41080-2.patch @@ -0,0 +1,310 @@ +From 969472a6d33e994c234ab2ed34f1a01348351b28 Mon Sep 17 00:00:00 2001 +From: Amaury Couderc +Date: Thu, 2 Jul 2026 09:23:00 +0000 +Subject: [PATCH 2/3] expat: add XML_SetHashSalt16Bytes API for CVE-2026-41080 + +Add the new XML_SetHashSalt16Bytes API function which accepts a full +16 bytes of entropy for the hash salt, matching the capacity of the +SipHash implementation used by Expat. The existing XML_SetHashSalt +function is marked as deprecated since it only provides 4 to 8 bytes +of entropy depending on the size of unsigned long. + +Changes include: +- Add XML_SetHashSalt16Bytes to public API (expat.h) +- Add symbol export in libexpat.map.in (LIBEXPAT_2.7.6) +- Mark XML_SetHashSalt as deprecated +- Document that XML_SetHashSalt needs a non-NULL parser +- Include XML_SetHashSalt* with entropy debugging +- Add test_hash_salt_setter unit test +- Update documentation and Changes file + +Squashed backport of upstream commits f76124e7, e3349d85, c8c5caf4, +592d5fa3, 8ad3ef57, ec9fcd2e, and 8017e11e. + +CVE: CVE-2026-41080 +Upstream-Status: Backport [https://github.com/libexpat/libexpat/pull/1183/commits/4ba09dc471b39a78d77e5179d0243186c0c4ff7a] + +Signed-off-by: Sebastian Pipping +Signed-off-by: Amaury Couderc +--- + Changes | 17 ++++++++++++++ + doc/reference.html | 55 ++++++++++++++++++++++++++++++++++++++++----- + lib/expat.h | 15 +++++++++++++++ + lib/libexpat.map.in | 5 +++++ + lib/xmlparse.c | 33 ++++++++++++++++++++++++++- + tests/basic_tests.c | 25 +++++++++++++++++++++ + 6 files changed, 144 insertions(+), 6 deletions(-) + +diff --git a/Changes b/Changes +index 2b3704a6..1d8227ec 100644 +--- a/Changes ++++ b/Changes +@@ -29,6 +29,23 @@ + !! THANK YOU! Sebastian Pipping -- Berlin, 2026-03-17 !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ++Patches ++ Security fixes: ++ #47 #1183 CVE-2026-41080 -- The existing hash flooding protection ++ (based on SipHash) only used 4 to 8 bytes of entropy for ++ a salt, when 16 bytes of salt are supported by the ++ implementation of SipHash used by Expat. Now full 16 bytes ++ of entropy are used to improve protection against hash ++ flooding attacks. ++ Existing API function XML_SetHashSalt is now deprecated ++ because of its limitations, and its use should be ++ considered a vulnerability. Please either use the new API ++ function XML_SetHashSalt16Bytes (with known-high-quality ++ entropy input only!) instead, or leave the derivation of ++ a 16-bytes hash salt from high quality entropy to Expat's ++ internal machinery (by *not* calling either of the two ++ XML_SetHashSalt* functions). ++ + Release 2.7.5 Tue March 17 2026 + Security fixes: + #1158 CVE-2026-32776 -- Fix NULL function pointer dereference for +diff --git a/doc/reference.html b/doc/reference.html +index 5faa8d65..64b9fd67 100644 +--- a/doc/reference.html ++++ b/doc/reference.html +@@ -404,7 +404,11 @@ + + +
  • +- XML_SetHashSalt ++ XML_SetHashSalt (deprecated) ++
  • ++ ++
  • ++ XML_SetHashSalt16Bytes +
  • + +
  • +@@ -3449,22 +3453,35 @@ XML_SetParamEntityParsing(XML_Parser p, + + +

    +- XML_SetHashSalt ++ XML_SetHashSalt (deprecated) +

    + +
    + int XMLCALL
    +-XML_SetHashSalt(XML_Parser p,
    ++XML_SetHashSalt(XML_Parser parser,
    +                 unsigned long hash_salt);
    + 
    +
    + Sets the hash salt to use for internal hash calculations. Helps in preventing DoS + attacks based on predicting hash function behavior. In order to have an effect + this must be called before parsing has started. Returns 1 if successful, 0 when +- called after XML_Parse or XML_ParseBuffer. ++ called after XML_Parse or XML_ParseBuffer or when ++ parser is NULL. ++

    ++ Note: Function XML_SetHashSalt is ++ deprecated. Please use function XML_SetHashSalt16Bytes instead for better ++ security. XML_SetHashSalt only provides 4 to 8 bytes of entropy ++ (depending on the size of type unsigned long) while the SipHash ++ implementation used by Expat can leverage up to 16 bytes of entropy — at least ++ twice as much. Function XML_SetHashSalt16Bytes of Expat >=2.7.6 ++ (and where backported) matches the amount of entropy supported by SipHash. ++

    ++ +

    + Note: This call is optional, as the parser will auto-generate a new +- random salt value if no value has been set at the start of parsing. ++ random salt value internally if no value has been set by the start of parsing. +

    + +

    +@@ -3475,6 +3492,34 @@ XML_SetHashSalt(XML_Parser p, +

    +
    + ++

    ++ XML_SetHashSalt16Bytes ++

    ++ ++
    ++/* Added in Expat 2.7.6. */
    ++XML_Bool XMLCALL
    ++XML_SetHashSalt16Bytes(XML_Parser parser,
    ++                       const uint8_t entropy[16]);
    ++
    ++
    ++ Sets the hash salt to use for internal hash calculations. Helps in preventing DoS ++ attacks based on predicting hash function behavior. In order to have an effect ++ this must be called before parsing has started. Returns XML_TRUE if ++ successful, XML_FALSE when called after XML_Parse or ++ XML_ParseBuffer or when parser is NULL. ++

    ++ Note: Setting a salt that is not from a source of high quality ++ entropy (like getentropy(3)) will make the parser vulnerable to ++ hash flooding attacks. ++

    ++ ++

    ++ Note: This call is optional, as the parser will auto-generate a new ++ random salt value internally if no value has been set by the start of parsing. ++

    ++
    ++ +

    + XML_UseForeignDTD +

    +diff --git a/lib/expat.h b/lib/expat.h +index 18dbaebd..7693f62c 100644 +--- a/lib/expat.h ++++ b/lib/expat.h +@@ -45,6 +45,7 @@ + #ifndef Expat_INCLUDED + # define Expat_INCLUDED 1 + ++# include // for uint8_t + # include + # include "expat_external.h" + +@@ -917,10 +918,25 @@ XML_SetParamEntityParsing(XML_Parser parser, + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. + Note: If parser == NULL, the function will do nothing and return 0. ++ DEPRECATED since Expat 2.7.6. + */ + XMLPARSEAPI(int) + XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); + ++/* Sets the hash salt to use for internal hash calculations. ++ Helps in preventing DoS attacks based on predicting hash function behavior. ++ This must be called before parsing is started. ++ Returns XML_TRUE if successful, XML_FALSE when called after parsing has ++ started or when parser is NULL. ++ Added in Expat 2.7.6. ++*/ ++XMLPARSEAPI(XML_Bool) ++XML_SetHashSalt16Bytes(XML_Parser parser, const uint8_t entropy[16]); ++ ++/* Backport feature macro: signals that XML_SetHashSalt16Bytes is available ++ even though XML_COMBINED_VERSION < 20800. */ ++# define XML_BACKPORT_SET_HASH_SALT_16_BYTES 1 ++ + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then + XML_GetErrorCode returns information about the error. + */ +diff --git a/lib/libexpat.map.in b/lib/libexpat.map.in +index 52e59ed3..8527eb54 100644 +--- a/lib/libexpat.map.in ++++ b/lib/libexpat.map.in +@@ -117,3 +117,8 @@ LIBEXPAT_2.7.2 { + @_EXPAT_COMMENT_DTD_OR_GE@ XML_SetAllocTrackerActivationThreshold; + @_EXPAT_COMMENT_DTD_OR_GE@ XML_SetAllocTrackerMaximumAmplification; + } LIBEXPAT_2.6.0; ++ ++LIBEXPAT_2.7.6 { ++ global: ++ XML_SetHashSalt16Bytes; ++} LIBEXPAT_2.7.2; +diff --git a/lib/xmlparse.c b/lib/xmlparse.c +index 59235c85..09ae4f92 100644 +--- a/lib/xmlparse.c ++++ b/lib/xmlparse.c +@@ -2336,6 +2336,7 @@ XML_SetParamEntityParsing(XML_Parser parser, + #endif + } + ++// DEPRECATED since Expat 2.7.6. + int XMLCALL + XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) { + if (parser == NULL) +@@ -2351,12 +2352,42 @@ XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) { + rootParser->m_hash_secret_salt_128.k[0] = 0; + rootParser->m_hash_secret_salt_128.k[1] = hash_salt; + +- if (hash_salt != 0) // to remain backwards compatible ++ if (hash_salt != 0) { // to remain backwards compatible + rootParser->m_hash_secret_salt_set = XML_TRUE; + ++ if (sizeof(unsigned long) == 4) ++ ENTROPY_DEBUG("explicit(4)", rootParser->m_hash_secret_salt_128); ++ else ++ ENTROPY_DEBUG("explicit(8)", rootParser->m_hash_secret_salt_128); ++ } ++ + return 1; + } + ++XML_Bool XMLCALL ++XML_SetHashSalt16Bytes(XML_Parser parser, const uint8_t entropy[16]) { ++ if (parser == NULL) ++ return XML_FALSE; ++ ++ if (entropy == NULL) ++ return XML_FALSE; ++ ++ const XML_Parser rootParser = getRootParserOf(parser, NULL); ++ assert(! rootParser->m_parentParser); ++ ++ /* block after XML_Parse()/XML_ParseBuffer() has been called */ ++ if (parserBusy(rootParser)) ++ return XML_FALSE; ++ ++ sip_tokey(&(rootParser->m_hash_secret_salt_128), entropy); ++ ++ rootParser->m_hash_secret_salt_set = XML_TRUE; ++ ++ ENTROPY_DEBUG("explicit(16)", rootParser->m_hash_secret_salt_128); ++ ++ return XML_TRUE; ++} ++ + enum XML_Status XMLCALL + XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) { + if ((parser == NULL) || (len < 0) || ((s == NULL) && (len != 0))) { +diff --git a/tests/basic_tests.c b/tests/basic_tests.c +index 02d1d5fd..26662fee 100644 +--- a/tests/basic_tests.c ++++ b/tests/basic_tests.c +@@ -204,6 +204,30 @@ START_TEST(test_hash_collision) { + END_TEST + #undef COLLIDING_HASH_SALT + ++START_TEST(test_hash_salt_setter) { ++ const uint8_t entropy[16] = {'0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; ++ XML_Parser parser = XML_ParserCreate(NULL); ++ ++ // NULL parser should be rejected ++ assert_true(XML_SetHashSalt16Bytes(NULL, entropy) == XML_FALSE); ++ ++ // NULL entropy should be rejected ++ assert_true(XML_SetHashSalt16Bytes(parser, NULL) == XML_FALSE); ++ ++ // Setting should be allowed more than once ++ assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_TRUE); ++ assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_TRUE); ++ ++ // But not after parsing has started ++ assert_true(XML_Parse(parser, "", 0, XML_FALSE /* isFinal */) ++ == XML_STATUS_OK); ++ assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_FALSE); ++ ++ XML_ParserFree(parser); ++} ++END_TEST ++ + /* Regression test for SF bug #491986. */ + START_TEST(test_danish_latin1) { + const char *text = "\n" +@@ -6292,6 +6316,7 @@ make_basic_test_case(Suite *s) { + tcase_add_test(tc_basic, test_bom_utf16_le); + tcase_add_test(tc_basic, test_nobom_utf16_le); + tcase_add_test(tc_basic, test_hash_collision); ++ tcase_add_test(tc_basic, test_hash_salt_setter); + tcase_add_test(tc_basic, test_illegal_utf8); + tcase_add_test(tc_basic, test_utf8_auto_align); + tcase_add_test(tc_basic, test_utf16); +-- +2.34.1 + diff --git a/meta/recipes-core/expat/expat/CVE-2026-41080-3.patch b/meta/recipes-core/expat/expat/CVE-2026-41080-3.patch new file mode 100644 index 0000000000..69a1c99fcc --- /dev/null +++ b/meta/recipes-core/expat/expat/CVE-2026-41080-3.patch @@ -0,0 +1,32 @@ +From cfc4475518cd38890071b280e8619e74dd9e8722 Mon Sep 17 00:00:00 2001 +From: Christoph Reiter +Date: Wed, 10 Jun 2026 21:27:51 +0200 +Subject: [PATCH 3/3] cmake|windows: add missing export for new XML_SetHashSalt16Bytes + +A new XML_SetHashSalt16Bytes symbol was added in #1183, but it +wasn't added to the def file, so the export is missing when building +libexpat on Windows with cmake. + +Add the new symbol to the .def template. + +CVE: CVE-2026-41080 +Upstream-Status: Backport [https://github.com/libexpat/libexpat/pull/1270/commits/3cdd1df2644388aff25dd0ed7128c7bb1de1a7d8] + +Signed-off-by: Amaury Couderc +--- + lib/libexpat.def.cmake | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/lib/libexpat.def.cmake b/lib/libexpat.def.cmake +index 9b9e22cb..948135a5 100644 +--- a/lib/libexpat.def.cmake ++++ b/lib/libexpat.def.cmake +@@ -83,3 +83,5 @@ EXPORTS + ; added with version 2.7.2 + @_EXPAT_COMMENT_DTD_OR_GE@ XML_SetAllocTrackerMaximumAmplification @72 + @_EXPAT_COMMENT_DTD_OR_GE@ XML_SetAllocTrackerActivationThreshold @73 ++; added with version 2.7.6 ++ XML_SetHashSalt16Bytes @74 +-- +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 4f2578292d..1191d9a943 100644 --- a/meta/recipes-core/expat/expat_2.7.5.bb +++ b/meta/recipes-core/expat/expat_2.7.5.bb @@ -10,6 +10,9 @@ VERSION_TAG = "${@d.getVar('PV').replace('.', '_')}" SRC_URI = "${GITHUB_BASE_URI}/download/R_${VERSION_TAG}/expat-${PV}.tar.bz2 \ file://run-ptest \ + file://CVE-2026-41080-1.patch \ + file://CVE-2026-41080-2.patch \ + file://CVE-2026-41080-3.patch \ " GITHUB_BASE_URI = "https://github.com/libexpat/libexpat/releases/" From patchwork Mon Jul 6 12:04:54 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Amaury Couderc X-Patchwork-Id: 91806 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3CCD6C43458 for ; Mon, 6 Jul 2026 12:05:28 +0000 (UTC) Received: from AM0PR83CU005.outbound.protection.outlook.com (AM0PR83CU005.outbound.protection.outlook.com [52.101.69.58]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.148523.1783339517948815253 for ; Mon, 06 Jul 2026 05:05:18 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: body hash did not verify" header.i=@est.tech header.s=selector1 header.b=Mhx375GB; spf=pass (domain: est.tech, ip: 52.101.69.58, mailfrom: amaury.couderc@est.tech) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=l4dSsPEkilUD+C0sLvXYIZW4jO2ORrYaTlHGlw1nE0KN4NSSDcynft/e2fcJxYUYEmC3wepwngVFk8tzLhJmTNWd4x96BIlptL+ZrfskQchWK2uYcm8RffMw3FOXa5oO03du1bOeBAktfX8IH/cgo/e/BM8ypes3t8kHMJTNd3JZ2JTh/OKggji/gQjlNOkT62pYiqOMR+xRfsa3a+nUctPkY9e2aOEXbbrW8ySNFoL9QMWghe9Jog0btBOkpRZ+3IDtqLHY/CPykSoI4Y8rEd5p4Ujs4+X+bmvOB9O25AhIS9Z8Bk3K6n3fGEQPt7cB18kgyB6g6i/nJ9XG87nJMw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=gloNKkFynzRfhxd2yzTa1kJ9V9oRNraaEHxj2l3JK2Y=; b=Jo8/3rjfbaA2bjgciseXy3muYReVuyf7JaVVyelxg6Yc3ct3VGEpQvPwe/2IfWde2EHRc4OXSBBrTumfnbScLq+nH0LPC7SoUu1P3Ze6VL+MFghb91KXK3QEQZg/Dlq1nt2bFBnrKGR8426mxyvy10ksfKnGUz79BzFEmwBnITleP+Aj26UDGAEPYalrlbraaHxTZpelnoQiwgQBaDcf43QEWFbAgQ5/EkwJsKLegrdqKObu39j0maWQ+eBQ1zLi9F0kWcMv6bjDXupGXqF1P0Aj+ig6Bbm6gN3zFP+BOOo6jp31x9OrehRxDSENbQ7vOOP28vp+f7BXYlxX0QSeng== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=est.tech; dmarc=pass action=none header.from=est.tech; dkim=pass header.d=est.tech; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=est.tech; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=gloNKkFynzRfhxd2yzTa1kJ9V9oRNraaEHxj2l3JK2Y=; b=Mhx375GBPyuqieKiV1nXemQgcBnjUr+tTi/1sYYwLAGk0/my3mSfiNatCUnmRXEGMsGK8HzO9BpDyp6Yg2kSIkYdPTDXxoQ3xcx9QRohliug4hYitkuAKM8DL/Qo2TMJiHhG9nTyjthyOiSIokcbnwSd5b1rKHshGR9oh6l1ZDMgzA4mRQHuJ1JPrDUR9TZHfIHZ3GAwSMtLkg+YAZ6oH/bcrcH1HCNQzRM4nnwXX+tZPO5k6hMzvWVfXz3IR/8DT7ATTDC0YZlHow2O8gRDQz6pqkF/YxHNmVa9tSi4cNei+zsq74xvz5HTJpWiDaV1PfWivP26gIq959RX65B2gA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=est.tech; Received: from AMBP189MB3196.EURP189.PROD.OUTLOOK.COM (2603:10a6:20b:6ad::11) by GV2P189MB2453.EURP189.PROD.OUTLOOK.COM (2603:10a6:150:d3::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.181.11; Mon, 6 Jul 2026 12:05:14 +0000 Received: from AMBP189MB3196.EURP189.PROD.OUTLOOK.COM ([fe80::1afd:f059:542:3d95]) by AMBP189MB3196.EURP189.PROD.OUTLOOK.COM ([fe80::1afd:f059:542:3d95%4]) with mapi id 15.21.0181.008; Mon, 6 Jul 2026 12:05:14 +0000 From: amaury.couderc@est.tech To: openembedded-core@lists.openembedded.org Subject: [PATCH 2/2][wrynose] python3: fix CVE-2026-7210 Date: Mon, 6 Jul 2026 14:04:54 +0200 Message-ID: <20260706120508.37474-1-amaury.couderc@est.tech> X-Mailer: git-send-email 2.43.0 X-ClientProxiedBy: LO4P123CA0099.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:191::14) To AMBP189MB3196.EURP189.PROD.OUTLOOK.COM (2603:10a6:20b:6ad::11) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AMBP189MB3196:EE_|GV2P189MB2453:EE_ X-MS-Office365-Filtering-Correlation-Id: c5fd181d-9a5b-447a-a62a-08dedb56d648 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|23010399003|18002099003|56012099006|11063799006|29003799003|12006099003|6133799003|25016099003|13003099007; X-Microsoft-Antispam-Message-Info: xG1BtLvQLqlb5p11WW178p5oMFCLFoILl7w9X7zSG3crmblYiMpQ2nIzuelzvguGMMRjZBcSZEyRhKYeeQ8acyLSTJqwSqMO0rPxoLYfBu+2mUJWNjACCPIopGA8q2mMq1wodzgIjiAg9L9HOxc1zVEwYpnpCWVT9ZbcFSVnZcOor0wXq8e64pPFi70/uv+TYo6+nvAP3EAQPRJI//G+H0X0+Z8un513qTfSqQ0O5jq3P1nmzkyaR+d4yatgHV0ajQ+gkGV8UT4D1RsjrJEjy9yUUA9ULzH8F0kiHphkP/Q8LM8FTuShfIQCR3u88VW0SlV2Uq8W4qzxLRaLo3HdVqzxIvJ7JwJcLekZGsqbZiv3s2ktXKkeHzVf7rTIGs1lht9D0y9BPELgM8AmT3I/2CtmJiLPDWFOEaFHPS0/6oEO6d41WXKBs3WTBN99M3+MOMI3MCbFiC/ksz067u2hk97PHXHOEHF4hc3PvdYkezPeNhhBtJY+H9/Qh0uC/YcG+BpGZEW+mtO1BUAfvCeirAlXcCIE3xLRMwnLfUDa6SVB0bpWRUzzFx/QCnDLhAl198WOFwkxipne0KhTPObCt32Jm0zQzgxZXfX0o/JgIhrwOTFFpxEP22EdOTsIe1Ji4usvihccZDiI1Zu9bOs/lBqn0S3alumIMmmhqweI9/U= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:AMBP189MB3196.EURP189.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(366016)(1800799024)(23010399003)(18002099003)(56012099006)(11063799006)(29003799003)(12006099003)(6133799003)(25016099003)(13003099007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: YRhunaWjnXxhs9jaPHbkUOqASvyh+qV0Zkn+uKrhpN/x9MusErq2VphoyFb3DGJgUXpWn/0P1lwNKFOdlUO9uLXefCWEQRF/bdpyDvLd0YWkJl65gNTodcgNvJXRcfjtikNBgryk/rr6Ik/FsVW8C9SGn5FmV6dZZAZTwu+MbxzZuhnBx5gpsksX7FyVWsaeBOhuHKr+WffKxYZ4T/FUNfU8hwbbNI/NoXcpbZGiv5hnD3GzdAh9/BcxNh/kSohuq3pxofb1nR3w1ADOmbN/YWVufLyW2fj7iSgxlzr5gxcJCUwG+djm+1BPj6WbXS5YP2XKqMK09egvZxwV/Bx/lZQGQziy0ryJ3h/Bo38YrLPGpVEX4AyThx0CBII90xdZSkQEWC9h3xdZYQimV6XoLF0iDAcz6+fB5RZCAJj0/l0XhhWd0c3hm8Y9bTFDmCxajLgg/By8ePVCalle/KO6ETVdD2DrJp/e3zEK2+vMpN45FQ/C7uWZux4vXfNSsoZE4l+QpJS4i8bHiDsN0rMaknlIY2HDAurSqy+mwfR+Qk9tSDg9c1wyVwNIfMpUknGnqxg7Kw1ncurCAj2M8v2C4EwxnPGZoY0n8gUT4qsMa6vNUWTDxxsNMOjxkF8T1dxNfsBaa7VwenGfKsMEOkdCI1WNsr3nMp9D0jHQlW+HAgczBMaNUMp6AsPCCfrsWQeN5CXPuocJ4XvFq7khl2sQ/JE0zemCxy6a47uJGUgi1YIOYyePBSoKERMR3tjoo3im0fW3K7vxkymZYItNJK8r7RpeQx8vRfDcW1FS2FZv9gjZdYIRFE65gt+18z4RbD4SEaAmbomJTHIgRQBxRMaMSZsxV7BIwg0WpvAUcKklyKxCOovMGHUG9AIX4ApI3NXjbsGMYmD3xQbEjJyKL4Ek0X4CbmCeumfOu8mD9+3t9EnKVlbwRYRjuEBGZElFSl4+fmM0gaXpOvvi/zE1kPvx9GUPyREhn1Wcg83Az1V4UbGophSnsrKwvzlugrSFWn9kGhpVXCY83Hboh/RQEVJ71uyD6/p+a7bi3bs0JtPiiSZk/bILrEUbQ0+x3EvWmr6MLLJNn2btQBdDr3zf6O13BLXJ6Jjm3l4/4KszQvSkge+NDnzkatJkJ3o5BFAgPrDroECbV9+fxE89KoondaByPs3Gv+DQohvXh0INT/XSU11wWTcS/Kd08g01DaL7/oGCUvrf39+FGUjni07n/Z/zpQyHG7HC3Vs/ft3lF6B2N+D1wr/N7g3/Dlvn2jnTX41Pl5MEH4M3zo8qvS1qwjMOB0UxjzsuvXl3LOXVLaE8Bui6jKN45B6amhruqSFJktO/k31UL2myS0EwLEiYoABrowusmCUHCjwRvVGBHQotpxGb8tDIm/tD+dJpCZK3/P607Tbk/H7O6A1mnxRhE/8QU1uOKH64AouApIfFHKIx8xLmSPvCnu6mtk897YufvlFGLEx0iI3dy1ax5mWGqvwyid9Md/W/gZIjTs0QraJib8kRyWVHXrv/NumZuS30MX3XSJaHBxaqRUUHNRtWhmVW9OM4042S2/qe51O2cJaMyp3o07qcn2/J1Yv2GogDAVwsyfdpLNk9XtFeokMGO+7KeGvxShZQGmFVn4ZmRrx7N0n35YmxADo3gtTi2yYjnI+0cnFmpNSd9keNzcRCpkxOfX/VhOc/rjZbviGg1+gtJxrV9zlvcFPJ6IZ/GLJBKS9VoVm0CJhvqbBXJcYUmF1bSw== X-OriginatorOrg: est.tech X-MS-Exchange-CrossTenant-Network-Message-Id: c5fd181d-9a5b-447a-a62a-08dedb56d648 X-MS-Exchange-CrossTenant-AuthSource: AMBP189MB3196.EURP189.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 06 Jul 2026 12:05:14.2638 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: d2585e63-66b9-44b6-a76e-4f4b217d97fd X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: RTsME0lGeXCXAYBy4cVbzGvFya8FRnpBDU6XsyeXUe7hx+tlYTKczhLjSokjyXv2LOMw/o+Y03emJQGU1kesGg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: GV2P189MB2453 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 06 Jul 2026 12:05:28 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/240262 From: Amaury Couderc CVE-2026-7210 is a hash-flooding denial-of-service vulnerability in Python's XML parsing modules (xml.parsers.expat, xml.etree.ElementTree). An attacker can craft XML input that forces O(n²) hash collisions in libexpat's internal name dictionary, causing excessive CPU consumption. The previous mitigation seeded libexpat's hash function with only 4 bytes of entropy, which is insufficient against a determined attacker. This patch upgrades to XML_SetHashSalt16Bytes (libexpat >= 2.8.0), providing a full 16-byte secret. Older expat versions fall back gracefully to the legacy XML_SetHashSalt via a runtime NULL check. NOTE: CVE-2026-7210 full mitigation requires the companion expat CVE-2026-41080 patch (raises expat to >= 2.8.0 API) Backport patch to fix CVE-2026-7210. https://nvd.nist.gov/vuln/detail/CVE-2026-7210 Upstream fix: https://github.com/python/cpython/commit/24b8f12544468e4cedf5bfbe25442fcd495391e4 Tested with ptest: Before: PASSED: 43903, FAILED: 0, SKIPPED: 2471 After: PASSED: 43903, FAILED: 0, SKIPPED: 2471 CVE: CVE-2026-7210 Signed-off-by: Amaury Couderc --- .../python/python3/CVE-2026-7210.patch | 136 ++++++++++++++++++ .../recipes-devtools/python/python3_3.14.5.bb | 1 + 2 files changed, 137 insertions(+) create mode 100644 meta/recipes-devtools/python/python3/CVE-2026-7210.patch diff --git a/meta/recipes-devtools/python/python3/CVE-2026-7210.patch b/meta/recipes-devtools/python/python3/CVE-2026-7210.patch new file mode 100644 index 0000000000..337130d9b7 --- /dev/null +++ b/meta/recipes-devtools/python/python3/CVE-2026-7210.patch @@ -0,0 +1,136 @@ +From a7fafeebaf33995556a37e9eec4f6a6bcfce2e67 Mon Sep 17 00:00:00 2001 +From: Stan Ulbrych +Date: Sun, 10 May 2026 18:36:26 +0100 +Subject: [PATCH] gh-149018: Use `XML_SetHashSalt16Bytes` in `pyexpat`/`_elementtree` when possible (#149023) + +CVE-2026-7210 is a hash-flooding denial-of-service vulnerability in +Python's XML parsing modules (xml.parsers.expat, xml.etree.ElementTree). +An attacker can craft XML input that forces O(n²) hash collisions in +libexpat's internal name dictionary, causing excessive CPU consumption. + +The previous mitigation seeded libexpat's hash function with only 4 +bytes of entropy, which is insufficient against a determined attacker. +This patch upgrades to XML_SetHashSalt16Bytes (libexpat >= 2.8.0), +providing a full 16-byte secret. Older expat versions fall back +gracefully to the legacy XML_SetHashSalt via a runtime NULL check. + +NOTE: CVE-2026-7210 full mitigation requires the companion + expat CVE-2026-41080 patch (raises expat to >= 2.8.0 API) + +CVE: CVE-2026-7210 +Upstream-Status: Backport [https://github.com/python/cpython/commit/24b8f12544468e4cedf5bfbe25442fcd495391e4] + +Signed-off-by: Amaury Couderc +--- + Include/internal/pycore_pyhash.h | 8 +++++--- + Include/pyexpat.h | 3 +++ + .../2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst | 3 +++ + Modules/_elementtree.c | 8 ++++++-- + Modules/pyexpat.c | 10 +++++++++- + 5 files changed, 26 insertions(+), 6 deletions(-) + create mode 100644 Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst + +diff --git a/Include/internal/pycore_pyhash.h b/Include/internal/pycore_pyhash.h +index 84cb72fa6fd..3056dc44cc0 100644 +--- a/Include/internal/pycore_pyhash.h ++++ b/Include/internal/pycore_pyhash.h +@@ -27,14 +27,14 @@ _Py_HashPointerRaw(const void *ptr) + * pppppppp ssssssss ........ fnv -- two Py_hash_t + * k0k0k0k0 k1k1k1k1 ........ siphash -- two uint64_t + * ........ ........ ssssssss djbx33a -- 16 bytes padding + one Py_hash_t +- * ........ ........ eeeeeeee pyexpat XML hash salt ++ * eeeeeeee eeeeeeee eeeeeeee pyexpat XML hash salt + * + * memory layout on 32 bit systems + * cccccccc cccccccc cccccccc uc + * ppppssss ........ ........ fnv -- two Py_hash_t + * k0k0k0k0 k1k1k1k1 ........ siphash -- two uint64_t (*) + * ........ ........ ssss.... djbx33a -- 16 bytes padding + one Py_hash_t +- * ........ ........ eeee.... pyexpat XML hash salt ++ * eeeeeeee eeeeeeee eeee.... pyexpat XML hash salt + * + * (*) The siphash member may not be available on 32 bit platforms without + * an unsigned int64 data type. +@@ -58,7 +58,9 @@ typedef union { + Py_hash_t suffix; + } djbx33a; + struct { +- unsigned char padding[16]; ++ /* 16 bytes for XML_SetHashSalt16Bytes */ ++ uint8_t hashsalt16[16]; ++ /* 4/8 bytes for legacy XML_SetHashSalt */ + Py_hash_t hashsalt; + } expat; + } _Py_HashSecret_t; +diff --git a/Include/pyexpat.h b/Include/pyexpat.h +index 04548b7684a..d28d6828975 100644 +--- a/Include/pyexpat.h ++++ b/Include/pyexpat.h +@@ -57,6 +57,9 @@ struct PyExpat_CAPI + XML_Parser parser, unsigned long long activationThresholdBytes); + XML_Bool (*SetAllocTrackerMaximumAmplification)( + XML_Parser parser, float maxAmplificationFactor); ++ /* might be NULL for expat < 2.8.0 */ ++ XML_Bool (*SetHashSalt16Bytes)( ++ XML_Parser parser, const uint8_t entropy[16]); + /* always add new stuff to the end! */ + }; + +diff --git a/Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst b/Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst +new file mode 100644 +index 00000000000..d1b5b368684 +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-04-26-19-30-45.gh-issue-149018.a9SqWb.rst +@@ -0,0 +1,3 @@ ++Improved protection against XML hash-flooding attacks in ++:mod:`xml.parsers.expat` and :mod:`xml.etree.ElementTree` when Python is ++compiled with libExpat 2.8.0 or later. +diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c +index 7ca03f1561b..44d59fcb806 100644 +--- a/Modules/_elementtree.c ++++ b/Modules/_elementtree.c +@@ -3724,8 +3724,12 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target, + PyErr_NoMemory(); + return -1; + } +- /* expat < 2.1.0 has no XML_SetHashSalt() */ +- if (EXPAT(st, SetHashSalt) != NULL) { ++ // Prefer 16-byte entropy, only expat >= 2.8.0. See gh-149018 ++ if (EXPAT(st, SetHashSalt16Bytes) != NULL) { ++ EXPAT(st, SetHashSalt16Bytes)(self->parser, ++ _Py_HashSecret.expat.hashsalt16); ++ } ++ else if (EXPAT(st, SetHashSalt) != NULL) { + EXPAT(st, SetHashSalt)(self->parser, + (unsigned long)_Py_HashSecret.expat.hashsalt); + } +diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c +index f82f8456e48..437fd5fb61a 100644 +--- a/Modules/pyexpat.c ++++ b/Modules/pyexpat.c +@@ -1416,7 +1416,11 @@ newxmlparseobject(pyexpat_state *state, const char *encoding, + Py_DECREF(self); + return NULL; + } +-#if XML_COMBINED_VERSION >= 20100 ++#if defined(XML_BACKPORT_SET_HASH_SALT_16_BYTES) \ ++ || XML_COMBINED_VERSION >= 20800 ++ /* This feature was added upstream in libexpat 2.8.0. */ ++ XML_SetHashSalt16Bytes(self->itself, _Py_HashSecret.expat.hashsalt16); ++#elif XML_COMBINED_VERSION >= 20100 + /* This feature was added upstream in libexpat 2.1.0. */ + XML_SetHashSalt(self->itself, + (unsigned long)_Py_HashSecret.expat.hashsalt); +@@ -2310,6 +2313,12 @@ pyexpat_exec(PyObject *mod) + #else + capi->SetHashSalt = NULL; + #endif ++#if defined(XML_BACKPORT_SET_HASH_SALT_16_BYTES) \ ++ || XML_COMBINED_VERSION >= 20800 ++ capi->SetHashSalt16Bytes = XML_SetHashSalt16Bytes; ++#else ++ capi->SetHashSalt16Bytes = NULL; ++#endif + #if XML_COMBINED_VERSION >= 20600 + capi->SetReparseDeferralEnabled = XML_SetReparseDeferralEnabled; + #else diff --git a/meta/recipes-devtools/python/python3_3.14.5.bb b/meta/recipes-devtools/python/python3_3.14.5.bb index ed413dc1fe..83f6bf426c 100644 --- a/meta/recipes-devtools/python/python3_3.14.5.bb +++ b/meta/recipes-devtools/python/python3_3.14.5.bb @@ -36,6 +36,7 @@ SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \ file://0001-test_only_active_thread-skip-problematic-test.patch \ file://0001-prefer-valid-entrypoints.patch \ file://0001-Fix-ThreadingMock-call-count-race-condition.patch \ + file://CVE-2026-7210.patch \ " SRC_URI:append:class-native = " \ file://0001-Lib-sysconfig.py-use-prefix-value-from-build-configu.patch \