mirror of
https://git.yoctoproject.org/poky
synced 2026-07-27 07:27:12 +00:00
expat: patch CVE-2026-41080
Pick github PR [1] mentioned in [2]. * 969af8f4654ce50d837bb9199a73d1d02d2c7e16..4ba09dc471b39a78d77e5179d0243186c0c4ff7a * dropped code which doesn't exist in 2.6.4 yet (github actions, map file) * resolved minor conflicts (formatting) * picked 2 additional commits to apply the code cleanly [1] https://github.com/libexpat/libexpat/pull/1183 [2] https://security-tracker.debian.org/tracker/CVE-2026-41080 (From OE-Core rev: 273968c71fbf4a376996df555a8283bf63674ae8) Signed-off-by: Peter Marko <peter.marko@siemens.com> [YC: See discussion : https://lore.kernel.org/openembedded-core/2030b4435c8bc81bb4452637c0517ac33ab94d20.camel@pbarker.dev/T/#m56c5da4033c2f3571027c2745431178064ea1b5d ] Signed-off-by: Yoann Congal <yoann.congal@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
From fe04a7f0ff8afe57ba33d919f368b1ba23bcda92 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Sun, 30 Mar 2025 19:26:55 +0200
|
||||
Subject: [PATCH 1/3] lib/xmlparse.c: Address clang-tidy warning
|
||||
misc-no-recursion
|
||||
|
||||
CVE: CVE-2026-41080
|
||||
Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/fe04a7f0ff8afe57ba33d919f368b1ba23bcda92]
|
||||
Signed-off-by: Peter Marko <peter.marko@siemens.com>
|
||||
---
|
||||
lib/xmlparse.c | 17 ++++++++++-------
|
||||
1 file changed, 10 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index 9bc67f38..cb25c37b 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -1243,9 +1243,10 @@ generate_hash_secret_salt(XML_Parser parser) {
|
||||
|
||||
static unsigned long
|
||||
get_hash_secret_salt(XML_Parser parser) {
|
||||
- if (parser->m_parentParser != NULL)
|
||||
- return get_hash_secret_salt(parser->m_parentParser);
|
||||
- return parser->m_hash_secret_salt;
|
||||
+ const XML_Parser rootParser = getRootParserOf(parser, NULL);
|
||||
+ assert(! rootParser->m_parentParser);
|
||||
+
|
||||
+ return rootParser->m_hash_secret_salt;
|
||||
}
|
||||
|
||||
static enum XML_Error
|
||||
@@ -2321,12 +2322,14 @@ int XMLCALL
|
||||
XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) {
|
||||
if (parser == NULL)
|
||||
return 0;
|
||||
- if (parser->m_parentParser)
|
||||
- return XML_SetHashSalt(parser->m_parentParser, hash_salt);
|
||||
+
|
||||
+ const XML_Parser rootParser = getRootParserOf(parser, NULL);
|
||||
+ assert(! rootParser->m_parentParser);
|
||||
+
|
||||
/* block after XML_Parse()/XML_ParseBuffer() has been called */
|
||||
- if (parserBusy(parser))
|
||||
+ if (parserBusy(rootParser))
|
||||
return 0;
|
||||
- parser->m_hash_secret_salt = hash_salt;
|
||||
+ rootParser->m_hash_secret_salt = hash_salt;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
From 7fb2c7a454edc9e2880073a27f899c31d9b078ce Mon Sep 17 00:00:00 2001
|
||||
From: Atrem Borovik <polzovatellllk@gmail.com>
|
||||
Date: Sat, 20 Dec 2025 13:22:16 +0300
|
||||
Subject: [PATCH 2/3] WASI: remove getpid
|
||||
|
||||
CVE: CVE-2026-41080
|
||||
Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/7fb2c7a454edc9e2880073a27f899c31d9b078ce]
|
||||
Signed-off-by: Peter Marko <peter.marko@siemens.com>
|
||||
---
|
||||
lib/xmlparse.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index cb25c37b..1bafb948 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -1228,8 +1228,11 @@ generate_hash_secret_salt(XML_Parser parser) {
|
||||
# endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
|
||||
/* .. and self-made low quality for backup: */
|
||||
|
||||
+ entropy = gather_time_entropy();
|
||||
+# if ! defined(__wasi__)
|
||||
/* Process ID is 0 bits entropy if attacker has local access */
|
||||
- entropy = gather_time_entropy() ^ getpid();
|
||||
+ entropy ^= getpid();
|
||||
+# endif
|
||||
|
||||
/* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */
|
||||
if (sizeof(unsigned long) == 4) {
|
||||
@@ -0,0 +1,467 @@
|
||||
From b77ab600e1893fdcfc3868d0a46efcc87c87943d Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Wed, 8 Apr 2026 15:41:54 +0200
|
||||
Subject: [PATCH 3/3] [CVE-2026-41080] Improve protection against hash flooding
|
||||
(fixes #47)
|
||||
|
||||
Fixes #47
|
||||
|
||||
CVE: CVE-2026-41080
|
||||
Upstream-Status: Backport [https://github.com/libexpat/libexpat/pull/1183]
|
||||
Signed-off-by: Peter Marko <peter.marko@siemens.com>
|
||||
---
|
||||
Changes | 16 ++++++
|
||||
doc/reference.html | 51 ++++++++++++++--
|
||||
lib/expat.h | 12 ++++
|
||||
lib/internal.h | 2 +
|
||||
lib/xmlparse.c | 118 ++++++++++++++++++++++++++------------
|
||||
tests/basic_tests.c | 25 ++++++++
|
||||
6 files changed, 181 insertions(+), 43 deletions(-)
|
||||
|
||||
diff --git a/Changes b/Changes
|
||||
index 4265d608..1d87d6a0 100644
|
||||
--- a/Changes
|
||||
+++ b/Changes
|
||||
@@ -30,6 +30,22 @@
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
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).
|
||||
+
|
||||
Security fixes:
|
||||
#1018 #1034 CVE-2025-59375 -- Disallow use of disproportional amounts of
|
||||
dynamic memory from within an Expat parser (e.g. previously
|
||||
diff --git a/doc/reference.html b/doc/reference.html
|
||||
index 8f14b011..7f374f84 100644
|
||||
--- a/doc/reference.html
|
||||
+++ b/doc/reference.html
|
||||
@@ -174,7 +174,8 @@ interface.</p>
|
||||
<li><a href="#XML_GetAttributeInfo">XML_GetAttributeInfo</a></li>
|
||||
<li><a href="#XML_SetEncoding">XML_SetEncoding</a></li>
|
||||
<li><a href="#XML_SetParamEntityParsing">XML_SetParamEntityParsing</a></li>
|
||||
- <li><a href="#XML_SetHashSalt">XML_SetHashSalt</a></li>
|
||||
+ <li><a href="#XML_SetHashSalt">XML_SetHashSalt</a> (deprecated)</li>
|
||||
+ <li><a href="#XML_SetHashSalt16Bytes">XML_SetHashSalt16Bytes</a></li>
|
||||
<li><a href="#XML_UseForeignDTD">XML_UseForeignDTD</a></li>
|
||||
<li><a href="#XML_SetReturnNSTriplet">XML_SetReturnNSTriplet</a></li>
|
||||
<li><a href="#XML_DefaultCurrent">XML_DefaultCurrent</a></li>
|
||||
@@ -2553,10 +2554,10 @@ The choices for <code>code</code> are:
|
||||
no effect and will always return 0.
|
||||
</div>
|
||||
|
||||
-<h4 id="XML_SetHashSalt">XML_SetHashSalt</h4>
|
||||
+<h4 id="XML_SetHashSalt">XML_SetHashSalt (deprecated)</h4>
|
||||
<pre class="fcndec">
|
||||
int XMLCALL
|
||||
-XML_SetHashSalt(XML_Parser p,
|
||||
+XML_SetHashSalt(XML_Parser parser,
|
||||
unsigned long hash_salt);
|
||||
</pre>
|
||||
<div class="fcndef">
|
||||
@@ -2564,15 +2565,55 @@ 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 <code>XML_Parse</code> or <code>XML_ParseBuffer</code>.
|
||||
+after <code>XML_Parse</code> or <code>XML_ParseBuffer</code> or when
|
||||
+ <code>parser</code> is <code>NULL</code>.
|
||||
+ <p>
|
||||
+ <b>Note:</b> Function <code>XML_SetHashSalt</code> is
|
||||
+ <strong>deprecated</strong>. Please use function <code><a href=
|
||||
+ "#XML_SetHashSalt16Bytes">XML_SetHashSalt16Bytes</a></code> instead for better
|
||||
+ security. <code>XML_SetHashSalt</code> only provides 4 to 8 bytes of entropy
|
||||
+ (depending on the size of type <code>unsigned long</code>) while the SipHash
|
||||
+ implementation used by Expat can leverage up to 16 bytes of entropy — at least
|
||||
+ twice as much. Function <code><a href=
|
||||
+ "#XML_SetHashSalt16Bytes">XML_SetHashSalt16Bytes</a></code> of Expat >=2.7.6
|
||||
+ (and where backported) matches the amount of entropy supported by SipHash.
|
||||
+ </p>.
|
||||
<p><b>Note:</b> 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.</p>
|
||||
+a new random salt value internally if no value has been set by the start of parsing.</p>
|
||||
<p><b>Note:</b> One should not call <code>XML_SetHashSalt</code> with a
|
||||
hash salt value of 0, as this value is used as sentinel value to indicate
|
||||
that <code>XML_SetHashSalt</code> has <b>not</b> been called. Consequently
|
||||
such a call will have no effect, even if it returns 1.</p>
|
||||
</div>
|
||||
|
||||
+ <h4 id="XML_SetHashSalt16Bytes">
|
||||
+ XML_SetHashSalt16Bytes
|
||||
+ </h4>
|
||||
+
|
||||
+ <pre class="fcndec">
|
||||
+/* Added in Expat 2.7.6. */
|
||||
+XML_Bool XMLCALL
|
||||
+XML_SetHashSalt16Bytes(XML_Parser parser,
|
||||
+ const uint8_t entropy[16]);
|
||||
+</pre>
|
||||
+ <div class="fcndef">
|
||||
+ 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 <code>XML_TRUE</code> if
|
||||
+ successful, <code>XML_FALSE</code> when called after <code>XML_Parse</code> or
|
||||
+ <code>XML_ParseBuffer</code> or when <code>parser</code> is <code>NULL</code>.
|
||||
+ <p>
|
||||
+ <b>Note:</b> Setting a salt that is <em>not</em> from a source of high quality
|
||||
+ entropy (like <code>getentropy(3)</code>) will make the parser vulnerable to
|
||||
+ hash flooding attacks.
|
||||
+ </p>
|
||||
+
|
||||
+ <p>
|
||||
+ <b>Note:</b> 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.
|
||||
+ </p>
|
||||
+ </div>
|
||||
+
|
||||
<h4 id="XML_UseForeignDTD">XML_UseForeignDTD</h4>
|
||||
<pre class="fcndec">
|
||||
enum XML_Error XMLCALL
|
||||
diff --git a/lib/expat.h b/lib/expat.h
|
||||
index df207e9e..b356e002 100644
|
||||
--- a/lib/expat.h
|
||||
+++ b/lib/expat.h
|
||||
@@ -44,6 +44,7 @@
|
||||
#ifndef Expat_INCLUDED
|
||||
#define Expat_INCLUDED 1
|
||||
|
||||
+# include <stdint.h> // for uint8_t
|
||||
#include <stdlib.h>
|
||||
#include "expat_external.h"
|
||||
|
||||
@@ -916,10 +917,21 @@ 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]);
|
||||
+
|
||||
/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
|
||||
XML_GetErrorCode returns information about the error.
|
||||
*/
|
||||
diff --git a/lib/internal.h b/lib/internal.h
|
||||
index 32faaa05..617d6454 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 1bafb948..75a7e5d0 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;
|
||||
@@ -1189,69 +1190,65 @@ 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
|
||||
}
|
||||
|
||||
-static unsigned long
|
||||
-get_hash_secret_salt(XML_Parser parser) {
|
||||
- const XML_Parser rootParser = getRootParserOf(parser, NULL);
|
||||
- assert(! rootParser->m_parentParser);
|
||||
-
|
||||
- return rootParser->m_hash_secret_salt;
|
||||
-}
|
||||
-
|
||||
static enum XML_Error
|
||||
callProcessor(XML_Parser parser, const char *start, const char *end,
|
||||
const char **endPtr) {
|
||||
@@ -1320,8 +1316,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
|
||||
@@ -1609,7 +1607,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));
|
||||
@@ -1776,7 +1776,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 */
|
||||
@@ -1822,7 +1823,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
|
||||
@@ -1877,7 +1879,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
|
||||
@@ -2321,6 +2324,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)
|
||||
@@ -2332,10 +2336,46 @@ 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;
|
||||
+
|
||||
+ 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))) {
|
||||
@@ -7837,8 +7877,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
|
||||
diff --git a/tests/basic_tests.c b/tests/basic_tests.c
|
||||
index 023d9ce4..380caf19 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 = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
|
||||
@@ -6244,6 +6268,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);
|
||||
@@ -51,6 +51,9 @@ SRC_URI = "${GITHUB_BASE_URI}/download/R_${VERSION_TAG}/expat-${PV}.tar.bz2 \
|
||||
file://CVE-2026-32777-02.patch \
|
||||
file://CVE-2026-32778-01.patch \
|
||||
file://CVE-2026-32778-02.patch \
|
||||
file://CVE-2026-41080-01.patch \
|
||||
file://CVE-2026-41080-02.patch \
|
||||
file://CVE-2026-41080-03.patch \
|
||||
"
|
||||
|
||||
GITHUB_BASE_URI = "https://github.com/libexpat/libexpat/releases/"
|
||||
|
||||
Reference in New Issue
Block a user