!6 fix CVE-2013-0340 and fix reading uninitialized variable
From: @panxh_purple Reviewed-by: @xiezhipeng1 Signed-off-by: @xiezhipeng1
This commit is contained in:
commit
d940c756de
@ -0,0 +1,58 @@
|
||||
From f01a61402cd44bb0cb59db43e70309c01acc50d1 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Mon, 5 Apr 2021 17:23:26 +0200
|
||||
Subject: [PATCH] Autotools: Give test suite access to internal symbols
|
||||
|
||||
---
|
||||
lib/Makefile.am | 10 +++++++++-
|
||||
tests/Makefile.am | 4 ++--
|
||||
2 files changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/lib/Makefile.am b/lib/Makefile.am
|
||||
index 05343e2..f35a2e1 100644
|
||||
--- a/lib/Makefile.am
|
||||
+++ b/lib/Makefile.am
|
||||
@@ -34,16 +34,24 @@ include_HEADERS = \
|
||||
expat_external.h
|
||||
|
||||
lib_LTLIBRARIES = libexpat.la
|
||||
+noinst_LTLIBRARIES = libexpatinternal.la
|
||||
|
||||
libexpat_la_LDFLAGS = \
|
||||
-no-undefined \
|
||||
-version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@
|
||||
|
||||
-libexpat_la_SOURCES = \
|
||||
+libexpat_la_SOURCES =
|
||||
+
|
||||
+# This layer of indirection allows
|
||||
+# the test suite to access internal symbols
|
||||
+# despite compiling with -fvisibility=hidden
|
||||
+libexpatinternal_la_SOURCES = \
|
||||
xmlparse.c \
|
||||
xmltok.c \
|
||||
xmlrole.c
|
||||
|
||||
+libexpat_la_LIBADD = libexpatinternal.la
|
||||
+
|
||||
doc_DATA = \
|
||||
../AUTHORS \
|
||||
../Changes
|
||||
diff --git a/tests/Makefile.am b/tests/Makefile.am
|
||||
index e19fc1a..9724717 100644
|
||||
--- a/tests/Makefile.am
|
||||
+++ b/tests/Makefile.am
|
||||
@@ -52,8 +52,8 @@ runtests_SOURCES = \
|
||||
runtestspp_SOURCES = \
|
||||
runtestspp.cpp
|
||||
|
||||
-runtests_LDADD = libruntests.a ../lib/libexpat.la
|
||||
-runtestspp_LDADD = libruntests.a ../lib/libexpat.la
|
||||
+runtests_LDADD = libruntests.a ../lib/libexpatinternal.la
|
||||
+runtestspp_LDADD = libruntests.a ../lib/libexpatinternal.la
|
||||
|
||||
EXTRA_DIST = \
|
||||
chardata.h \
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
From 1e053c698b7ff8f7b4cc3c7c6e9945b72c3d5286 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Tue, 20 Apr 2021 19:01:30 +0200
|
||||
Subject: [PATCH] Autotools|CMake: Suppress -Wpedantic-ms-format false
|
||||
positives
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Addresses warning:
|
||||
ISO C does not support the ‘I64’ ms_printf length modifier.
|
||||
|
||||
It seems correct and relevant with __USE_MINGW_ANSI_STDIO, only.
|
||||
And -Werror doesn't tolerate false positives...
|
||||
---
|
||||
CMakeLists.txt | 4 ++++
|
||||
configure.ac | 2 +-
|
||||
2 files changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 951df0e..96ac5da 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -248,6 +248,10 @@ if(FLAG_VISIBILITY)
|
||||
add_definitions(-DXML_ENABLE_VISIBILITY=1)
|
||||
set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -fvisibility=hidden")
|
||||
endif(FLAG_VISIBILITY)
|
||||
+if(MINGW)
|
||||
+ # Without __USE_MINGW_ANSI_STDIO the compiler produces a false positive
|
||||
+ set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -Wno-pedantic-ms-format")
|
||||
+endif()
|
||||
if (EXPAT_WARNINGS_AS_ERRORS)
|
||||
if(MSVC)
|
||||
add_definitions(/WX)
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index f26ce6c..7d60a2c 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -111,7 +111,7 @@ AS_IF([test "$GCC" = yes],
|
||||
AX_APPEND_COMPILE_FLAGS([-fno-strict-aliasing -Wmissing-prototypes -Wstrict-prototypes], [CFLAGS])
|
||||
AX_APPEND_COMPILE_FLAGS([-pedantic -Wduplicated-cond -Wduplicated-branches -Wlogical-op], [CFLAGS])
|
||||
AX_APPEND_COMPILE_FLAGS([-Wrestrict -Wnull-dereference -Wjump-misses-init -Wdouble-promotion], [CFLAGS])
|
||||
- AX_APPEND_COMPILE_FLAGS([-Wshadow -Wformat=2 -Wmisleading-indentation], [CFLAGS])])
|
||||
+ AX_APPEND_COMPILE_FLAGS([-Wshadow -Wformat=2 -Wno-pedantic-ms-format -Wmisleading-indentation], [CFLAGS])])
|
||||
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_PROG_CXX
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
From 3f2f8786623cc3e89a1f4384715b3ad178c5ee2c Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Mon, 19 Apr 2021 15:08:17 +0200
|
||||
Subject: [PATCH] Changes: Document protection against billion laughs attacks
|
||||
|
||||
---
|
||||
Changes | 34 ++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 34 insertions(+)
|
||||
|
||||
diff --git a/Changes b/Changes
|
||||
index 2ecc8a0..a435999 100644
|
||||
--- a/Changes
|
||||
+++ b/Changes
|
||||
@@ -3,10 +3,39 @@ NOTE: We are looking for help with a few things:
|
||||
If you can help, please get in touch. Thanks!
|
||||
|
||||
Release 2.2.9 Wed Septemper 25 2019
|
||||
+ Security fixes:
|
||||
+ #34 #466 CVE-2013-0340/CWE-776 -- Protect against billion laughs attacks
|
||||
+ (denial-of-service; flavors targeting CPU time or RAM or both,
|
||||
+ leveraging general entities or parameter entities or both)
|
||||
+ by tracking and limiting the input amplification factor
|
||||
+ (<amplification> := (<direct> + <indirect>) / <direct>).
|
||||
+ By conservative default, amplification up to a factor of 100.0
|
||||
+ is tolerated and rejection only starts after 8 MiB of output bytes
|
||||
+ (=<direct> + <indirect>) have been processed.
|
||||
+ A new error code XML_ERROR_AMPLIFICATION_LIMIT_BREACH signals
|
||||
+ this condition.
|
||||
+
|
||||
Bug fixes:
|
||||
#390 #395 Fix undefined behavior during parsing when compiled with
|
||||
-DXML_UNICODE that was introduced with Expat 2.0.1
|
||||
|
||||
+ New features:
|
||||
+ #34 #466 Add two new API functions to further tighten billion laughs
|
||||
+ protection parameters when desired.
|
||||
+ - XML_SetBillionLaughsAttackProtectionMaximumAmplification
|
||||
+ - XML_SetBillionLaughsAttackProtectionActivationThreshold
|
||||
+ Please see file "doc/reference.html" for more details.
|
||||
+ If you ever need to increase the defaults for non-attack XML
|
||||
+ payload, please file a bug report with libexpat.
|
||||
+ #34 #466 Introduce environment switches EXPAT_ACCOUNTING_DEBUG=(0|1|2|3)
|
||||
+ and EXPAT_ENTITY_DEBUG=(0|1) for runtime debugging of accounting
|
||||
+ and entity processing; specific behavior of these values may
|
||||
+ change in the future.
|
||||
+ #34 #466 xmlwf: Add arguments "-a FACTOR" and "-b BYTES" to further tighten
|
||||
+ billion laughs protection parameters when desired.
|
||||
+ If you ever need to increase the defaults for non-attack XML
|
||||
+ payload, please file a bug report with libexpat.
|
||||
+
|
||||
Other changes:
|
||||
examples: Drop executable bits from elements.c
|
||||
#349 Windows: Change the name of the Windows DLLs from expat*.dll
|
||||
@@ -20,6 +49,11 @@ Release 2.2.9 Wed Septemper 25 2019
|
||||
|
||||
Special thanks to:
|
||||
Ben Wagner
|
||||
+ Nick Wellnhofer
|
||||
+ Yury Gribov
|
||||
+ and
|
||||
+ Clang LeakSan
|
||||
+ JetBrains
|
||||
|
||||
Release 2.2.8 Fri Septemper 13 2019
|
||||
Security fixes:
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,130 @@
|
||||
From 899c00e613800ef973a93ce8f83b3514992f1afa Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Sun, 25 Apr 2021 20:57:17 +0200
|
||||
Subject: [PATCH] doc/reference.html: Document billion laughs attack protection
|
||||
API
|
||||
|
||||
---
|
||||
doc/reference.html | 99 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 99 insertions(+)
|
||||
|
||||
diff --git a/doc/reference.html b/doc/reference.html
|
||||
index 1b37071..06a70e2 100644
|
||||
--- a/doc/reference.html
|
||||
+++ b/doc/reference.html
|
||||
@@ -149,6 +149,13 @@ interface.</p>
|
||||
<li><a href="#XML_GetInputContext">XML_GetInputContext</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
+ <li>
|
||||
+ <a href="#billion-laughs">Billion Laughs Attack Protection</a>
|
||||
+ <ul>
|
||||
+ <li><a href="#XML_SetBillionLaughsAttackProtectionMaximumAmplification">XML_SetBillionLaughsAttackProtectionMaximumAmplification</a></li>
|
||||
+ <li><a href="#XML_SetBillionLaughsAttackProtectionActivationThreshold">XML_SetBillionLaughsAttackProtectionActivationThreshold</a></li>
|
||||
+ </ul>
|
||||
+ </li>
|
||||
<li><a href="#miscellaneous">Miscellaneous Functions</a>
|
||||
<ul>
|
||||
<li><a href="#XML_SetUserData">XML_SetUserData</a></li>
|
||||
@@ -2074,6 +2081,98 @@ parse position may be before the beginning of the buffer.</p>
|
||||
return NULL.</p>
|
||||
</div>
|
||||
|
||||
+<h3><a name="billion-laughs">Billion Laughs Attack Protection</a></h3>
|
||||
+
|
||||
+<p>The functions in this section configure the built-in
|
||||
+ protection against various forms of
|
||||
+ <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>.</p>
|
||||
+
|
||||
+<h4 id="XML_SetBillionLaughsAttackProtectionMaximumAmplification">XML_SetBillionLaughsAttackProtectionMaximumAmplification</h4>
|
||||
+<pre class="fcndec">
|
||||
+/* Added in Expat 2.4.0. */
|
||||
+XML_Bool XMLCALL
|
||||
+XML_SetBillionLaughsAttackProtectionMaximumAmplification(XML_Parser p,
|
||||
+ float maximumAmplificationFactor);
|
||||
+</pre>
|
||||
+<div class="fcndef">
|
||||
+ <p>
|
||||
+ Sets the maximum tolerated amplification factor
|
||||
+ for protection against
|
||||
+ <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>
|
||||
+ (default: <code>100.0</code>)
|
||||
+ of parser <code>p</code> to <code>maximumAmplificationFactor</code>, and
|
||||
+ returns <code>XML_TRUE</code> upon success and <code>XML_TRUE</code> upon error.
|
||||
+ </p>
|
||||
+
|
||||
+ The amplification factor is calculated as ..
|
||||
+ <pre>
|
||||
+ amplification := (direct + indirect) / direct
|
||||
+ </pre>
|
||||
+ .. while parsing, whereas
|
||||
+ <code>direct</code> is the number of bytes read from the primary document in parsing and
|
||||
+ <code>indirect</code> is the number of bytes added by expanding entities and reading of external DTD files, combined.
|
||||
+
|
||||
+ <p>For a call to <code>XML_SetBillionLaughsAttackProtectionMaximumAmplification</code> to succeed:</p>
|
||||
+ <ul>
|
||||
+ <li>parser <code>p</code> must be a non-<code>NULL</code> root parser (without any parent parsers) and</li>
|
||||
+ <li><code>maximumAmplificationFactor</code> must be non-<code>NaN</code> and greater than or equal to <code>1.0</code>.</li>
|
||||
+ </ul>
|
||||
+
|
||||
+ <p>
|
||||
+ <strong>Note:</strong>
|
||||
+ If you ever need to increase this value for non-attack payload,
|
||||
+ please <a href="https://github.com/libexpat/libexpat/issues">file a bug report</a>.
|
||||
+ </p>
|
||||
+
|
||||
+ <p>
|
||||
+ <strong>Note:</strong>
|
||||
+ Peak amplifications
|
||||
+ of factor 15,000 for the entire payload and
|
||||
+ of factor 30,000 in the middle of parsing
|
||||
+ have been observed with small benign files in practice.
|
||||
+
|
||||
+ So if you do reduce the maximum allowed amplification,
|
||||
+ please make sure that the activation threshold is still big enough
|
||||
+ to not end up with undesired false positives (i.e. benign files being rejected).
|
||||
+ </p>
|
||||
+</div>
|
||||
+
|
||||
+<h4 id="XML_SetBillionLaughsAttackProtectionActivationThreshold">XML_SetBillionLaughsAttackProtectionActivationThreshold</h4>
|
||||
+<pre class="fcndec">
|
||||
+/* Added in Expat 2.4.0. */
|
||||
+XML_Bool XMLCALL
|
||||
+XML_SetBillionLaughsAttackProtectionActivationThreshold(XML_Parser p,
|
||||
+ unsigned long long activationThresholdBytes);
|
||||
+</pre>
|
||||
+<div class="fcndef">
|
||||
+ <p>
|
||||
+ Sets number of output bytes (including amplification from entity expansion and reading DTD files)
|
||||
+ needed to activate protection against
|
||||
+ <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>
|
||||
+ (default: <code>8 MiB</code>)
|
||||
+ of parser <code>p</code> to <code>activationThresholdBytes</code>, and
|
||||
+ returns <code>XML_TRUE</code> upon success and <code>XML_TRUE</code> upon error.
|
||||
+ </p>
|
||||
+
|
||||
+ <p>For a call to <code>XML_SetBillionLaughsAttackProtectionActivationThreshold</code> to succeed:</p>
|
||||
+ <ul>
|
||||
+ <li>parser <code>p</code> must be a non-<code>NULL</code> root parser (without any parent parsers).</li>
|
||||
+ </ul>
|
||||
+
|
||||
+ <p>
|
||||
+ <strong>Note:</strong>
|
||||
+ If you ever need to increase this value for non-attack payload,
|
||||
+ please <a href="https://github.com/libexpat/libexpat/issues">file a bug report</a>.
|
||||
+ </p>
|
||||
+
|
||||
+ <p>
|
||||
+ <strong>Note:</strong>
|
||||
+ Activation thresholds below 4 MiB are known to break support for
|
||||
+ <a href="https://en.wikipedia.org/wiki/Darwin_Information_Typing_Architecture">DITA</a> 1.3 payload
|
||||
+ and are hence not recommended.
|
||||
+ </p>
|
||||
+</div>
|
||||
+
|
||||
<h3><a name="miscellaneous">Miscellaneous functions</a></h3>
|
||||
|
||||
<p>The functions in this section either obtain state information from
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
From 857fdc4c3bf47eb3fedcd15d3763f62727476df0 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Wed, 14 Apr 2021 17:30:22 +0200
|
||||
Subject: [PATCH] lib: Add prefix "expat: " to EXPAT_ENTROPY_DEBUG=1 stderr
|
||||
output
|
||||
|
||||
---
|
||||
lib/xmlparse.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index fce7447..641f005 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -889,7 +889,7 @@ static unsigned long
|
||||
ENTROPY_DEBUG(const char *label, unsigned long entropy) {
|
||||
const char *const EXPAT_ENTROPY_DEBUG = getenv("EXPAT_ENTROPY_DEBUG");
|
||||
if (EXPAT_ENTROPY_DEBUG && ! strcmp(EXPAT_ENTROPY_DEBUG, "1")) {
|
||||
- fprintf(stderr, "Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
|
||||
+ fprintf(stderr, "expat: Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
|
||||
(int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy));
|
||||
}
|
||||
return entropy;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
From fcd0e14c3e35a56eb7ec42142a12e984fbe1b3c0 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Tue, 20 Apr 2021 14:01:27 +0200
|
||||
Subject: [PATCH] lib: Address Cppcheck 2.4.1 warning "uninitvar"
|
||||
|
||||
---
|
||||
lib/xmlparse.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index 97e7980..4628def 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -5581,7 +5581,8 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
- const char *next;
|
||||
+ const char *next
|
||||
+ = ptr; /* XmlAttributeValueTok doesn't always set the last arg */
|
||||
int tok = XmlAttributeValueTok(enc, ptr, end, &next);
|
||||
#ifdef XML_DTD
|
||||
if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
|
||||
@@ -5792,7 +5793,8 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
- const char *next;
|
||||
+ const char *next
|
||||
+ = entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
|
||||
int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
|
||||
|
||||
#ifdef XML_DTD
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
From 8af7d22ff029796484c78a16d4c6d44a47cb5729 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Mon, 19 Apr 2021 21:44:38 +0200
|
||||
Subject: [PATCH] lib: Allow test suite to access raw accounting values
|
||||
|
||||
---
|
||||
lib/internal.h | 7 +++++++
|
||||
lib/xmlparse.c | 14 ++++++++++++++
|
||||
2 files changed, 21 insertions(+)
|
||||
|
||||
diff --git a/lib/internal.h b/lib/internal.h
|
||||
index 40c5033..ce6d27a 100644
|
||||
--- a/lib/internal.h
|
||||
+++ b/lib/internal.h
|
||||
@@ -139,6 +139,8 @@
|
||||
8388608 // 8 MiB, 2^23
|
||||
/* NOTE END */
|
||||
|
||||
+#include "expat.h" // so we can use type XML_Parser below
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -146,6 +148,11 @@ extern "C" {
|
||||
_INTERNAL_trim_to_complete_utf8_characters(const char *from,
|
||||
const char **fromLimRef);
|
||||
|
||||
+#if defined(XML_DTD)
|
||||
+unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser);
|
||||
+unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
|
||||
+#endif
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index 4628def..fce7447 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -7357,6 +7357,20 @@ accountingDiffTolerated(XML_Parser originParser, int tok, const char *before,
|
||||
return tolerated;
|
||||
}
|
||||
|
||||
+unsigned long long
|
||||
+testingAccountingGetCountBytesDirect(XML_Parser parser) {
|
||||
+ if (! parser)
|
||||
+ return 0;
|
||||
+ return parser->m_accounting.countBytesDirect;
|
||||
+}
|
||||
+
|
||||
+unsigned long long
|
||||
+testingAccountingGetCountBytesIndirect(XML_Parser parser) {
|
||||
+ if (! parser)
|
||||
+ return 0;
|
||||
+ return parser->m_accounting.countBytesIndirect;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
|
||||
const char *action, int sourceLine) {
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,119 @@
|
||||
From 60959f2b491876199879d97c8ed956eabb0c2e73 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Fri, 14 May 2021 20:09:22 +0200
|
||||
Subject: [PATCH] lib: Fix accounting of CDATA sections inside of general
|
||||
entities
|
||||
|
||||
---
|
||||
Changes | 9 +++++----
|
||||
lib/xmlparse.c | 20 ++++++++++++--------
|
||||
2 files changed, 17 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/Changes b/Changes
|
||||
index a435999..e62814b 100644
|
||||
--- a/Changes
|
||||
+++ b/Changes
|
||||
@@ -4,7 +4,7 @@ NOTE: We are looking for help with a few things:
|
||||
|
||||
Release 2.2.9 Wed Septemper 25 2019
|
||||
Security fixes:
|
||||
- #34 #466 CVE-2013-0340/CWE-776 -- Protect against billion laughs attacks
|
||||
+ #34 #466 #484 CVE-2013-0340/CWE-776 -- Protect against billion laughs attacks
|
||||
(denial-of-service; flavors targeting CPU time or RAM or both,
|
||||
leveraging general entities or parameter entities or both)
|
||||
by tracking and limiting the input amplification factor
|
||||
@@ -20,18 +20,18 @@ Release 2.2.9 Wed Septemper 25 2019
|
||||
-DXML_UNICODE that was introduced with Expat 2.0.1
|
||||
|
||||
New features:
|
||||
- #34 #466 Add two new API functions to further tighten billion laughs
|
||||
+ #34 #466 #484 Add two new API functions to further tighten billion laughs
|
||||
protection parameters when desired.
|
||||
- XML_SetBillionLaughsAttackProtectionMaximumAmplification
|
||||
- XML_SetBillionLaughsAttackProtectionActivationThreshold
|
||||
Please see file "doc/reference.html" for more details.
|
||||
If you ever need to increase the defaults for non-attack XML
|
||||
payload, please file a bug report with libexpat.
|
||||
- #34 #466 Introduce environment switches EXPAT_ACCOUNTING_DEBUG=(0|1|2|3)
|
||||
+ #34 #466 #484 Introduce environment switches EXPAT_ACCOUNTING_DEBUG=(0|1|2|3)
|
||||
and EXPAT_ENTITY_DEBUG=(0|1) for runtime debugging of accounting
|
||||
and entity processing; specific behavior of these values may
|
||||
change in the future.
|
||||
- #34 #466 xmlwf: Add arguments "-a FACTOR" and "-b BYTES" to further tighten
|
||||
+ #34 #466 #484 xmlwf: Add arguments "-a FACTOR" and "-b BYTES" to further tighten
|
||||
billion laughs protection parameters when desired.
|
||||
If you ever need to increase the defaults for non-attack XML
|
||||
payload, please file a bug report with libexpat.
|
||||
@@ -54,6 +54,7 @@ Release 2.2.9 Wed Septemper 25 2019
|
||||
and
|
||||
Clang LeakSan
|
||||
JetBrains
|
||||
+ OSS-Fuzz
|
||||
|
||||
Release 2.2.8 Fri Septemper 13 2019
|
||||
Security fixes:
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index 3870dfa..64d5dc3 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -448,7 +448,8 @@ static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
|
||||
XML_Bool haveMore, enum XML_Account account);
|
||||
static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *,
|
||||
const char **startPtr, const char *end,
|
||||
- const char **nextPtr, XML_Bool haveMore);
|
||||
+ const char **nextPtr, XML_Bool haveMore,
|
||||
+ enum XML_Account account);
|
||||
#ifdef XML_DTD
|
||||
static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
|
||||
const char **startPtr, const char *end,
|
||||
@@ -3062,7 +3063,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
||||
/* END disabled code */
|
||||
else if (parser->m_defaultHandler)
|
||||
reportDefault(parser, enc, s, next);
|
||||
- result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
|
||||
+ result
|
||||
+ = doCdataSection(parser, enc, &next, end, nextPtr, haveMore, account);
|
||||
if (result != XML_ERROR_NONE)
|
||||
return result;
|
||||
else if (! next) {
|
||||
@@ -3691,9 +3693,9 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
|
||||
static enum XML_Error PTRCALL
|
||||
cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
|
||||
const char **endPtr) {
|
||||
- enum XML_Error result
|
||||
- = doCdataSection(parser, parser->m_encoding, &start, end, endPtr,
|
||||
- (XML_Bool)! parser->m_parsingStatus.finalBuffer);
|
||||
+ enum XML_Error result = doCdataSection(
|
||||
+ parser, parser->m_encoding, &start, end, endPtr,
|
||||
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
|
||||
if (result != XML_ERROR_NONE)
|
||||
return result;
|
||||
if (start) {
|
||||
@@ -3713,7 +3715,8 @@ cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
|
||||
*/
|
||||
static enum XML_Error
|
||||
doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
||||
- const char *end, const char **nextPtr, XML_Bool haveMore) {
|
||||
+ const char *end, const char **nextPtr, XML_Bool haveMore,
|
||||
+ enum XML_Account account) {
|
||||
const char *s = *startPtr;
|
||||
const char **eventPP;
|
||||
const char **eventEndPP;
|
||||
@@ -3732,11 +3735,12 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
||||
const char *next;
|
||||
int tok = XmlCdataSectionTok(enc, s, end, &next);
|
||||
#ifdef XML_DTD
|
||||
- if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
|
||||
- XML_ACCOUNT_DIRECT)) {
|
||||
+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
|
||||
accountingOnAbort(parser);
|
||||
return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
|
||||
}
|
||||
+#else
|
||||
+ UNUSED_P(account);
|
||||
#endif
|
||||
*eventEndPP = next;
|
||||
switch (tok) {
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
From 29c3748788ff5ba0e4b14b02dfa15080177a3c8c Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Mon, 19 Apr 2021 20:39:42 +0200
|
||||
Subject: [PATCH] lib: Make EXPAT_ENTROPY_DEBUG consistent with other
|
||||
EXPAT_*_DEBUG variables
|
||||
|
||||
---
|
||||
lib/xmlparse.c | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index 641f005..adaab23 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -887,8 +887,7 @@ gather_time_entropy(void) {
|
||||
|
||||
static unsigned long
|
||||
ENTROPY_DEBUG(const char *label, unsigned long entropy) {
|
||||
- const char *const EXPAT_ENTROPY_DEBUG = getenv("EXPAT_ENTROPY_DEBUG");
|
||||
- if (EXPAT_ENTROPY_DEBUG && ! strcmp(EXPAT_ENTROPY_DEBUG, "1")) {
|
||||
+ 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));
|
||||
}
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
From 77cfb8f4cd9679cef27ae9bc38e39ac51235af2d Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Fri, 14 May 2021 20:26:26 +0200
|
||||
Subject: [PATCH] tests: Cover accounting of CDATA sections inside of general
|
||||
entities
|
||||
|
||||
---
|
||||
tests/runtests.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/tests/runtests.c b/tests/runtests.c
|
||||
index 0e2b49f..e394456 100644
|
||||
--- a/tests/runtests.c
|
||||
+++ b/tests/runtests.c
|
||||
@@ -11318,6 +11318,16 @@ START_TEST(test_accounting_precision) {
|
||||
|
||||
/* CDATA */
|
||||
{"<e><![CDATA[one two three]]></e>", NULL, NULL, 0, filled_later},
|
||||
+ /* The following is the essence of this OSS-Fuzz finding:
|
||||
+ https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=34302
|
||||
+ https://oss-fuzz.com/testcase-detail/4860575394955264
|
||||
+ */
|
||||
+ {"<!DOCTYPE r [\n"
|
||||
+ "<!ENTITY e \"111<![CDATA[2 <= 2]]>333\">\n"
|
||||
+ "]>\n"
|
||||
+ "<r>&e;</r>\n",
|
||||
+ NULL, NULL, sizeof(XML_Char) * strlen("111<![CDATA[2 <= 2]]>333"),
|
||||
+ filled_later},
|
||||
|
||||
/* Conditional sections */
|
||||
{"<!DOCTYPE r [\n"
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
374
backport-CVE-2013-0340-tests-Cover-accounting.patch
Normal file
374
backport-CVE-2013-0340-tests-Cover-accounting.patch
Normal file
@ -0,0 +1,374 @@
|
||||
From 271efb6069c5c979545cfbe00b738184c5632b93 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Wed, 21 Apr 2021 00:11:04 +0200
|
||||
Subject: [PATCH] tests: Cover accounting
|
||||
|
||||
---
|
||||
lib/internal.h | 6 +-
|
||||
tests/runtests.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 304 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/internal.h b/lib/internal.h
|
||||
index ce6d27a..377c12b 100644
|
||||
--- a/lib/internal.h
|
||||
+++ b/lib/internal.h
|
||||
@@ -109,10 +109,12 @@
|
||||
|
||||
#if defined(_WIN32) && ! defined(__USE_MINGW_ANSI_STDIO)
|
||||
# define EXPAT_FMT_ULL(midpart) "%" midpart "I64u"
|
||||
-# if defined(_WIN64) // Note: modifier "td" does not work for MinGW
|
||||
+# if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW
|
||||
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
|
||||
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "I64u"
|
||||
# else
|
||||
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
|
||||
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
|
||||
# endif
|
||||
#else
|
||||
# define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
|
||||
@@ -120,8 +122,10 @@
|
||||
# error Compiler did not define ULONG_MAX for us
|
||||
# elif ULONG_MAX == 18446744073709551615u // 2^64-1
|
||||
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
|
||||
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu"
|
||||
# else
|
||||
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
|
||||
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
diff --git a/tests/runtests.c b/tests/runtests.c
|
||||
index 40fdfb4..5234f49 100644
|
||||
--- a/tests/runtests.c
|
||||
+++ b/tests/runtests.c
|
||||
@@ -61,7 +61,7 @@
|
||||
#include "expat.h"
|
||||
#include "chardata.h"
|
||||
#include "structdata.h"
|
||||
-#include "internal.h" /* for UNUSED_P only */
|
||||
+#include "internal.h"
|
||||
#include "minicheck.h"
|
||||
#include "memcheck.h"
|
||||
#include "siphash.h"
|
||||
@@ -11225,6 +11225,296 @@ START_TEST(test_nsalloc_prefixed_element) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
+#if defined(XML_DTD)
|
||||
+typedef enum XML_Status (*XmlParseFunction)(XML_Parser, const char *, int, int);
|
||||
+
|
||||
+struct AccountingTestCase {
|
||||
+ const char *primaryText;
|
||||
+ const char *firstExternalText; /* often NULL */
|
||||
+ const char *secondExternalText; /* often NULL */
|
||||
+ const unsigned long long expectedCountBytesIndirectExtra;
|
||||
+ XML_Bool singleBytesWanted;
|
||||
+};
|
||||
+
|
||||
+static int
|
||||
+accounting_external_entity_ref_handler(XML_Parser parser,
|
||||
+ const XML_Char *context,
|
||||
+ const XML_Char *base,
|
||||
+ const XML_Char *systemId,
|
||||
+ const XML_Char *publicId) {
|
||||
+ UNUSED_P(context);
|
||||
+ UNUSED_P(base);
|
||||
+ UNUSED_P(publicId);
|
||||
+
|
||||
+ const struct AccountingTestCase *const testCase
|
||||
+ = (const struct AccountingTestCase *)XML_GetUserData(parser);
|
||||
+
|
||||
+ const char *externalText = NULL;
|
||||
+ if (xcstrcmp(systemId, XCS("first.ent")) == 0) {
|
||||
+ externalText = testCase->firstExternalText;
|
||||
+ } else if (xcstrcmp(systemId, XCS("second.ent")) == 0) {
|
||||
+ externalText = testCase->secondExternalText;
|
||||
+ } else {
|
||||
+ assert(! "systemId is neither \"first.ent\" nor \"second.ent\"");
|
||||
+ }
|
||||
+ assert(externalText);
|
||||
+
|
||||
+ XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
|
||||
+ assert(entParser);
|
||||
+
|
||||
+ const XmlParseFunction xmlParseFunction
|
||||
+ = testCase->singleBytesWanted ? _XML_Parse_SINGLE_BYTES : XML_Parse;
|
||||
+
|
||||
+ const enum XML_Status status = xmlParseFunction(
|
||||
+ entParser, externalText, (int)strlen(externalText), XML_TRUE);
|
||||
+
|
||||
+ XML_ParserFree(entParser);
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+START_TEST(test_accounting_precision) {
|
||||
+ const XML_Bool filled_later = XML_TRUE; /* value is arbitrary */
|
||||
+ struct AccountingTestCase cases[] = {
|
||||
+ {"<e/>", NULL, NULL, 0, 0},
|
||||
+ {"<e></e>", NULL, NULL, 0, 0},
|
||||
+
|
||||
+ /* Attributes */
|
||||
+ {"<e k1=\"v2\" k2=\"v2\"/>", NULL, NULL, 0, filled_later},
|
||||
+ {"<e k1=\"v2\" k2=\"v2\"></e>", NULL, NULL, 0, 0},
|
||||
+ {"<p:e xmlns:p=\"https://domain.invalid/\" />", NULL, NULL, 0,
|
||||
+ filled_later},
|
||||
+ {"<e k=\"&'><"\" />", NULL, NULL,
|
||||
+ sizeof(XML_Char) * 5 /* number of predefined entites */, filled_later},
|
||||
+ {"<e1 xmlns='https://example.org/'>\n"
|
||||
+ " <e2 xmlns=''/>\n"
|
||||
+ "</e1>",
|
||||
+ NULL, NULL, 0, filled_later},
|
||||
+
|
||||
+ /* Text */
|
||||
+ {"<e>text</e>", NULL, NULL, 0, filled_later},
|
||||
+ {"<e1><e2>text1<e3/>text2</e2></e1>", NULL, NULL, 0, filled_later},
|
||||
+ {"<e>&'><"</e>", NULL, NULL,
|
||||
+ sizeof(XML_Char) * 5 /* number of predefined entites */, filled_later},
|
||||
+ {"<e>A)</e>", NULL, NULL, 0, filled_later},
|
||||
+
|
||||
+ /* Prolog */
|
||||
+ {"<?xml version=\"1.0\"?><root/>", NULL, NULL, 0, filled_later},
|
||||
+
|
||||
+ /* Whitespace */
|
||||
+ {" <e1> <e2> </e2> </e1> ", NULL, NULL, 0, filled_later},
|
||||
+ {"<e1 ><e2 /></e1 >", NULL, NULL, 0, filled_later},
|
||||
+ {"<e1><e2 k = \"v\"/><e3 k = 'v'/></e1>", NULL, NULL, 0, filled_later},
|
||||
+
|
||||
+ /* Comments */
|
||||
+ {"<!-- Comment --><e><!-- Comment --></e>", NULL, NULL, 0, filled_later},
|
||||
+
|
||||
+ /* Processing instructions */
|
||||
+ {"<?xml-stylesheet type=\"text/xsl\" href=\"https://domain.invalid/\" media=\"all\"?><e/>",
|
||||
+ NULL, NULL, 0, filled_later},
|
||||
+ {"<?pi0?><?pi1 ?><?pi2 ?><!DOCTYPE r SYSTEM 'first.ent'><r/>",
|
||||
+ "<?pi3?><!ENTITY % e1 SYSTEM 'second.ent'><?pi4?>%e1;<?pi5?>", "<?pi6?>",
|
||||
+ 0, filled_later},
|
||||
+
|
||||
+ /* CDATA */
|
||||
+ {"<e><![CDATA[one two three]]></e>", NULL, NULL, 0, filled_later},
|
||||
+
|
||||
+ /* Conditional sections */
|
||||
+ {"<!DOCTYPE r [\n"
|
||||
+ "<!ENTITY % draft 'INCLUDE'>\n"
|
||||
+ "<!ENTITY % final 'IGNORE'>\n"
|
||||
+ "<!ENTITY % import SYSTEM \"first.ent\">\n"
|
||||
+ "%import;\n"
|
||||
+ "]>\n"
|
||||
+ "<r/>\n",
|
||||
+ "<![%draft;[<!--1-->]]>\n"
|
||||
+ "<![%final;[<!--22-->]]>",
|
||||
+ NULL, sizeof(XML_Char) * (strlen("INCLUDE") + strlen("IGNORE")),
|
||||
+ filled_later},
|
||||
+
|
||||
+ /* General entities */
|
||||
+ {"<!DOCTYPE root [\n"
|
||||
+ "<!ENTITY nine \"123456789\">\n"
|
||||
+ "]>\n"
|
||||
+ "<root>&nine;</root>",
|
||||
+ NULL, NULL, sizeof(XML_Char) * strlen("123456789"), filled_later},
|
||||
+ {"<!DOCTYPE root [\n"
|
||||
+ "<!ENTITY nine \"123456789\">\n"
|
||||
+ "]>\n"
|
||||
+ "<root k1=\"&nine;\"/>",
|
||||
+ NULL, NULL, sizeof(XML_Char) * strlen("123456789"), filled_later},
|
||||
+ {"<!DOCTYPE root [\n"
|
||||
+ "<!ENTITY nine \"123456789\">\n"
|
||||
+ "<!ENTITY nine2 \"&nine;&nine;\">\n"
|
||||
+ "]>\n"
|
||||
+ "<root>&nine2;&nine2;&nine2;</root>",
|
||||
+ NULL, NULL,
|
||||
+ sizeof(XML_Char) * 3 /* calls to &nine2; */ * 2 /* calls to &nine; */
|
||||
+ * (strlen("&nine;") + strlen("123456789")),
|
||||
+ filled_later},
|
||||
+ {"<!DOCTYPE r [\n"
|
||||
+ " <!ENTITY five SYSTEM 'first.ent'>\n"
|
||||
+ "]>\n"
|
||||
+ "<r>&five;</r>",
|
||||
+ "12345", NULL, 0, filled_later},
|
||||
+
|
||||
+ /* Parameter entities */
|
||||
+ {"<!DOCTYPE r [\n"
|
||||
+ "<!ENTITY % comment \"<!---->\">\n"
|
||||
+ "%comment;\n"
|
||||
+ "]>\n"
|
||||
+ "<r/>",
|
||||
+ NULL, NULL, sizeof(XML_Char) * strlen("<!---->"), filled_later},
|
||||
+ {"<!DOCTYPE r [\n"
|
||||
+ "<!ENTITY % ninedef \"<!ENTITY nine "123456789">\">\n"
|
||||
+ "%ninedef;\n"
|
||||
+ "]>\n"
|
||||
+ "<r>&nine;</r>",
|
||||
+ NULL, NULL,
|
||||
+ sizeof(XML_Char)
|
||||
+ * (strlen("<!ENTITY nine \"123456789\">") + strlen("123456789")),
|
||||
+ filled_later},
|
||||
+ {"<!DOCTYPE r [\n"
|
||||
+ "<!ENTITY % comment \"<!--1-->\">\n"
|
||||
+ "<!ENTITY % comment2 \"%comment;<!--22-->%comment;\">\n"
|
||||
+ "%comment2;\n"
|
||||
+ "]>\n"
|
||||
+ "<r/>\n",
|
||||
+ NULL, NULL,
|
||||
+ sizeof(XML_Char)
|
||||
+ * (strlen("%comment;<!--22-->%comment;") + 2 * strlen("<!--1-->")),
|
||||
+ filled_later},
|
||||
+ {"<!DOCTYPE r [\n"
|
||||
+ " <!ENTITY % five \"12345\">\n"
|
||||
+ " <!ENTITY % five2def \"<!ENTITY five2 "[%five;][%five;]]]]">\">\n"
|
||||
+ " %five2def;\n"
|
||||
+ "]>\n"
|
||||
+ "<r>&five2;</r>",
|
||||
+ NULL, NULL, /* from "%five2def;": */
|
||||
+ sizeof(XML_Char)
|
||||
+ * (strlen("<!ENTITY five2 \"[%five;][%five;]]]]\">")
|
||||
+ + 2 /* calls to "%five;" */ * strlen("12345")
|
||||
+ + /* from "&five2;": */ strlen("[12345][12345]]]]")),
|
||||
+ filled_later},
|
||||
+ {"<!DOCTYPE r SYSTEM \"first.ent\">\n"
|
||||
+ "<r/>",
|
||||
+ "<!ENTITY % comment '<!--1-->'>\n"
|
||||
+ "<!ENTITY % comment2 '<!--22-->%comment;<!--22-->%comment;<!--22-->'>\n"
|
||||
+ "%comment2;",
|
||||
+ NULL,
|
||||
+ sizeof(XML_Char)
|
||||
+ * (strlen("<!--22-->%comment;<!--22-->%comment;<!--22-->")
|
||||
+ + 2 /* calls to "%comment;" */ * strlen("<!---->")),
|
||||
+ filled_later},
|
||||
+ {"<!DOCTYPE r SYSTEM 'first.ent'>\n"
|
||||
+ "<r/>",
|
||||
+ "<!ENTITY % e1 PUBLIC 'foo' 'second.ent'>\n"
|
||||
+ "<!ENTITY % e2 '<!--22-->%e1;<!--22-->'>\n"
|
||||
+ "%e2;\n",
|
||||
+ "<!--1-->", sizeof(XML_Char) * strlen("<!--22--><!--1--><!--22-->"),
|
||||
+ filled_later},
|
||||
+ {
|
||||
+ "<!DOCTYPE r SYSTEM 'first.ent'>\n"
|
||||
+ "<r/>",
|
||||
+ "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
|
||||
+ "<!ENTITY % e2 '%e1;'>",
|
||||
+ "<?xml version='1.0' encoding='utf-8'?>\n"
|
||||
+ "hello\n"
|
||||
+ "xml" /* without trailing newline! */,
|
||||
+ 0,
|
||||
+ filled_later,
|
||||
+ },
|
||||
+ {
|
||||
+ "<!DOCTYPE r SYSTEM 'first.ent'>\n"
|
||||
+ "<r/>",
|
||||
+ "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
|
||||
+ "<!ENTITY % e2 '%e1;'>",
|
||||
+ "<?xml version='1.0' encoding='utf-8'?>\n"
|
||||
+ "hello\n"
|
||||
+ "xml\n" /* with trailing newline! */,
|
||||
+ 0,
|
||||
+ filled_later,
|
||||
+ },
|
||||
+ {"<!DOCTYPE doc SYSTEM 'first.ent'>\n"
|
||||
+ "<doc></doc>\n",
|
||||
+ "<!ELEMENT doc EMPTY>\n"
|
||||
+ "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
|
||||
+ "<!ENTITY % e2 '%e1;'>\n"
|
||||
+ "%e1;\n",
|
||||
+ "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>" /* UTF-8 BOM */,
|
||||
+ strlen("\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>"), filled_later},
|
||||
+ {"<!DOCTYPE r [\n"
|
||||
+ " <!ENTITY five SYSTEM 'first.ent'>\n"
|
||||
+ "]>\n"
|
||||
+ "<r>&five;</r>",
|
||||
+ "\xEF\xBB\xBF" /* UTF-8 BOM */, NULL, 0, filled_later},
|
||||
+ };
|
||||
+
|
||||
+ const size_t countCases = sizeof(cases) / sizeof(cases[0]);
|
||||
+ size_t u = 0;
|
||||
+ for (; u < countCases; u++) {
|
||||
+ size_t v = 0;
|
||||
+ for (; v < 2; v++) {
|
||||
+ const XML_Bool singleBytesWanted = (v == 0) ? XML_FALSE : XML_TRUE;
|
||||
+ const unsigned long long expectedCountBytesDirect
|
||||
+ = strlen(cases[u].primaryText);
|
||||
+ const unsigned long long expectedCountBytesIndirect
|
||||
+ = (cases[u].firstExternalText ? strlen(cases[u].firstExternalText)
|
||||
+ : 0)
|
||||
+ + (cases[u].secondExternalText ? strlen(cases[u].secondExternalText)
|
||||
+ : 0)
|
||||
+ + cases[u].expectedCountBytesIndirectExtra;
|
||||
+
|
||||
+ XML_Parser parser = XML_ParserCreate(NULL);
|
||||
+ XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
|
||||
+ if (cases[u].firstExternalText) {
|
||||
+ XML_SetExternalEntityRefHandler(parser,
|
||||
+ accounting_external_entity_ref_handler);
|
||||
+ XML_SetUserData(parser, (void *)&cases[u]);
|
||||
+ cases[u].singleBytesWanted = singleBytesWanted;
|
||||
+ }
|
||||
+
|
||||
+ const XmlParseFunction xmlParseFunction
|
||||
+ = singleBytesWanted ? _XML_Parse_SINGLE_BYTES : XML_Parse;
|
||||
+
|
||||
+ enum XML_Status status
|
||||
+ = xmlParseFunction(parser, cases[u].primaryText,
|
||||
+ (int)strlen(cases[u].primaryText), XML_TRUE);
|
||||
+ if (status != XML_STATUS_OK) {
|
||||
+ _xml_failure(parser, __FILE__, __LINE__);
|
||||
+ }
|
||||
+
|
||||
+ const unsigned long long actualCountBytesDirect
|
||||
+ = testingAccountingGetCountBytesDirect(parser);
|
||||
+ const unsigned long long actualCountBytesIndirect
|
||||
+ = testingAccountingGetCountBytesIndirect(parser);
|
||||
+
|
||||
+ XML_ParserFree(parser);
|
||||
+
|
||||
+ if (actualCountBytesDirect != expectedCountBytesDirect) {
|
||||
+ fprintf(
|
||||
+ stderr,
|
||||
+ "Document " EXPAT_FMT_SIZE_T("") " of " EXPAT_FMT_SIZE_T("") ", %s: Expected " EXPAT_FMT_ULL(
|
||||
+ "") " count direct bytes, got " EXPAT_FMT_ULL("") " instead.\n",
|
||||
+ u + 1, countCases, singleBytesWanted ? "single bytes" : "chunks",
|
||||
+ expectedCountBytesDirect, actualCountBytesDirect);
|
||||
+ fail("Count of direct bytes is off");
|
||||
+ }
|
||||
+
|
||||
+ if (actualCountBytesIndirect != expectedCountBytesIndirect) {
|
||||
+ fprintf(
|
||||
+ stderr,
|
||||
+ "Document " EXPAT_FMT_SIZE_T("") " of " EXPAT_FMT_SIZE_T("") ", %s: Expected " EXPAT_FMT_ULL(
|
||||
+ "") " count indirect bytes, got " EXPAT_FMT_ULL("") " instead.\n",
|
||||
+ u + 1, countCases, singleBytesWanted ? "single bytes" : "chunks",
|
||||
+ expectedCountBytesIndirect, actualCountBytesIndirect);
|
||||
+ fail("Count of indirect bytes is off");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+END_TEST
|
||||
+#endif // defined(XML_DTD)
|
||||
+
|
||||
static Suite *
|
||||
make_suite(void) {
|
||||
Suite *s = suite_create("basic");
|
||||
@@ -11233,6 +11523,9 @@ make_suite(void) {
|
||||
TCase *tc_misc = tcase_create("miscellaneous tests");
|
||||
TCase *tc_alloc = tcase_create("allocation tests");
|
||||
TCase *tc_nsalloc = tcase_create("namespace allocation tests");
|
||||
+#if defined(XML_DTD)
|
||||
+ TCase *tc_accounting = tcase_create("accounting tests");
|
||||
+#endif
|
||||
|
||||
suite_add_tcase(s, tc_basic);
|
||||
tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
|
||||
@@ -11593,6 +11886,11 @@ make_suite(void) {
|
||||
tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
|
||||
tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
|
||||
|
||||
+#if defined(XML_DTD)
|
||||
+ suite_add_tcase(s, tc_accounting);
|
||||
+ tcase_add_test(tc_accounting, test_accounting_precision);
|
||||
+#endif
|
||||
+
|
||||
return s;
|
||||
}
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,103 @@
|
||||
From e9d8f115580c3a25a9579c213f096af623dd92ce Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Mon, 26 Apr 2021 14:52:45 +0200
|
||||
Subject: [PATCH] tests: Cover billion laughs attack protection API
|
||||
|
||||
---
|
||||
tests/runtests.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 66 insertions(+)
|
||||
|
||||
diff --git a/tests/runtests.c b/tests/runtests.c
|
||||
index 100574a..d4e05a7 100644
|
||||
--- a/tests/runtests.c
|
||||
+++ b/tests/runtests.c
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <stddef.h> /* ptrdiff_t */
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
+#include <math.h> /* NAN, INFINITY, isnan */
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||
/* For vs2003/7.1 up to vs2008/9.0; _MSC_VER 1600 is vs2010/10.0 */
|
||||
@@ -11485,6 +11486,70 @@ START_TEST(test_accounting_precision) {
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
+
|
||||
+START_TEST(test_billion_laughs_attack_protection_api) {
|
||||
+ XML_Parser parserWithoutParent = XML_ParserCreate(NULL);
|
||||
+ XML_Parser parserWithParent
|
||||
+ = XML_ExternalEntityParserCreate(parserWithoutParent, NULL, NULL);
|
||||
+ if (parserWithoutParent == NULL)
|
||||
+ fail("parserWithoutParent is NULL");
|
||||
+ if (parserWithParent == NULL)
|
||||
+ fail("parserWithParent is NULL");
|
||||
+
|
||||
+ // XML_SetBillionLaughsAttackProtectionMaximumAmplification, error cases
|
||||
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(NULL, 123.0f)
|
||||
+ == XML_TRUE)
|
||||
+ fail("Call with NULL parser is NOT supposed to succeed");
|
||||
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(parserWithParent,
|
||||
+ 123.0f)
|
||||
+ == XML_TRUE)
|
||||
+ fail("Call with non-root parser is NOT supposed to succeed");
|
||||
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
|
||||
+ parserWithoutParent, NAN)
|
||||
+ == XML_TRUE)
|
||||
+ fail("Call with NaN limit is NOT supposed to succeed");
|
||||
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
|
||||
+ parserWithoutParent, -1.0f)
|
||||
+ == XML_TRUE)
|
||||
+ fail("Call with negative limit is NOT supposed to succeed");
|
||||
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
|
||||
+ parserWithoutParent, 0.9f)
|
||||
+ == XML_TRUE)
|
||||
+ fail("Call with positive limit <1.0 is NOT supposed to succeed");
|
||||
+
|
||||
+ // XML_SetBillionLaughsAttackProtectionMaximumAmplification, success cases
|
||||
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
|
||||
+ parserWithoutParent, 1.0f)
|
||||
+ == XML_FALSE)
|
||||
+ fail("Call with positive limit >=1.0 is supposed to succeed");
|
||||
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
|
||||
+ parserWithoutParent, 123456.789f)
|
||||
+ == XML_FALSE)
|
||||
+ fail("Call with positive limit >=1.0 is supposed to succeed");
|
||||
+ if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
|
||||
+ parserWithoutParent, INFINITY)
|
||||
+ == XML_FALSE)
|
||||
+ fail("Call with positive limit >=1.0 is supposed to succeed");
|
||||
+
|
||||
+ // XML_SetBillionLaughsAttackProtectionActivationThreshold, error cases
|
||||
+ if (XML_SetBillionLaughsAttackProtectionActivationThreshold(NULL, 123)
|
||||
+ == XML_TRUE)
|
||||
+ fail("Call with NULL parser is NOT supposed to succeed");
|
||||
+ if (XML_SetBillionLaughsAttackProtectionActivationThreshold(parserWithParent,
|
||||
+ 123)
|
||||
+ == XML_TRUE)
|
||||
+ fail("Call with non-root parser is NOT supposed to succeed");
|
||||
+
|
||||
+ // XML_SetBillionLaughsAttackProtectionActivationThreshold, success cases
|
||||
+ if (XML_SetBillionLaughsAttackProtectionActivationThreshold(
|
||||
+ parserWithoutParent, 123)
|
||||
+ == XML_FALSE)
|
||||
+ fail("Call with non-NULL parentless parser is supposed to succeed");
|
||||
+
|
||||
+ XML_ParserFree(parserWithParent);
|
||||
+ XML_ParserFree(parserWithoutParent);
|
||||
+}
|
||||
+END_TEST
|
||||
#endif // defined(XML_DTD)
|
||||
|
||||
static Suite *
|
||||
@@ -11859,6 +11924,7 @@ make_suite(void) {
|
||||
#if defined(XML_DTD)
|
||||
suite_add_tcase(s, tc_accounting);
|
||||
tcase_add_test(tc_accounting, test_accounting_precision);
|
||||
+ tcase_add_test(tc_accounting, test_billion_laughs_attack_protection_api);
|
||||
#endif
|
||||
|
||||
return s;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
From 5dbc857f47ecd6c37748ce279c6535fbbf526590 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Mon, 26 Apr 2021 15:12:53 +0200
|
||||
Subject: [PATCH] tests: Cover helper unsignedCharToPrintable
|
||||
|
||||
---
|
||||
lib/internal.h | 1 +
|
||||
lib/xmlparse.c | 3 +--
|
||||
tests/runtests.c | 20 ++++++++++++++++++++
|
||||
3 files changed, 22 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/internal.h b/lib/internal.h
|
||||
index 377c12b..444eba0 100644
|
||||
--- a/lib/internal.h
|
||||
+++ b/lib/internal.h
|
||||
@@ -155,6 +155,7 @@ void _INTERNAL_trim_to_complete_utf8_characters(const char *from,
|
||||
#if defined(XML_DTD)
|
||||
unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser);
|
||||
unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
|
||||
+const char *unsignedCharToPrintable(unsigned char c);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index adaab23..a1aadd8 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -580,7 +580,6 @@ static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
|
||||
|
||||
static XML_Parser getRootParserOf(XML_Parser parser,
|
||||
unsigned int *outLevelDiff);
|
||||
-static const char *unsignedCharToPrintable(unsigned char c);
|
||||
#endif /* XML_DTD */
|
||||
|
||||
static unsigned long getDebugLevel(const char *variableName,
|
||||
@@ -7433,7 +7432,7 @@ getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
|
||||
return rootParser;
|
||||
}
|
||||
|
||||
-static const char *
|
||||
+const char *
|
||||
unsignedCharToPrintable(unsigned char c) {
|
||||
switch (c) {
|
||||
case 0:
|
||||
diff --git a/tests/runtests.c b/tests/runtests.c
|
||||
index 8c5ad72..0e2b49f 100644
|
||||
--- a/tests/runtests.c
|
||||
+++ b/tests/runtests.c
|
||||
@@ -11578,6 +11578,25 @@ START_TEST(test_billion_laughs_attack_protection_api) {
|
||||
XML_ParserFree(parserWithoutParent);
|
||||
}
|
||||
END_TEST
|
||||
+
|
||||
+START_TEST(test_helper_unsigned_char_to_printable) {
|
||||
+ // Smoke test
|
||||
+ unsigned char uc = 0;
|
||||
+ for (; uc < (unsigned char)-1; uc++) {
|
||||
+ const char *const printable = unsignedCharToPrintable(uc);
|
||||
+ if (printable == NULL)
|
||||
+ fail("unsignedCharToPrintable returned NULL");
|
||||
+ if (strlen(printable) < (size_t)1)
|
||||
+ fail("unsignedCharToPrintable returned empty string");
|
||||
+ }
|
||||
+
|
||||
+ // Two concrete samples
|
||||
+ if (strcmp(unsignedCharToPrintable('A'), "A") != 0)
|
||||
+ fail("unsignedCharToPrintable result mistaken");
|
||||
+ if (strcmp(unsignedCharToPrintable('\\'), "\\\\") != 0)
|
||||
+ fail("unsignedCharToPrintable result mistaken");
|
||||
+}
|
||||
+END_TEST
|
||||
#endif // defined(XML_DTD)
|
||||
|
||||
static Suite *
|
||||
@@ -11955,6 +11974,7 @@ make_suite(void) {
|
||||
suite_add_tcase(s, tc_accounting);
|
||||
tcase_add_test(tc_accounting, test_accounting_precision);
|
||||
tcase_add_test(tc_accounting, test_billion_laughs_attack_protection_api);
|
||||
+ tcase_add_test(tc_accounting, test_helper_unsigned_char_to_printable);
|
||||
#endif
|
||||
|
||||
return s;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,161 @@
|
||||
From c6223b3b0f3d8e6a37b5775b44eeded02e9c3ea7 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Sat, 17 Apr 2021 17:26:17 +0200
|
||||
Subject: [PATCH] xmlwf: Add support for custom attack protection parameters
|
||||
|
||||
---
|
||||
xmlwf/xmltchar.h | 5 +++-
|
||||
xmlwf/xmlwf.c | 69 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
xmlwf/xmlwf_helpgen.py | 8 +++++
|
||||
3 files changed, 82 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/xmlwf/xmltchar.h b/xmlwf/xmltchar.h
|
||||
index 4843fbe..30283d0 100644
|
||||
--- a/xmlwf/xmltchar.h
|
||||
+++ b/xmlwf/xmltchar.h
|
||||
@@ -55,6 +55,8 @@
|
||||
# define tmain wmain
|
||||
# define tremove _wremove
|
||||
# define tchar wchar_t
|
||||
+# define tcstof wcstof
|
||||
+# define tcstoull wcstoull
|
||||
#else /* not XML_UNICODE */
|
||||
# define T(x) x
|
||||
# define ftprintf fprintf
|
||||
@@ -72,4 +74,6 @@
|
||||
# define tmain main
|
||||
# define tremove remove
|
||||
# define tchar char
|
||||
+# define tcstof strtof
|
||||
+# define tcstoull strtoull
|
||||
#endif /* not XML_UNICODE */
|
||||
diff --git a/xmlwf/xmlwf.c b/xmlwf/xmlwf.c
|
||||
index 2b86966..342d6c5 100644
|
||||
--- a/xmlwf/xmlwf.c
|
||||
+++ b/xmlwf/xmlwf.c
|
||||
@@ -46,6 +46,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
+#include <math.h> /* for isnan */
|
||||
+#include <errno.h>
|
||||
|
||||
#include "expat.h"
|
||||
#include "codepage.h"
|
||||
@@ -905,6 +907,12 @@ usage(const XML_Char *prog, int rc) {
|
||||
T(" -t write no XML output for [t]iming of plain parsing\n")
|
||||
T(" -N enable adding doctype and [n]otation declarations\n")
|
||||
T("\n")
|
||||
+ T("billion laughs attack protection:\n")
|
||||
+ T(" NOTE: If you ever need to increase these values for non-attack payload, please file a bug report.\n")
|
||||
+ T("\n")
|
||||
+ T(" -a FACTOR set maximum tolerated [a]mplification factor (default: 100.0)\n")
|
||||
+ T(" -b BYTES set number of output [b]ytes needed to activate (default: 8 MiB)\n")
|
||||
+ T("\n")
|
||||
T("info arguments:\n")
|
||||
T(" -h show this [h]elp message and exit\n")
|
||||
T(" -v show program's [v]ersion number and exit\n")
|
||||
@@ -953,6 +961,11 @@ tmain(int argc, XML_Char **argv) {
|
||||
int useNamespaces = 0;
|
||||
int requireStandalone = 0;
|
||||
int requiresNotations = 0;
|
||||
+
|
||||
+ float attackMaximumAmplification = -1.0f; /* signaling "not set" */
|
||||
+ unsigned long long attackThresholdBytes;
|
||||
+ XML_Bool attackThresholdGiven = XML_FALSE;
|
||||
+
|
||||
enum XML_ParamEntityParsing paramEntityParsing
|
||||
= XML_PARAM_ENTITY_PARSING_NEVER;
|
||||
int useStdin = 0;
|
||||
@@ -1032,6 +1045,49 @@ tmain(int argc, XML_Char **argv) {
|
||||
case T('v'):
|
||||
showVersion(argv[0]);
|
||||
return 0;
|
||||
+ case T('a'): {
|
||||
+ const XML_Char *valueText = NULL;
|
||||
+ XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
|
||||
+
|
||||
+ errno = 0;
|
||||
+ XML_Char *afterValueText = (XML_Char *)valueText;
|
||||
+ attackMaximumAmplification = tcstof(valueText, &afterValueText);
|
||||
+ if ((errno != 0) || (afterValueText[0] != T('\0'))
|
||||
+ || isnan(attackMaximumAmplification)
|
||||
+ || (attackMaximumAmplification < 1.0f)) {
|
||||
+ // This prevents tperror(..) from reporting misleading "[..]: Success"
|
||||
+ errno = ERANGE;
|
||||
+ tperror(T("invalid amplification limit") T(
|
||||
+ " (needs a floating point number greater or equal than 1.0)"));
|
||||
+ exit(2);
|
||||
+ }
|
||||
+#ifndef XML_DTD
|
||||
+ ftprintf(stderr, T("Warning: Given amplification limit ignored") T(
|
||||
+ ", xmlwf has been compiled without DTD support.\n"));
|
||||
+#endif
|
||||
+ break;
|
||||
+ }
|
||||
+ case T('b'): {
|
||||
+ const XML_Char *valueText = NULL;
|
||||
+ XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
|
||||
+
|
||||
+ errno = 0;
|
||||
+ XML_Char *afterValueText = (XML_Char *)valueText;
|
||||
+ attackThresholdBytes = tcstoull(valueText, &afterValueText, 10);
|
||||
+ if ((errno != 0) || (afterValueText[0] != T('\0'))) {
|
||||
+ // This prevents tperror(..) from reporting misleading "[..]: Success"
|
||||
+ errno = ERANGE;
|
||||
+ tperror(T("invalid ignore threshold")
|
||||
+ T(" (needs an integer from 0 to 2^64-1)"));
|
||||
+ exit(2);
|
||||
+ }
|
||||
+ attackThresholdGiven = XML_TRUE;
|
||||
+#ifndef XML_DTD
|
||||
+ ftprintf(stderr, T("Warning: Given attack threshold ignored") T(
|
||||
+ ", xmlwf has been compiled without DTD support.\n"));
|
||||
+#endif
|
||||
+ break;
|
||||
+ }
|
||||
case T('\0'):
|
||||
if (j > 1) {
|
||||
i++;
|
||||
@@ -1062,6 +1118,19 @@ tmain(int argc, XML_Char **argv) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+ if (attackMaximumAmplification != -1.0f) {
|
||||
+#ifdef XML_DTD
|
||||
+ XML_SetBillionLaughsAttackProtectionMaximumAmplification(
|
||||
+ parser, attackMaximumAmplification);
|
||||
+#endif
|
||||
+ }
|
||||
+ if (attackThresholdGiven) {
|
||||
+#ifdef XML_DTD
|
||||
+ XML_SetBillionLaughsAttackProtectionActivationThreshold(
|
||||
+ parser, attackThresholdBytes);
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
if (requireStandalone)
|
||||
XML_SetNotStandaloneHandler(parser, notStandalone);
|
||||
XML_SetParamEntityParsing(parser, paramEntityParsing);
|
||||
diff --git a/xmlwf/xmlwf_helpgen.py b/xmlwf/xmlwf_helpgen.py
|
||||
index 8ec8d4e..c2a527f 100755
|
||||
--- a/xmlwf/xmlwf_helpgen.py
|
||||
+++ b/xmlwf/xmlwf_helpgen.py
|
||||
@@ -73,6 +73,14 @@ output_mode.add_argument('-m', action='store_true', help='write [m]eta XML, not
|
||||
output_mode.add_argument('-t', action='store_true', help='write no XML output for [t]iming of plain parsing')
|
||||
output_related.add_argument('-N', action='store_true', help='enable adding doctype and [n]otation declarations')
|
||||
|
||||
+billion_laughs = parser.add_argument_group('billion laughs attack protection',
|
||||
+ description='NOTE: '
|
||||
+ 'If you ever need to increase these values '
|
||||
+ 'for non-attack payload, please file a bug report.')
|
||||
+billion_laughs.add_argument('-a', metavar='FACTOR',
|
||||
+ help='set maximum tolerated [a]mplification factor (default: 100.0)')
|
||||
+billion_laughs.add_argument('-b', metavar='BYTES', help='set number of output [b]ytes needed to activate (default: 8 MiB)')
|
||||
+
|
||||
parser.add_argument('files', metavar='FILE', nargs='*', help='files to process (default: STDIN)')
|
||||
|
||||
info = parser.add_argument_group('info arguments')
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
From 65cddaa4e93263fb88261b60f97cf29f1589d038 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Sun, 18 Apr 2021 20:17:43 +0200
|
||||
Subject: [PATCH] xmlwf: Include expat_config.h so we can check for macro
|
||||
XML_DTD
|
||||
|
||||
---
|
||||
xmlwf/xmlwf.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/xmlwf/xmlwf.c b/xmlwf/xmlwf.c
|
||||
index 4242e1c..2b86966 100644
|
||||
--- a/xmlwf/xmlwf.c
|
||||
+++ b/xmlwf/xmlwf.c
|
||||
@@ -39,6 +39,8 @@
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
+#include <expat_config.h>
|
||||
+
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,84 @@
|
||||
From bf878495985b81731c620bbac26df79e6c98c9fd Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Sun, 25 Apr 2021 18:16:14 +0200
|
||||
Subject: [PATCH] xmlwf.1: Document arguments -a and -b
|
||||
|
||||
---
|
||||
doc/xmlwf.xml | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 46 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/doc/xmlwf.xml b/doc/xmlwf.xml
|
||||
index 5e2a4ae..648b581 100644
|
||||
--- a/doc/xmlwf.xml
|
||||
+++ b/doc/xmlwf.xml
|
||||
@@ -3,7 +3,7 @@
|
||||
<!ENTITY dhfirstname "<firstname>Scott</firstname>">
|
||||
<!ENTITY dhsurname "<surname>Bronson</surname>">
|
||||
<!-- Please adjust the date whenever revising the manpage. -->
|
||||
- <!ENTITY dhdate "<date>March 11, 2016</date>">
|
||||
+ <!ENTITY dhdate "<date>May 4, 2021</date>">
|
||||
<!-- SECTION should be 1-8, maybe w/ subsection other parameters are
|
||||
allowed: see man(7), man(1). -->
|
||||
<!ENTITY dhsection "<manvolnum>1</manvolnum>">
|
||||
@@ -140,6 +140,50 @@ supports both.
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
+ <term><option>-a</option> <replaceable>factor</replaceable></term>
|
||||
+ <listitem>
|
||||
+ <para>
|
||||
+ Sets the maximum tolerated amplification factor
|
||||
+ for protection against billion laughs attacks (default: 100.0).
|
||||
+ The amplification factor is calculated as ..
|
||||
+ </para>
|
||||
+ <literallayout>
|
||||
+ amplification := (direct + indirect) / direct
|
||||
+ </literallayout>
|
||||
+ <para>
|
||||
+ .. while parsing, whereas
|
||||
+ <direct> is the number of bytes read
|
||||
+ from the primary document in parsing and
|
||||
+ <indirect> is the number of bytes
|
||||
+ added by expanding entities and reading of external DTD files,
|
||||
+ combined.
|
||||
+ </para>
|
||||
+ <para>
|
||||
+ <emphasis>NOTE</emphasis>:
|
||||
+ If you ever need to increase this value for non-attack payload,
|
||||
+ please file a bug report.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
+ <varlistentry>
|
||||
+ <term><option>-b</option> <replaceable>bytes</replaceable></term>
|
||||
+ <listitem>
|
||||
+ <para>
|
||||
+ Sets the number of output bytes (including amplification)
|
||||
+ needed to activate protection against billion laughs attacks
|
||||
+ (default: 8 MiB).
|
||||
+ This can be thought of as an "activation threshold".
|
||||
+ </para>
|
||||
+ <para>
|
||||
+ <emphasis>NOTE</emphasis>:
|
||||
+ If you ever need to increase this value for non-attack payload,
|
||||
+ please file a bug report.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
+ <varlistentry>
|
||||
<term><option>-c</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -434,6 +478,7 @@ http://www.xml.com/pub/a/tools/ruwf/check.html
|
||||
<literallayout>
|
||||
The Expat home page: http://www.libexpat.org/
|
||||
The W3 XML specification: http://www.w3.org/TR/REC-xml
|
||||
+Billion laughs attack: https://en.wikipedia.org/wiki/Billion_laughs_attack
|
||||
</literallayout>
|
||||
|
||||
</para>
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
From 13bb381d296ef8da09a3f00f5b23724b5deb6a38 Mon Sep 17 00:00:00 2001w
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Wed, 27 May 2020 20:28:06 +0200
|
||||
Subject: [PATCH] xmlparse.c: Fix reading uninitialized variable (#404)
|
||||
|
||||
---
|
||||
Changes | 3 +++
|
||||
lib/xmlparse.c | 4 ++--
|
||||
2 files changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/Changes b/Changes
|
||||
index a642bf6..72c1f13 100644
|
||||
--- a/Changes
|
||||
+++ b/Changes
|
||||
@@ -18,6 +18,7 @@ Release 2.2.9 Wed Septemper 25 2019
|
||||
Bug fixes:
|
||||
#390 #395 Fix undefined behavior during parsing when compiled with
|
||||
-DXML_UNICODE that was introduced with Expat 2.0.1
|
||||
+ #404 Fix reading uninitialized variable during parsing
|
||||
|
||||
New features:
|
||||
#34 #466 #484 Add two new API functions to further tighten billion laughs
|
||||
@@ -55,6 +56,8 @@ Release 2.2.9 Wed Septemper 25 2019
|
||||
Clang LeakSan
|
||||
JetBrains
|
||||
OSS-Fuzz
|
||||
+ and
|
||||
+ Cppcheck 2.0 and the Cppcheck team
|
||||
|
||||
Release 2.2.8 Fri Septemper 13 2019
|
||||
Security fixes:
|
||||
diff --git a/lib/xmlparse.c b/lib/xmlparse.c
|
||||
index f2ad416..03da172 100644
|
||||
--- a/lib/xmlparse.c
|
||||
+++ b/lib/xmlparse.c
|
||||
@@ -3732,7 +3732,7 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
||||
*startPtr = NULL;
|
||||
|
||||
for (;;) {
|
||||
- const char *next;
|
||||
+ const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
|
||||
int tok = XmlCdataSectionTok(enc, s, end, &next);
|
||||
#ifdef XML_DTD
|
||||
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
|
||||
@@ -3858,7 +3858,7 @@ ignoreSectionProcessor(XML_Parser parser, const char *start, const char *end,
|
||||
static enum XML_Error
|
||||
doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
||||
const char *end, const char **nextPtr, XML_Bool haveMore) {
|
||||
- const char *next;
|
||||
+ const char *next = *startPtr; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
|
||||
int tok;
|
||||
const char *s = *startPtr;
|
||||
const char **eventPP;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
63
backport-xmlwf-Extract-macro-XMLWF_SHIFT_ARGUMENT.patch
Normal file
63
backport-xmlwf-Extract-macro-XMLWF_SHIFT_ARGUMENT.patch
Normal file
@ -0,0 +1,63 @@
|
||||
From 385aeb477bac9538ab2b3d5cf0e76e8c751374be Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Pipping <sebastian@pipping.org>
|
||||
Date: Sat, 17 Apr 2021 18:35:51 +0200
|
||||
Subject: [PATCH] xmlwf: Extract macro XMLWF_SHIFT_ARGUMENT
|
||||
|
||||
---
|
||||
xmlwf/xmlwf.c | 31 +++++++++++++++----------------
|
||||
1 file changed, 15 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/xmlwf/xmlwf.c b/xmlwf/xmlwf.c
|
||||
index 493b697..fc83f73 100644
|
||||
--- a/xmlwf/xmlwf.c
|
||||
+++ b/xmlwf/xmlwf.c
|
||||
@@ -908,6 +908,19 @@ usage(const XML_Char *prog, int rc) {
|
||||
int wmain(int argc, XML_Char **argv);
|
||||
#endif
|
||||
|
||||
+#define XMLWF_SHIFT_ARG_INTO(constCharStarTarget, argc, argv, i, j) \
|
||||
+ { \
|
||||
+ if (argv[i][j + 1] == T('\0')) { \
|
||||
+ if (++i == argc) \
|
||||
+ usage(argv[0], 2); \
|
||||
+ constCharStarTarget = argv[i]; \
|
||||
+ } else { \
|
||||
+ constCharStarTarget = argv[i] + j + 1; \
|
||||
+ } \
|
||||
+ i++; \
|
||||
+ j = 0; \
|
||||
+ }
|
||||
+
|
||||
int
|
||||
tmain(int argc, XML_Char **argv) {
|
||||
int i, j;
|
||||
@@ -984,24 +997,10 @@ tmain(int argc, XML_Char **argv) {
|
||||
j++;
|
||||
break;
|
||||
case T('d'):
|
||||
- if (argv[i][j + 1] == T('\0')) {
|
||||
- if (++i == argc)
|
||||
- usage(argv[0], 2);
|
||||
- outputDir = argv[i];
|
||||
- } else
|
||||
- outputDir = argv[i] + j + 1;
|
||||
- i++;
|
||||
- j = 0;
|
||||
+ XMLWF_SHIFT_ARG_INTO(outputDir, argc, argv, i, j);
|
||||
break;
|
||||
case T('e'):
|
||||
- if (argv[i][j + 1] == T('\0')) {
|
||||
- if (++i == argc)
|
||||
- usage(argv[0], 2);
|
||||
- encoding = argv[i];
|
||||
- } else
|
||||
- encoding = argv[i] + j + 1;
|
||||
- i++;
|
||||
- j = 0;
|
||||
+ XMLWF_SHIFT_ARG_INTO(encoding, argc, argv, i, j);
|
||||
break;
|
||||
case T('h'):
|
||||
usage(argv[0], 0);
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
30
expat.spec
30
expat.spec
@ -1,14 +1,34 @@
|
||||
%define Rversion %(echo %{version} | sed -e 's/\\./_/g' -e 's/^/R_/')
|
||||
Name: expat
|
||||
Version: 2.2.9
|
||||
Release: 2
|
||||
Release: 3
|
||||
Summary: An XML parser library
|
||||
License: MIT
|
||||
URL: https://libexpat.github.io/
|
||||
Source0: https://github.com/libexpat/libexpat/releases/download/%{Rversion}/expat-%{version}.tar.gz
|
||||
|
||||
Patch0000: xmlparse.c-Fix-undefined-behavior-for-XML_UNICODE.patch
|
||||
Patch0001: Don-t-add-to-NULL-in-iterator.patch
|
||||
Patch0: xmlparse.c-Fix-undefined-behavior-for-XML_UNICODE.patch
|
||||
Patch1: Don-t-add-to-NULL-in-iterator.patch
|
||||
|
||||
Patch2: backport-Autotools-Give-test-suite-access-to-internal-symbols.patch
|
||||
Patch3: backport-xmlwf-Extract-macro-XMLWF_SHIFT_ARGUMENT.patch
|
||||
Patch4: backport-CVE-2013-0340-lib-Add-prefix-expat-to-EXPAT_ENTROPY_DEBUG-1-stderr.patch
|
||||
Patch5: backport-CVE-2013-0340-xmlwf-Add-support-for-custom-attack-protection-param.patch
|
||||
Patch6: backport-CVE-2013-0340-xmlwf-Include-expat_config.h-so-we-can-check-for-mac.patch
|
||||
Patch7: backport-CVE-2013-0340-Changes-Document-protection-against-billion-laughs-a.patch
|
||||
Patch8: backport-CVE-2013-0340-lib-Protect-against-billion-laughs-attacks-approach-.patch
|
||||
Patch9: backport-CVE-2013-0340-lib-Make-EXPAT_ENTROPY_DEBUG-consistent-with-other-E.patch
|
||||
Patch10: backport-CVE-2013-0340-lib-Allow-test-suite-to-access-raw-accounting-values.patch
|
||||
Patch11: backport-CVE-2013-0340-Autotools-CMake-Suppress-Wpedantic-ms-format-false-p.patch
|
||||
Patch12: backport-CVE-2013-0340-lib-Address-Cppcheck-2.4.1-warning-uninitvar.patch
|
||||
Patch13: backport-CVE-2013-0340-tests-Cover-accounting.patch
|
||||
Patch14: backport-CVE-2013-0340-xmlwf.1-Document-arguments-a-and-b.patch
|
||||
Patch15: backport-CVE-2013-0340-doc-reference.html-Document-billion-laughs-attack-pr.patch
|
||||
Patch16: backport-CVE-2013-0340-tests-Cover-billion-laughs-attack-protection-API.patch
|
||||
Patch17: backport-CVE-2013-0340-tests-Cover-helper-unsignedCharToPrintable.patch
|
||||
Patch18: backport-CVE-2013-0340-tests-Cover-accounting-of-CDATA-sections.patch
|
||||
Patch19: backport-CVE-2013-0340-lib-Fix-accounting-of-CDATA-sections-inside.patch
|
||||
Patch20: backport-xmlparse.c-Fix-reading-uninitialized-variable-404.patch
|
||||
|
||||
BuildRequires: sed,autoconf,automake,gcc-c++,libtool,xmlto
|
||||
|
||||
@ -61,6 +81,10 @@ make check
|
||||
%{_mandir}/man1/*
|
||||
|
||||
%changelog
|
||||
* Fri Jul 2 2021 panxiaohe <panxiaohe@huawei.com> - 2.2.9-3
|
||||
- fix CVE-2013-0340
|
||||
- xmlparse.c: Fix reading uninitialized variable
|
||||
|
||||
* Sun Jun 28 2020 liuchenguang <liuchenguang4@huawei.com> - 2.2.9-2
|
||||
- quality enhancement synchronization github patch
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user