All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
       [not found] <168917379DAE252D.8130@lists.openembedded.org>
@ 2021-06-16 14:48 ` Jasper Orschulko
  2021-06-16 15:09   ` Steve Sakoman
  2021-06-16 18:19 ` Jasper Orschulko
       [not found] ` <168922F3778E5D40.4659@lists.openembedded.org>
  2 siblings, 1 reply; 11+ messages in thread
From: Jasper Orschulko @ 2021-06-16 14:48 UTC (permalink / raw)
  To: openembedded-core

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

P.S.: I am not too familiar with expat, this particular CVE, not with
the practise of backporting security patches, so someone(TM) should
definitely take a closer look at this first.

- -- 
With best regards

Jasper Orschulko
DevOps Engineer

Tel. +49 30 58 58 14 265
Fax +49 30 58 58 14 999
Jasper.Orschulko@iris-sensing.com

• • • • • • • • • • • • • • • • • • • • • • • • • •

iris-GmbH
infrared & intelligent sensors
Ostendstraße 1-14 | 12459 Berlin

https://iris-sensing.com/




On Wed, 2021-06-16 at 14:44 +0000, Jasper Orschulko wrote:
> expat < 4.0 is vulnerable to billion laughs attacks (see
> [https://github.com/libexpat/libexpat/issues/34]). This patch
> backports
> the commits b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> and 60959f2b491876199879d97c8ed956eabb0c2e73 from upstream.
> 
> Additionally, the SRC_URI had to be adjusted due to renaming of the
> source archive
> 
> Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
> ---
>  ...expat-Backport-fix-for-CVE-2013-0340.patch | 1758
> +++++++++++++++++
>  meta/recipes-core/expat/expat_2.2.9.bb        |    3 +-
>  2 files changed, 1760 insertions(+), 1 deletion(-)
>  create mode 100644 meta/recipes-core/expat/expat/0001-expat-
> Backport-
> fix-for-CVE-2013-0340.patch
> 
> diff --git a/meta/recipes-core/expat/expat/0001-expat-Backport-fix-
> for-
> CVE-2013-0340.patch b/meta/recipes-core/expat/expat/0001-expat-
> Backport-fix-for-CVE-2013-0340.patch
> new file mode 100644
> index 0000000000..b2ca066d96
> --- /dev/null
> +++ b/meta/recipes-core/expat/expat/0001-expat-Backport-fix-for-CVE-
> 2013-0340.patch
> @@ -0,0 +1,1758 @@
> +From 6f68eb0439f3c1807a143ff8c8972e74d404d8f0 Mon Sep 17 00:00:00
> 2001
> +From: Sebastian Pipping <sebastian@pipping.org>
> +Date: Mon, 19 Apr 2021 21:42:51 +0200
> +Subject: [PATCH] expat: Backport fix for CVE-2013-0340
> +
> +Issue: https://github.com/libexpat/libexpat/issues/34
> +
> +This patch cherry-picks the following commits from upstream release
> +2.4.0 onto 2.2.9:
> +
> +- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> +- 60959f2b491876199879d97c8ed956eabb0c2e73
> +
> +Upstream-Status: Backport
> +CVE: CVE-2013-0340
> +Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
> +---
> + expat/lib/expat.h       |   21 +-
> + expat/lib/internal.h    |   30 +
> + expat/lib/libexpat.def  |    3 +
> + expat/lib/libexpatw.def |    3 +
> + expat/lib/xmlparse.c    | 1147
> +++++++++++++++++++++++++++++++++++++-
> -
> + 5 files changed, 1143 insertions(+), 61 deletions(-)
> +
> +diff --git a/expat/lib/expat.h b/expat/lib/expat.h
> +index 48a6e2a3..796086c2 100644
> +--- a/expat/lib/expat.h
> ++++ b/expat/lib/expat.h
> +@@ -115,7 +115,9 @@ enum XML_Error {
> +   XML_ERROR_RESERVED_PREFIX_XMLNS,
> +   XML_ERROR_RESERVED_NAMESPACE_URI,
> +   /* Added in 2.2.1. */
> +-  XML_ERROR_INVALID_ARGUMENT
> ++  XML_ERROR_INVALID_ARGUMENT,
> ++  /* Backported from 2.4.0. */
> ++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
> + };
> + 
> + enum XML_Content_Type {
> +@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
> +   XML_FEATURE_SIZEOF_XML_LCHAR,
> +   XML_FEATURE_NS,
> +   XML_FEATURE_LARGE_SIZE,
> +-  XML_FEATURE_ATTR_INFO
> ++  XML_FEATURE_ATTR_INFO,
> ++  /* Added in Expat 2.4.0. */
> ++ 
> XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DE
> FA
> ULT,
> ++ 
> XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEF
> AU
> LT
> +   /* Additional features must be added to the end of this enum. */
> + };
> + 
> +@@ -1010,6 +1015,18 @@ typedef struct {
> + XMLPARSEAPI(const XML_Feature *)
> + XML_GetFeatureList(void);
> + 
> ++#ifdef XML_DTD
> ++/* Backported from Expat 2.4.0. */
> ++XMLPARSEAPI(XML_Bool)
> ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> ++    XML_Parser parser, float maximumAmplificationFactor);
> ++
> ++/* Backported from Expat 2.4.0. */
> ++XMLPARSEAPI(XML_Bool)
> ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> ++    XML_Parser parser, unsigned long long
> activationThresholdBytes);
> ++#endif
> ++
> + /* Expat follows the semantic versioning convention.
> +    See http://semver.org.
> + */
> +diff --git a/expat/lib/internal.h b/expat/lib/internal.h
> +index 60913dab..d8b31fa2 100644
> +--- a/expat/lib/internal.h
> ++++ b/expat/lib/internal.h
> +@@ -101,10 +101,40 @@
> + #  endif
> + #endif
> + 
> ++#include <limits.h> // ULONG_MAX
> ++
> ++#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
> ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
> ++#  else
> ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> ++#  endif
> ++#else
> ++#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
> ++#  if ! defined(ULONG_MAX)
> ++#    error Compiler did not define ULONG_MAX for us
> ++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
> ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
> ++#  else
> ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> ++#  endif
> ++#endif
> ++
> + #ifndef UNUSED_P
> + #  define UNUSED_P(p) (void)p
> + #endif
> + 
> ++/* NOTE BEGIN If you ever patch these defaults to greater values
> ++              for non-attack XML payload in your environment,
> ++              please file a bug report with libexpat.  Thank you!
> ++*/
> ++#define
> \
> ++  100.0f
> ++#define
> \
> ++  8388608 // 8 MiB, 2^23
> ++/* NOTE END */
> ++
> + #ifdef __cplusplus
> + extern "C" {
> + #endif
> +diff --git a/expat/lib/libexpat.def b/expat/lib/libexpat.def
> +index 16faf595..b5e59d8d 100644
> +--- a/expat/lib/libexpat.def
> ++++ b/expat/lib/libexpat.def
> +@@ -76,3 +76,6 @@ EXPORTS
> +   XML_SetHashSalt @67
> + ; added with version 2.2.5
> +   _INTERNAL_trim_to_complete_utf8_characters @68
> ++; backported from version 2.4.0
> ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
> +diff --git a/expat/lib/libexpatw.def b/expat/lib/libexpatw.def
> +index 16faf595..ebd77707 100644
> +--- a/expat/lib/libexpatw.def
> ++++ b/expat/lib/libexpatw.def
> +@@ -76,3 +76,6 @@ EXPORTS
> +   XML_SetHashSalt @67
> + ; added with version 2.2.5
> +   _INTERNAL_trim_to_complete_utf8_characters @68
> ++; backported from version 2.4.0
> ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @7
> +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
> +index 3aaf35b9..fdcc7296 100644
> +--- a/expat/lib/xmlparse.c
> ++++ b/expat/lib/xmlparse.c
> +@@ -47,6 +47,8 @@
> + #include <limits.h> /* UINT_MAX */
> + #include <stdio.h>  /* fprintf */
> + #include <stdlib.h> /* getenv, rand_s */
> ++#include <stdint.h> /* uintptr_t */
> ++#include <math.h>   /* isnan */
> + 
> + #ifdef _WIN32
> + #  define getpid GetCurrentProcessId
> +@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
> +   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
> + } OPEN_INTERNAL_ENTITY;
> + 
> ++enum XML_Account {
> ++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the
> Expat
> parser */
> ++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced
> during
> entity
> ++                                   expansion */
> ++  XML_ACCOUNT_NONE              /* i.e. do not account, was
> accounted
> already */
> ++};
> ++
> ++#ifdef XML_DTD
> ++typedef unsigned long long XmlBigCount;
> ++typedef struct accounting {
> ++  XmlBigCount countBytesDirect;
> ++  XmlBigCount countBytesIndirect;
> ++  int debugLevel;
> ++  float maximumAmplificationFactor; // >=1.0
> ++  unsigned long long activationThresholdBytes;
> ++} ACCOUNTING;
> ++
> ++typedef struct entity_stats {
> ++  unsigned int countEverOpened;
> ++  unsigned int currentDepth;
> ++  unsigned int maximumDepthSeen;
> ++  int debugLevel;
> ++} ENTITY_STATS;
> ++#endif /* XML_DTD */
> ++
> + typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const
> char *start,
> +                                          const char *end, const
> char
> **endPtr);
> + 
> +@@ -403,16 +430,18 @@ static enum XML_Error
> initializeEncoding(XML_Parser parser);
> + static enum XML_Error doProlog(XML_Parser parser, const ENCODING
> *enc,
> +                                const char *s, const char *end, int
> tok,
> +                                const char *next, const char
> **nextPtr,
> +-                               XML_Bool haveMore, XML_Bool
> allowClosingDoctype);
> ++                               XML_Bool haveMore, XML_Bool
> allowClosingDoctype,
> ++                               enum XML_Account account);
> + static enum XML_Error processInternalEntity(XML_Parser parser,
> ENTITY
> *entity,
> +                                             XML_Bool betweenDecl);
> + static enum XML_Error doContent(XML_Parser parser, int
> startTagLevel,
> +                                 const ENCODING *enc, const char
> *start,
> +                                 const char *end, const char
> **endPtr,
> +-                                XML_Bool haveMore);
> ++                                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,
> +@@ -422,7 +451,8 @@ static enum XML_Error doIgnoreSection(XML_Parser
> parser, const ENCODING *,
> + static void freeBindings(XML_Parser parser, BINDING *bindings);
> + static enum XML_Error storeAtts(XML_Parser parser, const ENCODING
> *,
> +                                 const char *s, TAG_NAME
> *tagNamePtr,
> +-                                BINDING **bindingsPtr);
> ++                                BINDING **bindingsPtr,
> ++                                enum XML_Account account);
> + static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
> +                                  const ATTRIBUTE_ID *attId, const
> XML_Char *uri,
> +                                  BINDING **bindingsPtr);
> +@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE *type,
> ATTRIBUTE_ID *, XML_Bool isCdata,
> +                            XML_Parser parser);
> + static enum XML_Error storeAttributeValue(XML_Parser parser, const
> ENCODING *,
> +                                           XML_Bool isCdata, const
> char *,
> +-                                          const char *, STRING_POOL
> *);
> ++                                          const char *, STRING_POOL
> *,
> ++                                          enum XML_Account
> account);
> + static enum XML_Error appendAttributeValue(XML_Parser parser, const
> ENCODING *,
> +                                            XML_Bool isCdata, const
> char *,
> +-                                           const char *,
> STRING_POOL
> *);
> ++                                           const char *,
> STRING_POOL
> *,
> ++                                           enum XML_Account
> account);
> + static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const
> ENCODING
> *enc,
> +                                     const char *start, const char
> *end);
> + static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
> + static enum XML_Error storeEntityValue(XML_Parser parser, const
> ENCODING *enc,
> +-                                       const char *start, const
> char
> *end);
> ++                                       const char *start, const
> char
> *end,
> ++                                       enum XML_Account account);
> + static int reportProcessingInstruction(XML_Parser parser, const
> ENCODING *enc,
> +                                        const char *start, const
> char
> *end);
> + static int reportComment(XML_Parser parser, const ENCODING *enc,
> +@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const XML_Char
> *encodingName,
> + 
> + static void parserInit(XML_Parser parser, const XML_Char
> *encodingName);
> + 
> ++#ifdef XML_DTD
> ++static float accountingGetCurrentAmplification(XML_Parser
> rootParser);
> ++static void accountingReportStats(XML_Parser originParser, const
> char
> *epilog);
> ++static void accountingOnAbort(XML_Parser originParser);
> ++static void accountingReportDiff(XML_Parser rootParser,
> ++                                 unsigned int
> levelsAwayFromRootParser,
> ++                                 const char *before, const char
> *after,
> ++                                 ptrdiff_t bytesMore, int
> source_line,
> ++                                 enum XML_Account account);
> ++static XML_Bool accountingDiffTolerated(XML_Parser originParser,
> int
> tok,
> ++                                        const char *before, const
> char *after,
> ++                                        int source_line,
> ++                                        enum XML_Account account);
> ++
> ++static void entityTrackingReportStats(XML_Parser parser, ENTITY
> *entity,
> ++                                      const char *action, int
> sourceLine);
> ++static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
> ++                                 int sourceLine);
> ++static void entityTrackingOnClose(XML_Parser parser, ENTITY
> *entity,
> ++                                  int sourceLine);
> ++
> ++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,
> ++                                   unsigned long
> defaultDebugLevel);
> ++
> + #define poolStart(pool) ((pool)->start)
> + #define poolEnd(pool) ((pool)->ptr)
> + #define poolLength(pool) ((pool)->ptr - (pool)->start)
> +@@ -616,6 +678,10 @@ struct XML_ParserStruct {
> +   enum XML_ParamEntityParsing m_paramEntityParsing;
> + #endif
> +   unsigned long m_hash_secret_salt;
> ++#ifdef XML_DTD
> ++  ACCOUNTING m_accounting;
> ++  ENTITY_STATS m_entity_stats;
> ++#endif
> + };
> + 
> + #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
> +@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const XML_Char
> *encodingName) {
> +   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
> + #endif
> +   parser->m_hash_secret_salt = 0;
> ++
> ++#ifdef XML_DTD
> ++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
> ++  parser->m_accounting.debugLevel =
> getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
> ++  parser->m_accounting.maximumAmplificationFactor
> ++      =
> EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
> ++  parser->m_accounting.activationThresholdBytes
> ++      =
> EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
> ++
> ++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
> ++  parser->m_entity_stats.debugLevel =
> getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
> ++#endif
> + }
> + 
> + /* moves list of bindings to m_freeBindingList */
> +@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
> +   /* Added in 2.2.5. */
> +   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1,
> already */
> +     return XML_L("invalid argument");
> ++  /* Backported from 2.4.0. */
> ++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
> ++    return XML_L(
> ++        "limit on input amplification factor (from DTD and
> entities)
> breached");
> +   }
> +   return NULL;
> + }
> +@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
> + 
> + const XML_Feature *XMLCALL
> + XML_GetFeatureList(void) {
> +-  static const XML_Feature features[]
> +-      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
> +-          sizeof(XML_Char)},
> +-         {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
> +-          sizeof(XML_LChar)},
> ++  static const XML_Feature features[] = {
> ++      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
> ++       sizeof(XML_Char)},
> ++      {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
> ++       sizeof(XML_LChar)},
> + #ifdef XML_UNICODE
> +-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> ++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> + #endif
> + #ifdef XML_UNICODE_WCHAR_T
> +-         {XML_FEATURE_UNICODE_WCHAR_T,
> XML_L("XML_UNICODE_WCHAR_T"),
> 0},
> ++      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"),
> 0},
> + #endif
> + #ifdef XML_DTD
> +-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> ++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> + #endif
> + #ifdef XML_CONTEXT_BYTES
> +-         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
> +-          XML_CONTEXT_BYTES},
> ++      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
> ++       XML_CONTEXT_BYTES},
> + #endif
> + #ifdef XML_MIN_SIZE
> +-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> ++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> + #endif
> + #ifdef XML_NS
> +-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> ++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> + #endif
> + #ifdef XML_LARGE_SIZE
> +-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> ++      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> + #endif
> + #ifdef XML_ATTR_INFO
> +-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> ++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> + #endif
> +-         {XML_FEATURE_END, NULL, 0}};
> ++#ifdef XML_DTD
> ++      /* Added in Expat 2.4.0. */
> ++     
> {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_D
> EF
> AULT,
> ++       XML_L("XML_BLAP_MAX_AMP"),
> ++       (long int)
> ++          
> EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT}
> ,
> ++     
> {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DE
> FA
> ULT,
> ++       XML_L("XML_BLAP_ACT_THRES"),
> ++      
> EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
> ++#endif
> ++      {XML_FEATURE_END, NULL, 0}};
> + 
> +   return features;
> + }
> + 
> ++#ifdef XML_DTD
> ++XML_Bool XMLCALL
> ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> ++    XML_Parser parser, float maximumAmplificationFactor) {
> ++  if ((parser == NULL) || (parser->m_parentParser != NULL)
> ++      || isnan(maximumAmplificationFactor)
> ++      || (maximumAmplificationFactor < 1.0f)) {
> ++    return XML_FALSE;
> ++  }
> ++  parser->m_accounting.maximumAmplificationFactor =
> maximumAmplificationFactor;
> ++  return XML_TRUE;
> ++}
> ++
> ++XML_Bool XMLCALL
> ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> ++    XML_Parser parser, unsigned long long activationThresholdBytes)
> {
> ++  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
> ++    return XML_FALSE;
> ++  }
> ++  parser->m_accounting.activationThresholdBytes =
> activationThresholdBytes;
> ++  return XML_TRUE;
> ++}
> ++#endif /* XML_DTD */
> ++
> + /* Initially tag->rawName always points into the parse buffer;
> +    for those TAG instances opened while the current parse buffer
> was
> +    processed, and not yet closed, we need to store tag->rawName in
> a
> more
> +@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
> + static enum XML_Error PTRCALL
> + contentProcessor(XML_Parser parser, const char *start, const char
> *end,
> +                  const char **endPtr) {
> +-  enum XML_Error result
> +-      = doContent(parser, 0, parser->m_encoding, start, end,
> endPtr,
> +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
> ++  enum XML_Error result = doContent(
> ++      parser, 0, parser->m_encoding, start, end, endPtr,
> ++      (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> XML_ACCOUNT_DIRECT);
> +   if (result == XML_ERROR_NONE) {
> +     if (! storeRawNames(parser))
> +       return XML_ERROR_NO_MEMORY;
> +@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser
> parser,
> const char *start,
> +   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
> +   switch (tok) {
> +   case XML_TOK_BOM:
> ++#ifdef XML_DTD
> ++    if (! accountingDiffTolerated(parser, tok, start, next,
> __LINE__,
> ++                                  XML_ACCOUNT_DIRECT)) {
> ++      accountingOnAbort(parser);
> ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++    }
> ++#endif /* XML_DTD */
> ++
> +     /* If we are at the end of the buffer, this would cause the
> next
> stage,
> +        i.e. externalEntityInitProcessor3, to pass control directly
> to
> +        doContent (by detecting XML_TOK_NONE) without processing any
> xml text
> +@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser
> parser,
> const char *start,
> +   const char *next = start; /* XmlContentTok doesn't always set the
> last arg */
> +   parser->m_eventPtr = start;
> +   tok = XmlContentTok(parser->m_encoding, start, end, &next);
> ++  /* Note: These bytes are accounted later in:
> ++           - processXmlDecl
> ++           - externalEntityContentProcessor
> ++  */
> +   parser->m_eventEndPtr = next;
> + 
> +   switch (tok) {
> +@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser
> parser, const char *start,
> +                                const char *end, const char
> **endPtr)
> {
> +   enum XML_Error result
> +       = doContent(parser, 1, parser->m_encoding, start, end,
> endPtr,
> +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
> ++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> ++                  XML_ACCOUNT_ENTITY_EXPANSION);
> +   if (result == XML_ERROR_NONE) {
> +     if (! storeRawNames(parser))
> +       return XML_ERROR_NO_MEMORY;
> +@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser
> parser, const char *start,
> + static enum XML_Error
> + doContent(XML_Parser parser, int startTagLevel, const ENCODING
> *enc,
> +           const char *s, const char *end, const char **nextPtr,
> +-          XML_Bool haveMore) {
> ++          XML_Bool haveMore, enum XML_Account account) {
> +   /* save one level of indirection */
> +   DTD *const dtd = parser->m_dtd;
> + 
> +@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int
> startTagLevel,
> const ENCODING *enc,
> +   for (;;) {
> +     const char *next = s; /* XmlContentTok doesn't always set the
> last arg */
> +     int tok = XmlContentTok(enc, s, end, &next);
> ++#ifdef XML_DTD
> ++    const char *accountAfter
> ++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok ==
> XML_TOK_TRAILING_CR))
> ++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
> ++              : next;
> ++    if (! accountingDiffTolerated(parser, tok, s, accountAfter,
> __LINE__,
> ++                                  account)) {
> ++      accountingOnAbort(parser);
> ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++    }
> ++#endif
> +     *eventEndPP = next;
> +     switch (tok) {
> +     case XML_TOK_TRAILING_CR:
> +@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int
> startTagLevel,
> const ENCODING *enc,
> +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> +           enc, s + enc->minBytesPerChar, next - enc-
> > minBytesPerChar);
> +       if (ch) {
> ++#ifdef XML_DTD
> ++        /* NOTE: We are replacing 4-6 characters original input for
> 1
> character
> ++         *       so there is no amplification and hence recording
> without
> ++         *       protection. */
> ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> ++                                ((char *)&ch) + sizeof(XML_Char),
> __LINE__,
> ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> ++#endif /* XML_DTD */
> +         if (parser->m_characterDataHandler)
> +           parser->m_characterDataHandler(parser->m_handlerArg, &ch,
> 1);
> +         else if (parser->m_defaultHandler)
> +@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int
> startTagLevel,
> const ENCODING *enc,
> +       }
> +       tag->name.str = (XML_Char *)tag->buf;
> +       *toPtr = XML_T('\0');
> +-      result = storeAtts(parser, enc, s, &(tag->name), &(tag-
> > bindings));
> ++      result
> ++          = storeAtts(parser, enc, s, &(tag->name), &(tag-
> >bindings),
> account);
> +       if (result)
> +         return result;
> +       if (parser->m_startElementHandler)
> +@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int
> startTagLevel,
> const ENCODING *enc,
> +       if (! name.str)
> +         return XML_ERROR_NO_MEMORY;
> +       poolFinish(&parser->m_tempPool);
> +-      result = storeAtts(parser, enc, s, &name, &bindings);
> ++      result = storeAtts(parser, enc, s, &name, &bindings,
> ++                         XML_ACCOUNT_NONE /* token spans whole
> start
> tag */);
> +       if (result != XML_ERROR_NONE) {
> +         freeBindings(parser, bindings);
> +         return result;
> +@@ -2907,7 +3057,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) {
> +@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING
> *bindings) {
> + */
> + static enum XML_Error
> + storeAtts(XML_Parser parser, const ENCODING *enc, const char
> *attStr,
> +-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
> ++          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
> ++          enum XML_Account account) {
> +   DTD *const dtd = parser->m_dtd; /* save one level of indirection
> */
> +   ELEMENT_TYPE *elementType;
> +   int nDefaultAtts;
> +@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const ENCODING
> *enc, const char *attStr,
> +       /* normalize the attribute value */
> +       result = storeAttributeValue(
> +           parser, enc, isCdata, parser->m_atts[i].valuePtr,
> +-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
> ++          parser->m_atts[i].valueEnd, &parser->m_tempPool,
> account);
> +       if (result)
> +         return result;
> +       appAtts[attIndex] = poolStart(&parser->m_tempPool);
> +@@ -3535,9 +3687,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) {
> +@@ -3557,7 +3709,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;
> +@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const
> ENCODING *enc, const char **startPtr,
> +   for (;;) {
> +     const char *next;
> +     int tok = XmlCdataSectionTok(enc, s, end, &next);
> ++#ifdef XML_DTD
> ++    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) {
> +     case XML_TOK_CDATA_SECT_CLOSE:
> +@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const
> ENCODING *enc, const char **startPtr,
> +   *eventPP = s;
> +   *startPtr = NULL;
> +   tok = XmlIgnoreSectionTok(enc, s, end, &next);
> ++#  ifdef XML_DTD
> ++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> ++                                XML_ACCOUNT_DIRECT)) {
> ++    accountingOnAbort(parser);
> ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++  }
> ++#  endif
> +   *eventEndPP = next;
> +   switch (tok) {
> +   case XML_TOK_IGNORE_SECT:
> +@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int
> isGeneralTextEntity, const char *s,
> +   const char *versionend;
> +   const XML_Char *storedversion = NULL;
> +   int standalone = -1;
> ++
> ++#ifdef XML_DTD
> ++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next,
> __LINE__,
> ++                                XML_ACCOUNT_DIRECT)) {
> ++    accountingOnAbort(parser);
> ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++  }
> ++#endif
> ++
> +   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
> +           isGeneralTextEntity, parser->m_encoding, s, next,
> &parser-
> > m_eventPtr,
> +           &version, &versionend, &encodingName, &newEncoding,
> &standalone)) {
> +@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser parser,
> const char *s, const char *end,
> + 
> +   for (;;) {
> +     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
> ++    /* Note: Except for XML_TOK_BOM below, these bytes are
> accounted
> later in:
> ++             - storeEntityValue
> ++             - processXmlDecl
> ++    */
> +     parser->m_eventEndPtr = next;
> +     if (tok <= 0) {
> +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> XML_TOK_INVALID) {
> +@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser parser,
> const char *s, const char *end,
> +         break;
> +       }
> +       /* found end of entity value - can store it now */
> +-      return storeEntityValue(parser, parser->m_encoding, s, end);
> ++      return storeEntityValue(parser, parser->m_encoding, s, end,
> ++                              XML_ACCOUNT_DIRECT);
> +     } else if (tok == XML_TOK_XML_DECL) {
> +       enum XML_Error result;
> +       result = processXmlDecl(parser, 0, start, next);
> +@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser parser,
> const char *s, const char *end,
> +     */
> +     else if (tok == XML_TOK_BOM && next == end
> +              && ! parser->m_parsingStatus.finalBuffer) {
> ++#  ifdef XML_DTD
> ++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> ++                                    XML_ACCOUNT_DIRECT)) {
> ++        accountingOnAbort(parser);
> ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++      }
> ++#  endif
> ++
> +       *nextPtr = next;
> +       return XML_ERROR_NONE;
> +     }
> +@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser parser,
> const char *s, const char *end,
> +   }
> +   /* This would cause the next stage, i.e. doProlog to be passed
> XML_TOK_BOM.
> +      However, when parsing an external subset, doProlog will not
> accept a BOM
> +-     as valid, and report a syntax error, so we have to skip the
> BOM
> ++     as valid, and report a syntax error, so we have to skip the
> BOM,
> and
> ++     account for the BOM bytes.
> +   */
> +   else if (tok == XML_TOK_BOM) {
> ++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> ++                                  XML_ACCOUNT_DIRECT)) {
> ++      accountingOnAbort(parser);
> ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++    }
> ++
> +     s = next;
> +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> +   }
> + 
> +   parser->m_processor = prologProcessor;
> +   return doProlog(parser, parser->m_encoding, s, end, tok, next,
> nextPtr,
> +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> XML_TRUE);
> ++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> XML_TRUE,
> ++                  XML_ACCOUNT_DIRECT);
> + }
> + 
> + static enum XML_Error PTRCALL
> +@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser, const
> char *s, const char *end,
> + 
> +   for (;;) {
> +     tok = XmlPrologTok(enc, start, end, &next);
> ++    /* Note: These bytes are accounted later in:
> ++             - storeEntityValue
> ++    */
> +     if (tok <= 0) {
> +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> XML_TOK_INVALID) {
> +         *nextPtr = s;
> +@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser, const
> char *s, const char *end,
> +         break;
> +       }
> +       /* found end of entity value - can store it now */
> +-      return storeEntityValue(parser, enc, s, end);
> ++      return storeEntityValue(parser, enc, s, end,
> XML_ACCOUNT_DIRECT);
> +     }
> +     start = next;
> +   }
> +@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const
> char
> *s, const char *end,
> +   const char *next = s;
> +   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> +   return doProlog(parser, parser->m_encoding, s, end, tok, next,
> nextPtr,
> +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> XML_TRUE);
> ++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> XML_TRUE,
> ++                  XML_ACCOUNT_DIRECT);
> + }
> + 
> + static enum XML_Error
> + doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
> const
> char *end,
> +          int tok, const char *next, const char **nextPtr, XML_Bool
> haveMore,
> +-         XML_Bool allowClosingDoctype) {
> ++         XML_Bool allowClosingDoctype, enum XML_Account account) {
> + #ifdef XML_DTD
> +   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
> + #endif /* XML_DTD */
> +@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const ENCODING
> *enc, const char *s, const char *end,
> +   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
> +   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
> + 
> ++#ifndef XML_DTD
> ++  UNUSED_P(account);
> ++#endif
> ++
> +   /* save one level of indirection */
> +   DTD *const dtd = parser->m_dtd;
> + 
> +@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const ENCODING
> *enc, const char *s, const char *end,
> +       }
> +     }
> +     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
> ++#ifdef XML_DTD
> ++    switch (role) {
> ++    case XML_ROLE_INSTANCE_START: // bytes accounted in
> contentProcessor
> ++    case XML_ROLE_XML_DECL:       // bytes accounted in
> processXmlDecl
> ++    case XML_ROLE_TEXT_DECL:      // bytes accounted in
> processXmlDecl
> ++      break;
> ++    default:
> ++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> account)) {
> ++        accountingOnAbort(parser);
> ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++      }
> ++    }
> ++#endif
> +     switch (role) {
> +     case XML_ROLE_XML_DECL: {
> +       enum XML_Error result = processXmlDecl(parser, 0, s, next);
> +@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING
> *enc,
> const char *s, const char *end,
> +         const XML_Char *attVal;
> +         enum XML_Error result = storeAttributeValue(
> +             parser, enc, parser->m_declAttributeIsCdata,
> +-            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
> &dtd->pool);
> ++            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
> &dtd->pool,
> ++            XML_ACCOUNT_NONE);
> +         if (result)
> +           return result;
> +         attVal = poolStart(&dtd->pool);
> +@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING
> *enc,
> const char *s, const char *end,
> +       break;
> +     case XML_ROLE_ENTITY_VALUE:
> +       if (dtd->keepProcessing) {
> +-        enum XML_Error result = storeEntityValue(
> +-            parser, enc, s + enc->minBytesPerChar, next - enc-
> > minBytesPerChar);
> ++        enum XML_Error result
> ++            = storeEntityValue(parser, enc, s + enc-
> >minBytesPerChar,
> ++                               next - enc->minBytesPerChar,
> XML_ACCOUNT_NONE);
> +         if (parser->m_declEntity) {
> +           parser->m_declEntity->textPtr = poolStart(&dtd-
> > entityValuePool);
> +           parser->m_declEntity->textLen
> +@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const ENCODING
> *enc, const char *s, const char *end,
> +         if (parser->m_externalEntityRefHandler) {
> +           dtd->paramEntityRead = XML_FALSE;
> +           entity->open = XML_TRUE;
> ++          entityTrackingOnOpen(parser, entity, __LINE__);
> +           if (! parser->m_externalEntityRefHandler(
> +                   parser->m_externalEntityRefHandlerArg, 0, entity-
> > base,
> +                   entity->systemId, entity->publicId)) {
> ++            entityTrackingOnClose(parser, entity, __LINE__);
> +             entity->open = XML_FALSE;
> +             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> +           }
> ++          entityTrackingOnClose(parser, entity, __LINE__);
> +           entity->open = XML_FALSE;
> +           handleDefault = XML_FALSE;
> +           if (! dtd->paramEntityRead) {
> +@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const char
> *s, const char *end,
> +   for (;;) {
> +     const char *next = NULL;
> +     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> ++#ifdef XML_DTD
> ++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> ++                                  XML_ACCOUNT_DIRECT)) {
> ++      accountingOnAbort(parser);
> ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++    }
> ++#endif
> +     parser->m_eventEndPtr = next;
> +     switch (tok) {
> +     /* report partial linebreak - it might be the last token */
> +@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser,
> ENTITY
> *entity, XML_Bool betweenDecl) {
> +       return XML_ERROR_NO_MEMORY;
> +   }
> +   entity->open = XML_TRUE;
> ++#ifdef XML_DTD
> ++  entityTrackingOnOpen(parser, entity, __LINE__);
> ++#endif
> +   entity->processed = 0;
> +   openEntity->next = parser->m_openInternalEntities;
> +   parser->m_openInternalEntities = openEntity;
> +@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser,
> ENTITY *entity, XML_Bool betweenDecl) {
> +     int tok
> +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> textEnd, &next);
> +     result = doProlog(parser, parser->m_internalEncoding,
> textStart,
> textEnd,
> +-                      tok, next, &next, XML_FALSE, XML_FALSE);
> ++                      tok, next, &next, XML_FALSE, XML_FALSE,
> ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> +   } else
> + #endif /* XML_DTD */
> +     result = doContent(parser, parser->m_tagLevel, parser-
> > m_internalEncoding,
> +-                       textStart, textEnd, &next, XML_FALSE);
> ++                       textStart, textEnd, &next, XML_FALSE,
> ++                       XML_ACCOUNT_ENTITY_EXPANSION);
> + 
> +   if (result == XML_ERROR_NONE) {
> +     if (textEnd != next && parser->m_parsingStatus.parsing ==
> XML_SUSPENDED) {
> +       entity->processed = (int)(next - textStart);
> +       parser->m_processor = internalEntityProcessor;
> +     } else {
> ++#ifdef XML_DTD
> ++      entityTrackingOnClose(parser, entity, __LINE__);
> ++#endif /* XML_DTD */
> +       entity->open = XML_FALSE;
> +       parser->m_openInternalEntities = openEntity->next;
> +       /* put openEntity back in list of free instances */
> +@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser parser,
> const char *s, const char *end,
> +     int tok
> +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> textEnd, &next);
> +     result = doProlog(parser, parser->m_internalEncoding,
> textStart,
> textEnd,
> +-                      tok, next, &next, XML_FALSE, XML_TRUE);
> ++                      tok, next, &next, XML_FALSE, XML_TRUE,
> ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> +   } else
> + #endif /* XML_DTD */
> +     result = doContent(parser, openEntity->startTagLevel,
> +                        parser->m_internalEncoding, textStart,
> textEnd, &next,
> +-                       XML_FALSE);
> ++                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
> + 
> +   if (result != XML_ERROR_NONE)
> +     return result;
> +@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser,
> const
> char *s, const char *end,
> +     entity->processed = (int)(next - (char *)entity->textPtr);
> +     return result;
> +   } else {
> ++#ifdef XML_DTD
> ++    entityTrackingOnClose(parser, entity, __LINE__);
> ++#endif
> +     entity->open = XML_FALSE;
> +     parser->m_openInternalEntities = openEntity->next;
> +     /* put openEntity back in list of free instances */
> +@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser,
> const
> char *s, const char *end,
> +     parser->m_processor = prologProcessor;
> +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> +     return doProlog(parser, parser->m_encoding, s, end, tok, next,
> nextPtr,
> +-                    (XML_Bool)! parser-
> >m_parsingStatus.finalBuffer,
> XML_TRUE);
> ++                    (XML_Bool)! parser-
> >m_parsingStatus.finalBuffer,
> XML_TRUE,
> ++                    XML_ACCOUNT_DIRECT);
> +   } else
> + #endif /* XML_DTD */
> +   {
> +@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser,
> const
> char *s, const char *end,
> +     /* see externalEntityContentProcessor vs contentProcessor */
> +     return doContent(parser, parser->m_parentParser ? 1 : 0,
> parser-
> > m_encoding,
> +                      s, end, nextPtr,
> +-                     (XML_Bool)! parser-
> > m_parsingStatus.finalBuffer);
> ++                     (XML_Bool)! parser-
> >m_parsingStatus.finalBuffer,
> ++                     XML_ACCOUNT_DIRECT);
> +   }
> + }
> + 
> +@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const char
> *s, const char *end,
> + 
> + static enum XML_Error
> + storeAttributeValue(XML_Parser parser, const ENCODING *enc,
> XML_Bool
> isCdata,
> +-                    const char *ptr, const char *end, STRING_POOL
> *pool) {
> ++                    const char *ptr, const char *end, STRING_POOL
> *pool,
> ++                    enum XML_Account account) {
> +   enum XML_Error result
> +-      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
> ++      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool,
> account);
> +   if (result)
> +     return result;
> +   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
> +@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser, const
> ENCODING *enc, XML_Bool isCdata,
> + 
> + static enum XML_Error
> + appendAttributeValue(XML_Parser parser, const ENCODING *enc,
> XML_Bool
> isCdata,
> +-                     const char *ptr, const char *end, STRING_POOL
> *pool) {
> ++                     const char *ptr, const char *end, STRING_POOL
> *pool,
> ++                     enum XML_Account account) {
> +   DTD *const dtd = parser->m_dtd; /* save one level of indirection
> */
> ++#ifndef XML_DTD
> ++  UNUSED_P(account);
> ++#endif
> ++
> +   for (;;) {
> +     const char *next;
> +     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
> ++#ifdef XML_DTD
> ++    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__,
> account)) {
> ++      accountingOnAbort(parser);
> ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++    }
> ++#endif
> +     switch (tok) {
> +     case XML_TOK_NONE:
> +       return XML_ERROR_NONE;
> +@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser, const
> ENCODING *enc, XML_Bool isCdata,
> +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> +           enc, ptr + enc->minBytesPerChar, next - enc-
> > minBytesPerChar);
> +       if (ch) {
> ++#ifdef XML_DTD
> ++        /* NOTE: We are replacing 4-6 characters original input for
> 1
> character
> ++         *       so there is no amplification and hence recording
> without
> ++         *       protection. */
> ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> ++                                ((char *)&ch) + sizeof(XML_Char),
> __LINE__,
> ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> ++#endif /* XML_DTD */
> +         if (! poolAppendChar(pool, ch))
> +           return XML_ERROR_NO_MEMORY;
> +         break;
> +@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser, const
> ENCODING *enc, XML_Bool isCdata,
> +         enum XML_Error result;
> +         const XML_Char *textEnd = entity->textPtr + entity-
> >textLen;
> +         entity->open = XML_TRUE;
> ++#ifdef XML_DTD
> ++        entityTrackingOnOpen(parser, entity, __LINE__);
> ++#endif
> +         result = appendAttributeValue(parser, parser-
> > m_internalEncoding,
> +-                                      isCdata, (char *)entity-
> > textPtr,
> +-                                      (char *)textEnd, pool);
> ++                                      isCdata, (const char
> *)entity-
> > textPtr,
> ++                                      (const char *)textEnd, pool,
> ++                                     
> XML_ACCOUNT_ENTITY_EXPANSION);
> ++#ifdef XML_DTD
> ++        entityTrackingOnClose(parser, entity, __LINE__);
> ++#endif
> +         entity->open = XML_FALSE;
> +         if (result)
> +           return result;
> +@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser,
> const
> ENCODING *enc, XML_Bool isCdata,
> + 
> + static enum XML_Error
> + storeEntityValue(XML_Parser parser, const ENCODING *enc,
> +-                 const char *entityTextPtr, const char
> *entityTextEnd) {
> ++                 const char *entityTextPtr, const char
> *entityTextEnd,
> ++                 enum XML_Account account) {
> +   DTD *const dtd = parser->m_dtd; /* save one level of indirection
> */
> +   STRING_POOL *pool = &(dtd->entityValuePool);
> +   enum XML_Error result = XML_ERROR_NONE;
> + #ifdef XML_DTD
> +   int oldInEntityValue = parser->m_prologState.inEntityValue;
> +   parser->m_prologState.inEntityValue = 1;
> ++#else
> ++  UNUSED_P(account);
> + #endif /* XML_DTD */
> +   /* never return Null for the value argument in EntityDeclHandler,
> +      since this would indicate an external entity; therefore we
> +@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const
> ENCODING *enc,
> +   for (;;) {
> +     const char *next;
> +     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd,
> &next);
> ++
> ++#ifdef XML_DTD
> ++    if (! accountingDiffTolerated(parser, tok, entityTextPtr, next,
> __LINE__,
> ++                                  account)) {
> ++      accountingOnAbort(parser);
> ++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++      goto endEntityValue;
> ++    }
> ++#endif
> ++
> +     switch (tok) {
> +     case XML_TOK_PARAM_ENTITY_REF:
> + #ifdef XML_DTD
> +@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser, const
> ENCODING *enc,
> +           if (parser->m_externalEntityRefHandler) {
> +             dtd->paramEntityRead = XML_FALSE;
> +             entity->open = XML_TRUE;
> ++            entityTrackingOnOpen(parser, entity, __LINE__);
> +             if (! parser->m_externalEntityRefHandler(
> +                     parser->m_externalEntityRefHandlerArg, 0,
> entity-
> > base,
> +                     entity->systemId, entity->publicId)) {
> ++              entityTrackingOnClose(parser, entity, __LINE__);
> +               entity->open = XML_FALSE;
> +               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> +               goto endEntityValue;
> +             }
> ++            entityTrackingOnClose(parser, entity, __LINE__);
> +             entity->open = XML_FALSE;
> +             if (! dtd->paramEntityRead)
> +               dtd->keepProcessing = dtd->standalone;
> +@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const
> ENCODING *enc,
> +             dtd->keepProcessing = dtd->standalone;
> +         } else {
> +           entity->open = XML_TRUE;
> ++          entityTrackingOnOpen(parser, entity, __LINE__);
> +           result = storeEntityValue(
> +-              parser, parser->m_internalEncoding, (char *)entity-
> > textPtr,
> +-              (char *)(entity->textPtr + entity->textLen));
> ++              parser, parser->m_internalEncoding, (const char
> *)entity->textPtr,
> ++              (const char *)(entity->textPtr + entity->textLen),
> ++              XML_ACCOUNT_ENTITY_EXPANSION);
> ++          entityTrackingOnClose(parser, entity, __LINE__);
> +           entity->open = XML_FALSE;
> +           if (result)
> +             goto endEntityValue;
> +@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const
> XML_Memory_Handling_Suite *memsuite) {
> +   memcpy(result, s, charsRequired * sizeof(XML_Char));
> +   return result;
> + }
> ++
> ++#ifdef XML_DTD
> ++
> ++static float
> ++accountingGetCurrentAmplification(XML_Parser rootParser) {
> ++  const XmlBigCount countBytesOutput
> ++      = rootParser->m_accounting.countBytesDirect
> ++        + rootParser->m_accounting.countBytesIndirect;
> ++  const float amplificationFactor
> ++      = rootParser->m_accounting.countBytesDirect
> ++            ? (countBytesOutput
> ++               / (float)(rootParser-
> >m_accounting.countBytesDirect))
> ++            : 1.0f;
> ++  assert(! rootParser->m_parentParser);
> ++  return amplificationFactor;
> ++}
> ++
> ++static void
> ++accountingReportStats(XML_Parser originParser, const char *epilog)
> {
> ++  const XML_Parser rootParser = getRootParserOf(originParser,
> NULL);
> ++  assert(! rootParser->m_parentParser);
> ++
> ++  if (rootParser->m_accounting.debugLevel < 1) {
> ++    return;
> ++  }
> ++
> ++  const float amplificationFactor
> ++      = accountingGetCurrentAmplification(rootParser);
> ++  fprintf(stderr,
> ++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
> ++              "10") ", indirect " EXPAT_FMT_ULL("10") ",
> amplification %8.2f%s",
> ++          (void *)rootParser, rootParser-
> > m_accounting.countBytesDirect,
> ++          rootParser->m_accounting.countBytesIndirect,
> ++          (double)amplificationFactor, epilog);
> ++}
> ++
> ++static void
> ++accountingOnAbort(XML_Parser originParser) {
> ++  accountingReportStats(originParser, " ABORTING\n");
> ++}
> ++
> ++static void
> ++accountingReportDiff(XML_Parser rootParser,
> ++                     unsigned int levelsAwayFromRootParser, const
> char *before,
> ++                     const char *after, ptrdiff_t bytesMore, int
> source_line,
> ++                     enum XML_Account account) {
> ++  assert(! rootParser->m_parentParser);
> ++
> ++  fprintf(stderr,
> ++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d,
> xmlparse.c:%d) %*s\"",
> ++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" :
> "EXP",
> ++          levelsAwayFromRootParser, source_line, 10, "");
> ++
> ++  const char ellipis[] = "[..]";
> ++  const size_t ellipsisLength = sizeof(ellipis) /* because compile-
> time */ - 1;
> ++  const unsigned int contextLength = 10;
> ++
> ++  /* Note: Performance is of no concern here */
> ++  const char *walker = before;
> ++  if ((rootParser->m_accounting.debugLevel >= 3)
> ++      || (after - before)
> ++             <= (ptrdiff_t)(contextLength + ellipsisLength +
> contextLength)) {
> ++    for (; walker < after; walker++) {
> ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> ++    }
> ++  } else {
> ++    for (; walker < before + contextLength; walker++) {
> ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> ++    }
> ++    fprintf(stderr, ellipis);
> ++    walker = after - contextLength;
> ++    for (; walker < after; walker++) {
> ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> ++    }
> ++  }
> ++  fprintf(stderr, "\"\n");
> ++}
> ++
> ++static XML_Bool
> ++accountingDiffTolerated(XML_Parser originParser, int tok, const
> char
> *before,
> ++                        const char *after, int source_line,
> ++                        enum XML_Account account) {
> ++  /* Note: We need to check the token type *first* to be sure that
> ++   *       we can even access variable <after>, safely.
> ++   *       E.g. for XML_TOK_NONE <after> may hold an invalid
> pointer.
> */
> ++  switch (tok) {
> ++  case XML_TOK_INVALID:
> ++  case XML_TOK_PARTIAL:
> ++  case XML_TOK_PARTIAL_CHAR:
> ++  case XML_TOK_NONE:
> ++    return XML_TRUE;
> ++  }
> ++
> ++  if (account == XML_ACCOUNT_NONE)
> ++    return XML_TRUE; /* because these bytes have been accounted
> for,
> already */
> ++
> ++  unsigned int levelsAwayFromRootParser;
> ++  const XML_Parser rootParser
> ++      = getRootParserOf(originParser, &levelsAwayFromRootParser);
> ++  assert(! rootParser->m_parentParser);
> ++
> ++  const int isDirect
> ++      = (account == XML_ACCOUNT_DIRECT) && (originParser ==
> rootParser);
> ++  const ptrdiff_t bytesMore = after - before;
> ++
> ++  XmlBigCount *const additionTarget
> ++      = isDirect ? &rootParser->m_accounting.countBytesDirect
> ++                 : &rootParser->m_accounting.countBytesIndirect;
> ++
> ++  /* Detect and avoid integer overflow */
> ++  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
> ++    return XML_FALSE;
> ++  *additionTarget += bytesMore;
> ++
> ++  const XmlBigCount countBytesOutput
> ++      = rootParser->m_accounting.countBytesDirect
> ++        + rootParser->m_accounting.countBytesIndirect;
> ++  const float amplificationFactor
> ++      = accountingGetCurrentAmplification(rootParser);
> ++  const XML_Bool tolerated
> ++      = (countBytesOutput < rootParser-
> > m_accounting.activationThresholdBytes)
> ++        || (amplificationFactor
> ++            <= rootParser-
> >m_accounting.maximumAmplificationFactor);
> ++
> ++  if (rootParser->m_accounting.debugLevel >= 2) {
> ++    accountingReportStats(rootParser, "");
> ++    accountingReportDiff(rootParser, levelsAwayFromRootParser,
> before, after,
> ++                         bytesMore, source_line, account);
> ++  }
> ++
> ++  return tolerated;
> ++}
> ++
> ++static void
> ++entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
> ++                          const char *action, int sourceLine) {
> ++  assert(! rootParser->m_parentParser);
> ++  if (rootParser->m_entity_stats.debugLevel < 1)
> ++    return;
> ++
> ++#  if defined(XML_UNICODE)
> ++  const char *const entityName = "[..]";
> ++#  else
> ++  const char *const entityName = entity->name;
> ++#  endif
> ++
> ++  fprintf(
> ++      stderr,
> ++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s
> length %d (xmlparse.c:%d)\n",
> ++      (void *)rootParser, rootParser-
> >m_entity_stats.countEverOpened,
> ++      rootParser->m_entity_stats.currentDepth,
> ++      rootParser->m_entity_stats.maximumDepthSeen,
> ++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
> ++      entity->is_param ? "%" : "&", entityName, action, entity-
> > textLen,
> ++      sourceLine);
> ++}
> ++
> ++static void
> ++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int
> sourceLine) {
> ++  const XML_Parser rootParser = getRootParserOf(originParser,
> NULL);
> ++  assert(! rootParser->m_parentParser);
> ++
> ++  rootParser->m_entity_stats.countEverOpened++;
> ++  rootParser->m_entity_stats.currentDepth++;
> ++  if (rootParser->m_entity_stats.currentDepth
> ++      > rootParser->m_entity_stats.maximumDepthSeen) {
> ++    rootParser->m_entity_stats.maximumDepthSeen++;
> ++  }
> ++
> ++  entityTrackingReportStats(rootParser, entity, "OPEN ",
> sourceLine);
> ++}
> ++
> ++static void
> ++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int
> sourceLine) {
> ++  const XML_Parser rootParser = getRootParserOf(originParser,
> NULL);
> ++  assert(! rootParser->m_parentParser);
> ++
> ++  entityTrackingReportStats(rootParser, entity, "CLOSE",
> sourceLine);
> ++  rootParser->m_entity_stats.currentDepth--;
> ++}
> ++
> ++static XML_Parser
> ++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
> ++  XML_Parser rootParser = parser;
> ++  unsigned int stepsTakenUpwards = 0;
> ++  while (rootParser->m_parentParser) {
> ++    rootParser = rootParser->m_parentParser;
> ++    stepsTakenUpwards++;
> ++  }
> ++  assert(! rootParser->m_parentParser);
> ++  if (outLevelDiff != NULL) {
> ++    *outLevelDiff = stepsTakenUpwards;
> ++  }
> ++  return rootParser;
> ++}
> ++
> ++static const char *
> ++unsignedCharToPrintable(unsigned char c) {
> ++  switch (c) {
> ++  case 0:
> ++    return "\\0";
> ++  case 1:
> ++    return "\\x1";
> ++  case 2:
> ++    return "\\x2";
> ++  case 3:
> ++    return "\\x3";
> ++  case 4:
> ++    return "\\x4";
> ++  case 5:
> ++    return "\\x5";
> ++  case 6:
> ++    return "\\x6";
> ++  case 7:
> ++    return "\\x7";
> ++  case 8:
> ++    return "\\x8";
> ++  case 9:
> ++    return "\\t";
> ++  case 10:
> ++    return "\\n";
> ++  case 11:
> ++    return "\\xB";
> ++  case 12:
> ++    return "\\xC";
> ++  case 13:
> ++    return "\\r";
> ++  case 14:
> ++    return "\\xE";
> ++  case 15:
> ++    return "\\xF";
> ++  case 16:
> ++    return "\\x10";
> ++  case 17:
> ++    return "\\x11";
> ++  case 18:
> ++    return "\\x12";
> ++  case 19:
> ++    return "\\x13";
> ++  case 20:
> ++    return "\\x14";
> ++  case 21:
> ++    return "\\x15";
> ++  case 22:
> ++    return "\\x16";
> ++  case 23:
> ++    return "\\x17";
> ++  case 24:
> ++    return "\\x18";
> ++  case 25:
> ++    return "\\x19";
> ++  case 26:
> ++    return "\\x1A";
> ++  case 27:
> ++    return "\\x1B";
> ++  case 28:
> ++    return "\\x1C";
> ++  case 29:
> ++    return "\\x1D";
> ++  case 30:
> ++    return "\\x1E";
> ++  case 31:
> ++    return "\\x1F";
> ++  case 32:
> ++    return " ";
> ++  case 33:
> ++    return "!";
> ++  case 34:
> ++    return "\\\"";
> ++  case 35:
> ++    return "#";
> ++  case 36:
> ++    return "$";
> ++  case 37:
> ++    return "%";
> ++  case 38:
> ++    return "&";
> ++  case 39:
> ++    return "'";
> ++  case 40:
> ++    return "(";
> ++  case 41:
> ++    return ")";
> ++  case 42:
> ++    return "*";
> ++  case 43:
> ++    return "+";
> ++  case 44:
> ++    return ",";
> ++  case 45:
> ++    return "-";
> ++  case 46:
> ++    return ".";
> ++  case 47:
> ++    return "/";
> ++  case 48:
> ++    return "0";
> ++  case 49:
> ++    return "1";
> ++  case 50:
> ++    return "2";
> ++  case 51:
> ++    return "3";
> ++  case 52:
> ++    return "4";
> ++  case 53:
> ++    return "5";
> ++  case 54:
> ++    return "6";
> ++  case 55:
> ++    return "7";
> ++  case 56:
> ++    return "8";
> ++  case 57:
> ++    return "9";
> ++  case 58:
> ++    return ":";
> ++  case 59:
> ++    return ";";
> ++  case 60:
> ++    return "<";
> ++  case 61:
> ++    return "=";
> ++  case 62:
> ++    return ">";
> ++  case 63:
> ++    return "?";
> ++  case 64:
> ++    return "@";
> ++  case 65:
> ++    return "A";
> ++  case 66:
> ++    return "B";
> ++  case 67:
> ++    return "C";
> ++  case 68:
> ++    return "D";
> ++  case 69:
> ++    return "E";
> ++  case 70:
> ++    return "F";
> ++  case 71:
> ++    return "G";
> ++  case 72:
> ++    return "H";
> ++  case 73:
> ++    return "I";
> ++  case 74:
> ++    return "J";
> ++  case 75:
> ++    return "K";
> ++  case 76:
> ++    return "L";
> ++  case 77:
> ++    return "M";
> ++  case 78:
> ++    return "N";
> ++  case 79:
> ++    return "O";
> ++  case 80:
> ++    return "P";
> ++  case 81:
> ++    return "Q";
> ++  case 82:
> ++    return "R";
> ++  case 83:
> ++    return "S";
> ++  case 84:
> ++    return "T";
> ++  case 85:
> ++    return "U";
> ++  case 86:
> ++    return "V";
> ++  case 87:
> ++    return "W";
> ++  case 88:
> ++    return "X";
> ++  case 89:
> ++    return "Y";
> ++  case 90:
> ++    return "Z";
> ++  case 91:
> ++    return "[";
> ++  case 92:
> ++    return "\\\\";
> ++  case 93:
> ++    return "]";
> ++  case 94:
> ++    return "^";
> ++  case 95:
> ++    return "_";
> ++  case 96:
> ++    return "`";
> ++  case 97:
> ++    return "a";
> ++  case 98:
> ++    return "b";
> ++  case 99:
> ++    return "c";
> ++  case 100:
> ++    return "d";
> ++  case 101:
> ++    return "e";
> ++  case 102:
> ++    return "f";
> ++  case 103:
> ++    return "g";
> ++  case 104:
> ++    return "h";
> ++  case 105:
> ++    return "i";
> ++  case 106:
> ++    return "j";
> ++  case 107:
> ++    return "k";
> ++  case 108:
> ++    return "l";
> ++  case 109:
> ++    return "m";
> ++  case 110:
> ++    return "n";
> ++  case 111:
> ++    return "o";
> ++  case 112:
> ++    return "p";
> ++  case 113:
> ++    return "q";
> ++  case 114:
> ++    return "r";
> ++  case 115:
> ++    return "s";
> ++  case 116:
> ++    return "t";
> ++  case 117:
> ++    return "u";
> ++  case 118:
> ++    return "v";
> ++  case 119:
> ++    return "w";
> ++  case 120:
> ++    return "x";
> ++  case 121:
> ++    return "y";
> ++  case 122:
> ++    return "z";
> ++  case 123:
> ++    return "{";
> ++  case 124:
> ++    return "|";
> ++  case 125:
> ++    return "}";
> ++  case 126:
> ++    return "~";
> ++  case 127:
> ++    return "\\x7F";
> ++  case 128:
> ++    return "\\x80";
> ++  case 129:
> ++    return "\\x81";
> ++  case 130:
> ++    return "\\x82";
> ++  case 131:
> ++    return "\\x83";
> ++  case 132:
> ++    return "\\x84";
> ++  case 133:
> ++    return "\\x85";
> ++  case 134:
> ++    return "\\x86";
> ++  case 135:
> ++    return "\\x87";
> ++  case 136:
> ++    return "\\x88";
> ++  case 137:
> ++    return "\\x89";
> ++  case 138:
> ++    return "\\x8A";
> ++  case 139:
> ++    return "\\x8B";
> ++  case 140:
> ++    return "\\x8C";
> ++  case 141:
> ++    return "\\x8D";
> ++  case 142:
> ++    return "\\x8E";
> ++  case 143:
> ++    return "\\x8F";
> ++  case 144:
> ++    return "\\x90";
> ++  case 145:
> ++    return "\\x91";
> ++  case 146:
> ++    return "\\x92";
> ++  case 147:
> ++    return "\\x93";
> ++  case 148:
> ++    return "\\x94";
> ++  case 149:
> ++    return "\\x95";
> ++  case 150:
> ++    return "\\x96";
> ++  case 151:
> ++    return "\\x97";
> ++  case 152:
> ++    return "\\x98";
> ++  case 153:
> ++    return "\\x99";
> ++  case 154:
> ++    return "\\x9A";
> ++  case 155:
> ++    return "\\x9B";
> ++  case 156:
> ++    return "\\x9C";
> ++  case 157:
> ++    return "\\x9D";
> ++  case 158:
> ++    return "\\x9E";
> ++  case 159:
> ++    return "\\x9F";
> ++  case 160:
> ++    return "\\xA0";
> ++  case 161:
> ++    return "\\xA1";
> ++  case 162:
> ++    return "\\xA2";
> ++  case 163:
> ++    return "\\xA3";
> ++  case 164:
> ++    return "\\xA4";
> ++  case 165:
> ++    return "\\xA5";
> ++  case 166:
> ++    return "\\xA6";
> ++  case 167:
> ++    return "\\xA7";
> ++  case 168:
> ++    return "\\xA8";
> ++  case 169:
> ++    return "\\xA9";
> ++  case 170:
> ++    return "\\xAA";
> ++  case 171:
> ++    return "\\xAB";
> ++  case 172:
> ++    return "\\xAC";
> ++  case 173:
> ++    return "\\xAD";
> ++  case 174:
> ++    return "\\xAE";
> ++  case 175:
> ++    return "\\xAF";
> ++  case 176:
> ++    return "\\xB0";
> ++  case 177:
> ++    return "\\xB1";
> ++  case 178:
> ++    return "\\xB2";
> ++  case 179:
> ++    return "\\xB3";
> ++  case 180:
> ++    return "\\xB4";
> ++  case 181:
> ++    return "\\xB5";
> ++  case 182:
> ++    return "\\xB6";
> ++  case 183:
> ++    return "\\xB7";
> ++  case 184:
> ++    return "\\xB8";
> ++  case 185:
> ++    return "\\xB9";
> ++  case 186:
> ++    return "\\xBA";
> ++  case 187:
> ++    return "\\xBB";
> ++  case 188:
> ++    return "\\xBC";
> ++  case 189:
> ++    return "\\xBD";
> ++  case 190:
> ++    return "\\xBE";
> ++  case 191:
> ++    return "\\xBF";
> ++  case 192:
> ++    return "\\xC0";
> ++  case 193:
> ++    return "\\xC1";
> ++  case 194:
> ++    return "\\xC2";
> ++  case 195:
> ++    return "\\xC3";
> ++  case 196:
> ++    return "\\xC4";
> ++  case 197:
> ++    return "\\xC5";
> ++  case 198:
> ++    return "\\xC6";
> ++  case 199:
> ++    return "\\xC7";
> ++  case 200:
> ++    return "\\xC8";
> ++  case 201:
> ++    return "\\xC9";
> ++  case 202:
> ++    return "\\xCA";
> ++  case 203:
> ++    return "\\xCB";
> ++  case 204:
> ++    return "\\xCC";
> ++  case 205:
> ++    return "\\xCD";
> ++  case 206:
> ++    return "\\xCE";
> ++  case 207:
> ++    return "\\xCF";
> ++  case 208:
> ++    return "\\xD0";
> ++  case 209:
> ++    return "\\xD1";
> ++  case 210:
> ++    return "\\xD2";
> ++  case 211:
> ++    return "\\xD3";
> ++  case 212:
> ++    return "\\xD4";
> ++  case 213:
> ++    return "\\xD5";
> ++  case 214:
> ++    return "\\xD6";
> ++  case 215:
> ++    return "\\xD7";
> ++  case 216:
> ++    return "\\xD8";
> ++  case 217:
> ++    return "\\xD9";
> ++  case 218:
> ++    return "\\xDA";
> ++  case 219:
> ++    return "\\xDB";
> ++  case 220:
> ++    return "\\xDC";
> ++  case 221:
> ++    return "\\xDD";
> ++  case 222:
> ++    return "\\xDE";
> ++  case 223:
> ++    return "\\xDF";
> ++  case 224:
> ++    return "\\xE0";
> ++  case 225:
> ++    return "\\xE1";
> ++  case 226:
> ++    return "\\xE2";
> ++  case 227:
> ++    return "\\xE3";
> ++  case 228:
> ++    return "\\xE4";
> ++  case 229:
> ++    return "\\xE5";
> ++  case 230:
> ++    return "\\xE6";
> ++  case 231:
> ++    return "\\xE7";
> ++  case 232:
> ++    return "\\xE8";
> ++  case 233:
> ++    return "\\xE9";
> ++  case 234:
> ++    return "\\xEA";
> ++  case 235:
> ++    return "\\xEB";
> ++  case 236:
> ++    return "\\xEC";
> ++  case 237:
> ++    return "\\xED";
> ++  case 238:
> ++    return "\\xEE";
> ++  case 239:
> ++    return "\\xEF";
> ++  case 240:
> ++    return "\\xF0";
> ++  case 241:
> ++    return "\\xF1";
> ++  case 242:
> ++    return "\\xF2";
> ++  case 243:
> ++    return "\\xF3";
> ++  case 244:
> ++    return "\\xF4";
> ++  case 245:
> ++    return "\\xF5";
> ++  case 246:
> ++    return "\\xF6";
> ++  case 247:
> ++    return "\\xF7";
> ++  case 248:
> ++    return "\\xF8";
> ++  case 249:
> ++    return "\\xF9";
> ++  case 250:
> ++    return "\\xFA";
> ++  case 251:
> ++    return "\\xFB";
> ++  case 252:
> ++    return "\\xFC";
> ++  case 253:
> ++    return "\\xFD";
> ++  case 254:
> ++    return "\\xFE";
> ++  case 255:
> ++    return "\\xFF";
> ++  default:
> ++    assert(0); /* never gets here */
> ++    return "dead code";
> ++  }
> ++  assert(0); /* never gets here */
> ++}
> ++
> ++#endif /* XML_DTD */
> ++
> ++static unsigned long
> ++getDebugLevel(const char *variableName, unsigned long
> defaultDebugLevel) {
> ++  const char *const valueOrNull = getenv(variableName);
> ++  if (valueOrNull == NULL) {
> ++    return defaultDebugLevel;
> ++  }
> ++  const char *const value = valueOrNull;
> ++
> ++  errno = 0;
> ++  char *afterValue = (char *)value;
> ++  unsigned long debugLevel = strtoul(value, &afterValue, 10);
> ++  if ((errno != 0) || (afterValue[0] != '\0')) {
> ++    errno = 0;
> ++    return defaultDebugLevel;
> ++  }
> ++
> ++  return debugLevel;
> ++}
> +-- 
> +2.32.0
> +
> diff --git a/meta/recipes-core/expat/expat_2.2.9.bb b/meta/recipes-
> core/expat/expat_2.2.9.bb
> index 8f3db41352..3af457b2af 100644
> --- a/meta/recipes-core/expat/expat_2.2.9.bb
> +++ b/meta/recipes-core/expat/expat_2.2.9.bb
> @@ -6,8 +6,9 @@ LICENSE = "MIT"
>  
>  LIC_FILES_CHKSUM =
> "file://COPYING;md5=5b8620d98e49772d95fc1d291c26aa79"
>  
> -SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}.tar.bz2 \
> +SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}-RENAMED-
> VULNERABLE-
> PLEASE-USE-2.4.1-INSTEAD.tar.bz2 \
>             file://libtool-tag.patch \
> +           file://0001-expat-Backport-fix-for-CVE-2013-0340.patch \
>           "
>  
>  SRC_URI[md5sum] = "875a2c2ff3e8eb9e5a5cd62db2033ab5"
> 
> 
> 
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKDygACgkQYgqew07V
MNVpHAgAjxDiHJ+0Zl+xxBRKkD3E3bGlKlwsn4MOlP1HWN5zjComuAdnyQwvTmAj
2HRDxGUQ/ZnXUlSDbNzHSgrG2IDa1dlBWGRASRX3YxIXTJ1UL5LWHuprDL2P3xNp
XMaAeX2a86gJKDBA7/XXkrbVuCafjGZ6r0+urvcqpJFO1FR1Qb0aklAe/pEVtEYS
XcN2tWfqeOy9HBOvLIBfFwkRE07oBfr0eWxKzECOq1MPOUYr9k/E4LwqGEWcrOrq
rJM2U07Esu0NkQQSPZXP+NTYO9v5ztZjCLzOb0eI7tGbduW3ay7fOlawfP8fgiON
YVMOzcvA9DFOK7Z3ur3nCL7MWnN3OA==
=JFZY
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
  2021-06-16 14:48 ` [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340 Jasper Orschulko
@ 2021-06-16 15:09   ` Steve Sakoman
  2021-06-16 15:17     ` Jasper Orschulko
  2021-06-16 15:26     ` Jasper Orschulko
  0 siblings, 2 replies; 11+ messages in thread
From: Steve Sakoman @ 2021-06-16 15:09 UTC (permalink / raw)
  To: Jasper Orschulko; +Cc: openembedded-core

On Wed, Jun 16, 2021 at 4:49 AM Jasper Orschulko
<Jasper.Orschulko@iris-sensing.com> wrote:
>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA256
>
> P.S.: I am not too familiar with expat, this particular CVE, not with
> the practise of backporting security patches, so someone(TM) should
> definitely take a closer look at this first.

Will do!

A few initial comments:

1. Please don't PGP sign patch emails :-)
2. Change the patch file name to CVE-2013-0340.patch

Other than that it looks OK at first glance.

For reference the patch requirements for CVE's are outlined at:

https://wiki.yoctoproject.org/wiki/Security

in the "Patch name convention and commit message" section.

Thanks for helping with CVEs!

Steve




> With best regards
>
> Jasper Orschulko
> DevOps Engineer
>
> Tel. +49 30 58 58 14 265
> Fax +49 30 58 58 14 999
> Jasper.Orschulko@iris-sensing.com
>
> • • • • • • • • • • • • • • • • • • • • • • • • • •
>
> iris-GmbH
> infrared & intelligent sensors
> Ostendstraße 1-14 | 12459 Berlin
>
> https://iris-sensing.com/
>
>
>
>
> On Wed, 2021-06-16 at 14:44 +0000, Jasper Orschulko wrote:
> > expat < 4.0 is vulnerable to billion laughs attacks (see
> > [https://github.com/libexpat/libexpat/issues/34]). This patch
> > backports
> > the commits b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> > and 60959f2b491876199879d97c8ed956eabb0c2e73 from upstream.
> >
> > Additionally, the SRC_URI had to be adjusted due to renaming of the
> > source archive
> >
> > Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
> > ---
> >  ...expat-Backport-fix-for-CVE-2013-0340.patch | 1758
> > +++++++++++++++++
> >  meta/recipes-core/expat/expat_2.2.9.bb        |    3 +-
> >  2 files changed, 1760 insertions(+), 1 deletion(-)
> >  create mode 100644 meta/recipes-core/expat/expat/0001-expat-
> > Backport-
> > fix-for-CVE-2013-0340.patch
> >
> > diff --git a/meta/recipes-core/expat/expat/0001-expat-Backport-fix-
> > for-
> > CVE-2013-0340.patch b/meta/recipes-core/expat/expat/0001-expat-
> > Backport-fix-for-CVE-2013-0340.patch
> > new file mode 100644
> > index 0000000000..b2ca066d96
> > --- /dev/null
> > +++ b/meta/recipes-core/expat/expat/0001-expat-Backport-fix-for-CVE-
> > 2013-0340.patch
> > @@ -0,0 +1,1758 @@
> > +From 6f68eb0439f3c1807a143ff8c8972e74d404d8f0 Mon Sep 17 00:00:00
> > 2001
> > +From: Sebastian Pipping <sebastian@pipping.org>
> > +Date: Mon, 19 Apr 2021 21:42:51 +0200
> > +Subject: [PATCH] expat: Backport fix for CVE-2013-0340
> > +
> > +Issue: https://github.com/libexpat/libexpat/issues/34
> > +
> > +This patch cherry-picks the following commits from upstream release
> > +2.4.0 onto 2.2.9:
> > +
> > +- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> > +- 60959f2b491876199879d97c8ed956eabb0c2e73
> > +
> > +Upstream-Status: Backport
> > +CVE: CVE-2013-0340
> > +Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
> > +---
> > + expat/lib/expat.h       |   21 +-
> > + expat/lib/internal.h    |   30 +
> > + expat/lib/libexpat.def  |    3 +
> > + expat/lib/libexpatw.def |    3 +
> > + expat/lib/xmlparse.c    | 1147
> > +++++++++++++++++++++++++++++++++++++-
> > -
> > + 5 files changed, 1143 insertions(+), 61 deletions(-)
> > +
> > +diff --git a/expat/lib/expat.h b/expat/lib/expat.h
> > +index 48a6e2a3..796086c2 100644
> > +--- a/expat/lib/expat.h
> > ++++ b/expat/lib/expat.h
> > +@@ -115,7 +115,9 @@ enum XML_Error {
> > +   XML_ERROR_RESERVED_PREFIX_XMLNS,
> > +   XML_ERROR_RESERVED_NAMESPACE_URI,
> > +   /* Added in 2.2.1. */
> > +-  XML_ERROR_INVALID_ARGUMENT
> > ++  XML_ERROR_INVALID_ARGUMENT,
> > ++  /* Backported from 2.4.0. */
> > ++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
> > + };
> > +
> > + enum XML_Content_Type {
> > +@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
> > +   XML_FEATURE_SIZEOF_XML_LCHAR,
> > +   XML_FEATURE_NS,
> > +   XML_FEATURE_LARGE_SIZE,
> > +-  XML_FEATURE_ATTR_INFO
> > ++  XML_FEATURE_ATTR_INFO,
> > ++  /* Added in Expat 2.4.0. */
> > ++
> > XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DE
> > FA
> > ULT,
> > ++
> > XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEF
> > AU
> > LT
> > +   /* Additional features must be added to the end of this enum. */
> > + };
> > +
> > +@@ -1010,6 +1015,18 @@ typedef struct {
> > + XMLPARSEAPI(const XML_Feature *)
> > + XML_GetFeatureList(void);
> > +
> > ++#ifdef XML_DTD
> > ++/* Backported from Expat 2.4.0. */
> > ++XMLPARSEAPI(XML_Bool)
> > ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> > ++    XML_Parser parser, float maximumAmplificationFactor);
> > ++
> > ++/* Backported from Expat 2.4.0. */
> > ++XMLPARSEAPI(XML_Bool)
> > ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> > ++    XML_Parser parser, unsigned long long
> > activationThresholdBytes);
> > ++#endif
> > ++
> > + /* Expat follows the semantic versioning convention.
> > +    See http://semver.org.
> > + */
> > +diff --git a/expat/lib/internal.h b/expat/lib/internal.h
> > +index 60913dab..d8b31fa2 100644
> > +--- a/expat/lib/internal.h
> > ++++ b/expat/lib/internal.h
> > +@@ -101,10 +101,40 @@
> > + #  endif
> > + #endif
> > +
> > ++#include <limits.h> // ULONG_MAX
> > ++
> > ++#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
> > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
> > ++#  else
> > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> > ++#  endif
> > ++#else
> > ++#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
> > ++#  if ! defined(ULONG_MAX)
> > ++#    error Compiler did not define ULONG_MAX for us
> > ++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
> > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
> > ++#  else
> > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> > ++#  endif
> > ++#endif
> > ++
> > + #ifndef UNUSED_P
> > + #  define UNUSED_P(p) (void)p
> > + #endif
> > +
> > ++/* NOTE BEGIN If you ever patch these defaults to greater values
> > ++              for non-attack XML payload in your environment,
> > ++              please file a bug report with libexpat.  Thank you!
> > ++*/
> > ++#define
> > \
> > ++  100.0f
> > ++#define
> > \
> > ++  8388608 // 8 MiB, 2^23
> > ++/* NOTE END */
> > ++
> > + #ifdef __cplusplus
> > + extern "C" {
> > + #endif
> > +diff --git a/expat/lib/libexpat.def b/expat/lib/libexpat.def
> > +index 16faf595..b5e59d8d 100644
> > +--- a/expat/lib/libexpat.def
> > ++++ b/expat/lib/libexpat.def
> > +@@ -76,3 +76,6 @@ EXPORTS
> > +   XML_SetHashSalt @67
> > + ; added with version 2.2.5
> > +   _INTERNAL_trim_to_complete_utf8_characters @68
> > ++; backported from version 2.4.0
> > ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> > ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
> > +diff --git a/expat/lib/libexpatw.def b/expat/lib/libexpatw.def
> > +index 16faf595..ebd77707 100644
> > +--- a/expat/lib/libexpatw.def
> > ++++ b/expat/lib/libexpatw.def
> > +@@ -76,3 +76,6 @@ EXPORTS
> > +   XML_SetHashSalt @67
> > + ; added with version 2.2.5
> > +   _INTERNAL_trim_to_complete_utf8_characters @68
> > ++; backported from version 2.4.0
> > ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> > ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @7
> > +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
> > +index 3aaf35b9..fdcc7296 100644
> > +--- a/expat/lib/xmlparse.c
> > ++++ b/expat/lib/xmlparse.c
> > +@@ -47,6 +47,8 @@
> > + #include <limits.h> /* UINT_MAX */
> > + #include <stdio.h>  /* fprintf */
> > + #include <stdlib.h> /* getenv, rand_s */
> > ++#include <stdint.h> /* uintptr_t */
> > ++#include <math.h>   /* isnan */
> > +
> > + #ifdef _WIN32
> > + #  define getpid GetCurrentProcessId
> > +@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
> > +   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
> > + } OPEN_INTERNAL_ENTITY;
> > +
> > ++enum XML_Account {
> > ++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the
> > Expat
> > parser */
> > ++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced
> > during
> > entity
> > ++                                   expansion */
> > ++  XML_ACCOUNT_NONE              /* i.e. do not account, was
> > accounted
> > already */
> > ++};
> > ++
> > ++#ifdef XML_DTD
> > ++typedef unsigned long long XmlBigCount;
> > ++typedef struct accounting {
> > ++  XmlBigCount countBytesDirect;
> > ++  XmlBigCount countBytesIndirect;
> > ++  int debugLevel;
> > ++  float maximumAmplificationFactor; // >=1.0
> > ++  unsigned long long activationThresholdBytes;
> > ++} ACCOUNTING;
> > ++
> > ++typedef struct entity_stats {
> > ++  unsigned int countEverOpened;
> > ++  unsigned int currentDepth;
> > ++  unsigned int maximumDepthSeen;
> > ++  int debugLevel;
> > ++} ENTITY_STATS;
> > ++#endif /* XML_DTD */
> > ++
> > + typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const
> > char *start,
> > +                                          const char *end, const
> > char
> > **endPtr);
> > +
> > +@@ -403,16 +430,18 @@ static enum XML_Error
> > initializeEncoding(XML_Parser parser);
> > + static enum XML_Error doProlog(XML_Parser parser, const ENCODING
> > *enc,
> > +                                const char *s, const char *end, int
> > tok,
> > +                                const char *next, const char
> > **nextPtr,
> > +-                               XML_Bool haveMore, XML_Bool
> > allowClosingDoctype);
> > ++                               XML_Bool haveMore, XML_Bool
> > allowClosingDoctype,
> > ++                               enum XML_Account account);
> > + static enum XML_Error processInternalEntity(XML_Parser parser,
> > ENTITY
> > *entity,
> > +                                             XML_Bool betweenDecl);
> > + static enum XML_Error doContent(XML_Parser parser, int
> > startTagLevel,
> > +                                 const ENCODING *enc, const char
> > *start,
> > +                                 const char *end, const char
> > **endPtr,
> > +-                                XML_Bool haveMore);
> > ++                                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,
> > +@@ -422,7 +451,8 @@ static enum XML_Error doIgnoreSection(XML_Parser
> > parser, const ENCODING *,
> > + static void freeBindings(XML_Parser parser, BINDING *bindings);
> > + static enum XML_Error storeAtts(XML_Parser parser, const ENCODING
> > *,
> > +                                 const char *s, TAG_NAME
> > *tagNamePtr,
> > +-                                BINDING **bindingsPtr);
> > ++                                BINDING **bindingsPtr,
> > ++                                enum XML_Account account);
> > + static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
> > +                                  const ATTRIBUTE_ID *attId, const
> > XML_Char *uri,
> > +                                  BINDING **bindingsPtr);
> > +@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE *type,
> > ATTRIBUTE_ID *, XML_Bool isCdata,
> > +                            XML_Parser parser);
> > + static enum XML_Error storeAttributeValue(XML_Parser parser, const
> > ENCODING *,
> > +                                           XML_Bool isCdata, const
> > char *,
> > +-                                          const char *, STRING_POOL
> > *);
> > ++                                          const char *, STRING_POOL
> > *,
> > ++                                          enum XML_Account
> > account);
> > + static enum XML_Error appendAttributeValue(XML_Parser parser, const
> > ENCODING *,
> > +                                            XML_Bool isCdata, const
> > char *,
> > +-                                           const char *,
> > STRING_POOL
> > *);
> > ++                                           const char *,
> > STRING_POOL
> > *,
> > ++                                           enum XML_Account
> > account);
> > + static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const
> > ENCODING
> > *enc,
> > +                                     const char *start, const char
> > *end);
> > + static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
> > + static enum XML_Error storeEntityValue(XML_Parser parser, const
> > ENCODING *enc,
> > +-                                       const char *start, const
> > char
> > *end);
> > ++                                       const char *start, const
> > char
> > *end,
> > ++                                       enum XML_Account account);
> > + static int reportProcessingInstruction(XML_Parser parser, const
> > ENCODING *enc,
> > +                                        const char *start, const
> > char
> > *end);
> > + static int reportComment(XML_Parser parser, const ENCODING *enc,
> > +@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const XML_Char
> > *encodingName,
> > +
> > + static void parserInit(XML_Parser parser, const XML_Char
> > *encodingName);
> > +
> > ++#ifdef XML_DTD
> > ++static float accountingGetCurrentAmplification(XML_Parser
> > rootParser);
> > ++static void accountingReportStats(XML_Parser originParser, const
> > char
> > *epilog);
> > ++static void accountingOnAbort(XML_Parser originParser);
> > ++static void accountingReportDiff(XML_Parser rootParser,
> > ++                                 unsigned int
> > levelsAwayFromRootParser,
> > ++                                 const char *before, const char
> > *after,
> > ++                                 ptrdiff_t bytesMore, int
> > source_line,
> > ++                                 enum XML_Account account);
> > ++static XML_Bool accountingDiffTolerated(XML_Parser originParser,
> > int
> > tok,
> > ++                                        const char *before, const
> > char *after,
> > ++                                        int source_line,
> > ++                                        enum XML_Account account);
> > ++
> > ++static void entityTrackingReportStats(XML_Parser parser, ENTITY
> > *entity,
> > ++                                      const char *action, int
> > sourceLine);
> > ++static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
> > ++                                 int sourceLine);
> > ++static void entityTrackingOnClose(XML_Parser parser, ENTITY
> > *entity,
> > ++                                  int sourceLine);
> > ++
> > ++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,
> > ++                                   unsigned long
> > defaultDebugLevel);
> > ++
> > + #define poolStart(pool) ((pool)->start)
> > + #define poolEnd(pool) ((pool)->ptr)
> > + #define poolLength(pool) ((pool)->ptr - (pool)->start)
> > +@@ -616,6 +678,10 @@ struct XML_ParserStruct {
> > +   enum XML_ParamEntityParsing m_paramEntityParsing;
> > + #endif
> > +   unsigned long m_hash_secret_salt;
> > ++#ifdef XML_DTD
> > ++  ACCOUNTING m_accounting;
> > ++  ENTITY_STATS m_entity_stats;
> > ++#endif
> > + };
> > +
> > + #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
> > +@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const XML_Char
> > *encodingName) {
> > +   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
> > + #endif
> > +   parser->m_hash_secret_salt = 0;
> > ++
> > ++#ifdef XML_DTD
> > ++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
> > ++  parser->m_accounting.debugLevel =
> > getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
> > ++  parser->m_accounting.maximumAmplificationFactor
> > ++      =
> > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
> > ++  parser->m_accounting.activationThresholdBytes
> > ++      =
> > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
> > ++
> > ++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
> > ++  parser->m_entity_stats.debugLevel =
> > getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
> > ++#endif
> > + }
> > +
> > + /* moves list of bindings to m_freeBindingList */
> > +@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
> > +   /* Added in 2.2.5. */
> > +   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1,
> > already */
> > +     return XML_L("invalid argument");
> > ++  /* Backported from 2.4.0. */
> > ++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
> > ++    return XML_L(
> > ++        "limit on input amplification factor (from DTD and
> > entities)
> > breached");
> > +   }
> > +   return NULL;
> > + }
> > +@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
> > +
> > + const XML_Feature *XMLCALL
> > + XML_GetFeatureList(void) {
> > +-  static const XML_Feature features[]
> > +-      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
> > +-          sizeof(XML_Char)},
> > +-         {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
> > +-          sizeof(XML_LChar)},
> > ++  static const XML_Feature features[] = {
> > ++      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
> > ++       sizeof(XML_Char)},
> > ++      {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
> > ++       sizeof(XML_LChar)},
> > + #ifdef XML_UNICODE
> > +-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> > ++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> > + #endif
> > + #ifdef XML_UNICODE_WCHAR_T
> > +-         {XML_FEATURE_UNICODE_WCHAR_T,
> > XML_L("XML_UNICODE_WCHAR_T"),
> > 0},
> > ++      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"),
> > 0},
> > + #endif
> > + #ifdef XML_DTD
> > +-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> > ++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> > + #endif
> > + #ifdef XML_CONTEXT_BYTES
> > +-         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
> > +-          XML_CONTEXT_BYTES},
> > ++      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
> > ++       XML_CONTEXT_BYTES},
> > + #endif
> > + #ifdef XML_MIN_SIZE
> > +-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> > ++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> > + #endif
> > + #ifdef XML_NS
> > +-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> > ++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> > + #endif
> > + #ifdef XML_LARGE_SIZE
> > +-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> > ++      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> > + #endif
> > + #ifdef XML_ATTR_INFO
> > +-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> > ++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> > + #endif
> > +-         {XML_FEATURE_END, NULL, 0}};
> > ++#ifdef XML_DTD
> > ++      /* Added in Expat 2.4.0. */
> > ++
> > {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_D
> > EF
> > AULT,
> > ++       XML_L("XML_BLAP_MAX_AMP"),
> > ++       (long int)
> > ++
> > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT}
> > ,
> > ++
> > {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DE
> > FA
> > ULT,
> > ++       XML_L("XML_BLAP_ACT_THRES"),
> > ++
> > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
> > ++#endif
> > ++      {XML_FEATURE_END, NULL, 0}};
> > +
> > +   return features;
> > + }
> > +
> > ++#ifdef XML_DTD
> > ++XML_Bool XMLCALL
> > ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> > ++    XML_Parser parser, float maximumAmplificationFactor) {
> > ++  if ((parser == NULL) || (parser->m_parentParser != NULL)
> > ++      || isnan(maximumAmplificationFactor)
> > ++      || (maximumAmplificationFactor < 1.0f)) {
> > ++    return XML_FALSE;
> > ++  }
> > ++  parser->m_accounting.maximumAmplificationFactor =
> > maximumAmplificationFactor;
> > ++  return XML_TRUE;
> > ++}
> > ++
> > ++XML_Bool XMLCALL
> > ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> > ++    XML_Parser parser, unsigned long long activationThresholdBytes)
> > {
> > ++  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
> > ++    return XML_FALSE;
> > ++  }
> > ++  parser->m_accounting.activationThresholdBytes =
> > activationThresholdBytes;
> > ++  return XML_TRUE;
> > ++}
> > ++#endif /* XML_DTD */
> > ++
> > + /* Initially tag->rawName always points into the parse buffer;
> > +    for those TAG instances opened while the current parse buffer
> > was
> > +    processed, and not yet closed, we need to store tag->rawName in
> > a
> > more
> > +@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
> > + static enum XML_Error PTRCALL
> > + contentProcessor(XML_Parser parser, const char *start, const char
> > *end,
> > +                  const char **endPtr) {
> > +-  enum XML_Error result
> > +-      = doContent(parser, 0, parser->m_encoding, start, end,
> > endPtr,
> > +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
> > ++  enum XML_Error result = doContent(
> > ++      parser, 0, parser->m_encoding, start, end, endPtr,
> > ++      (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> > XML_ACCOUNT_DIRECT);
> > +   if (result == XML_ERROR_NONE) {
> > +     if (! storeRawNames(parser))
> > +       return XML_ERROR_NO_MEMORY;
> > +@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser
> > parser,
> > const char *start,
> > +   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
> > +   switch (tok) {
> > +   case XML_TOK_BOM:
> > ++#ifdef XML_DTD
> > ++    if (! accountingDiffTolerated(parser, tok, start, next,
> > __LINE__,
> > ++                                  XML_ACCOUNT_DIRECT)) {
> > ++      accountingOnAbort(parser);
> > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > ++    }
> > ++#endif /* XML_DTD */
> > ++
> > +     /* If we are at the end of the buffer, this would cause the
> > next
> > stage,
> > +        i.e. externalEntityInitProcessor3, to pass control directly
> > to
> > +        doContent (by detecting XML_TOK_NONE) without processing any
> > xml text
> > +@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser
> > parser,
> > const char *start,
> > +   const char *next = start; /* XmlContentTok doesn't always set the
> > last arg */
> > +   parser->m_eventPtr = start;
> > +   tok = XmlContentTok(parser->m_encoding, start, end, &next);
> > ++  /* Note: These bytes are accounted later in:
> > ++           - processXmlDecl
> > ++           - externalEntityContentProcessor
> > ++  */
> > +   parser->m_eventEndPtr = next;
> > +
> > +   switch (tok) {
> > +@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser
> > parser, const char *start,
> > +                                const char *end, const char
> > **endPtr)
> > {
> > +   enum XML_Error result
> > +       = doContent(parser, 1, parser->m_encoding, start, end,
> > endPtr,
> > +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
> > ++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> > ++                  XML_ACCOUNT_ENTITY_EXPANSION);
> > +   if (result == XML_ERROR_NONE) {
> > +     if (! storeRawNames(parser))
> > +       return XML_ERROR_NO_MEMORY;
> > +@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser
> > parser, const char *start,
> > + static enum XML_Error
> > + doContent(XML_Parser parser, int startTagLevel, const ENCODING
> > *enc,
> > +           const char *s, const char *end, const char **nextPtr,
> > +-          XML_Bool haveMore) {
> > ++          XML_Bool haveMore, enum XML_Account account) {
> > +   /* save one level of indirection */
> > +   DTD *const dtd = parser->m_dtd;
> > +
> > +@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int
> > startTagLevel,
> > const ENCODING *enc,
> > +   for (;;) {
> > +     const char *next = s; /* XmlContentTok doesn't always set the
> > last arg */
> > +     int tok = XmlContentTok(enc, s, end, &next);
> > ++#ifdef XML_DTD
> > ++    const char *accountAfter
> > ++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok ==
> > XML_TOK_TRAILING_CR))
> > ++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
> > ++              : next;
> > ++    if (! accountingDiffTolerated(parser, tok, s, accountAfter,
> > __LINE__,
> > ++                                  account)) {
> > ++      accountingOnAbort(parser);
> > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > ++    }
> > ++#endif
> > +     *eventEndPP = next;
> > +     switch (tok) {
> > +     case XML_TOK_TRAILING_CR:
> > +@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int
> > startTagLevel,
> > const ENCODING *enc,
> > +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> > +           enc, s + enc->minBytesPerChar, next - enc-
> > > minBytesPerChar);
> > +       if (ch) {
> > ++#ifdef XML_DTD
> > ++        /* NOTE: We are replacing 4-6 characters original input for
> > 1
> > character
> > ++         *       so there is no amplification and hence recording
> > without
> > ++         *       protection. */
> > ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> > ++                                ((char *)&ch) + sizeof(XML_Char),
> > __LINE__,
> > ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> > ++#endif /* XML_DTD */
> > +         if (parser->m_characterDataHandler)
> > +           parser->m_characterDataHandler(parser->m_handlerArg, &ch,
> > 1);
> > +         else if (parser->m_defaultHandler)
> > +@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int
> > startTagLevel,
> > const ENCODING *enc,
> > +       }
> > +       tag->name.str = (XML_Char *)tag->buf;
> > +       *toPtr = XML_T('\0');
> > +-      result = storeAtts(parser, enc, s, &(tag->name), &(tag-
> > > bindings));
> > ++      result
> > ++          = storeAtts(parser, enc, s, &(tag->name), &(tag-
> > >bindings),
> > account);
> > +       if (result)
> > +         return result;
> > +       if (parser->m_startElementHandler)
> > +@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int
> > startTagLevel,
> > const ENCODING *enc,
> > +       if (! name.str)
> > +         return XML_ERROR_NO_MEMORY;
> > +       poolFinish(&parser->m_tempPool);
> > +-      result = storeAtts(parser, enc, s, &name, &bindings);
> > ++      result = storeAtts(parser, enc, s, &name, &bindings,
> > ++                         XML_ACCOUNT_NONE /* token spans whole
> > start
> > tag */);
> > +       if (result != XML_ERROR_NONE) {
> > +         freeBindings(parser, bindings);
> > +         return result;
> > +@@ -2907,7 +3057,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) {
> > +@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING
> > *bindings) {
> > + */
> > + static enum XML_Error
> > + storeAtts(XML_Parser parser, const ENCODING *enc, const char
> > *attStr,
> > +-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
> > ++          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
> > ++          enum XML_Account account) {
> > +   DTD *const dtd = parser->m_dtd; /* save one level of indirection
> > */
> > +   ELEMENT_TYPE *elementType;
> > +   int nDefaultAtts;
> > +@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const ENCODING
> > *enc, const char *attStr,
> > +       /* normalize the attribute value */
> > +       result = storeAttributeValue(
> > +           parser, enc, isCdata, parser->m_atts[i].valuePtr,
> > +-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
> > ++          parser->m_atts[i].valueEnd, &parser->m_tempPool,
> > account);
> > +       if (result)
> > +         return result;
> > +       appAtts[attIndex] = poolStart(&parser->m_tempPool);
> > +@@ -3535,9 +3687,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) {
> > +@@ -3557,7 +3709,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;
> > +@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const
> > ENCODING *enc, const char **startPtr,
> > +   for (;;) {
> > +     const char *next;
> > +     int tok = XmlCdataSectionTok(enc, s, end, &next);
> > ++#ifdef XML_DTD
> > ++    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) {
> > +     case XML_TOK_CDATA_SECT_CLOSE:
> > +@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const
> > ENCODING *enc, const char **startPtr,
> > +   *eventPP = s;
> > +   *startPtr = NULL;
> > +   tok = XmlIgnoreSectionTok(enc, s, end, &next);
> > ++#  ifdef XML_DTD
> > ++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> > ++                                XML_ACCOUNT_DIRECT)) {
> > ++    accountingOnAbort(parser);
> > ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > ++  }
> > ++#  endif
> > +   *eventEndPP = next;
> > +   switch (tok) {
> > +   case XML_TOK_IGNORE_SECT:
> > +@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int
> > isGeneralTextEntity, const char *s,
> > +   const char *versionend;
> > +   const XML_Char *storedversion = NULL;
> > +   int standalone = -1;
> > ++
> > ++#ifdef XML_DTD
> > ++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next,
> > __LINE__,
> > ++                                XML_ACCOUNT_DIRECT)) {
> > ++    accountingOnAbort(parser);
> > ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > ++  }
> > ++#endif
> > ++
> > +   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
> > +           isGeneralTextEntity, parser->m_encoding, s, next,
> > &parser-
> > > m_eventPtr,
> > +           &version, &versionend, &encodingName, &newEncoding,
> > &standalone)) {
> > +@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser parser,
> > const char *s, const char *end,
> > +
> > +   for (;;) {
> > +     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
> > ++    /* Note: Except for XML_TOK_BOM below, these bytes are
> > accounted
> > later in:
> > ++             - storeEntityValue
> > ++             - processXmlDecl
> > ++    */
> > +     parser->m_eventEndPtr = next;
> > +     if (tok <= 0) {
> > +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> > XML_TOK_INVALID) {
> > +@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser parser,
> > const char *s, const char *end,
> > +         break;
> > +       }
> > +       /* found end of entity value - can store it now */
> > +-      return storeEntityValue(parser, parser->m_encoding, s, end);
> > ++      return storeEntityValue(parser, parser->m_encoding, s, end,
> > ++                              XML_ACCOUNT_DIRECT);
> > +     } else if (tok == XML_TOK_XML_DECL) {
> > +       enum XML_Error result;
> > +       result = processXmlDecl(parser, 0, start, next);
> > +@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser parser,
> > const char *s, const char *end,
> > +     */
> > +     else if (tok == XML_TOK_BOM && next == end
> > +              && ! parser->m_parsingStatus.finalBuffer) {
> > ++#  ifdef XML_DTD
> > ++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> > ++                                    XML_ACCOUNT_DIRECT)) {
> > ++        accountingOnAbort(parser);
> > ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > ++      }
> > ++#  endif
> > ++
> > +       *nextPtr = next;
> > +       return XML_ERROR_NONE;
> > +     }
> > +@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser parser,
> > const char *s, const char *end,
> > +   }
> > +   /* This would cause the next stage, i.e. doProlog to be passed
> > XML_TOK_BOM.
> > +      However, when parsing an external subset, doProlog will not
> > accept a BOM
> > +-     as valid, and report a syntax error, so we have to skip the
> > BOM
> > ++     as valid, and report a syntax error, so we have to skip the
> > BOM,
> > and
> > ++     account for the BOM bytes.
> > +   */
> > +   else if (tok == XML_TOK_BOM) {
> > ++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> > ++                                  XML_ACCOUNT_DIRECT)) {
> > ++      accountingOnAbort(parser);
> > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > ++    }
> > ++
> > +     s = next;
> > +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > +   }
> > +
> > +   parser->m_processor = prologProcessor;
> > +   return doProlog(parser, parser->m_encoding, s, end, tok, next,
> > nextPtr,
> > +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> > XML_TRUE);
> > ++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> > XML_TRUE,
> > ++                  XML_ACCOUNT_DIRECT);
> > + }
> > +
> > + static enum XML_Error PTRCALL
> > +@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser, const
> > char *s, const char *end,
> > +
> > +   for (;;) {
> > +     tok = XmlPrologTok(enc, start, end, &next);
> > ++    /* Note: These bytes are accounted later in:
> > ++             - storeEntityValue
> > ++    */
> > +     if (tok <= 0) {
> > +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> > XML_TOK_INVALID) {
> > +         *nextPtr = s;
> > +@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser, const
> > char *s, const char *end,
> > +         break;
> > +       }
> > +       /* found end of entity value - can store it now */
> > +-      return storeEntityValue(parser, enc, s, end);
> > ++      return storeEntityValue(parser, enc, s, end,
> > XML_ACCOUNT_DIRECT);
> > +     }
> > +     start = next;
> > +   }
> > +@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const
> > char
> > *s, const char *end,
> > +   const char *next = s;
> > +   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > +   return doProlog(parser, parser->m_encoding, s, end, tok, next,
> > nextPtr,
> > +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> > XML_TRUE);
> > ++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> > XML_TRUE,
> > ++                  XML_ACCOUNT_DIRECT);
> > + }
> > +
> > + static enum XML_Error
> > + doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
> > const
> > char *end,
> > +          int tok, const char *next, const char **nextPtr, XML_Bool
> > haveMore,
> > +-         XML_Bool allowClosingDoctype) {
> > ++         XML_Bool allowClosingDoctype, enum XML_Account account) {
> > + #ifdef XML_DTD
> > +   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
> > + #endif /* XML_DTD */
> > +@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const ENCODING
> > *enc, const char *s, const char *end,
> > +   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
> > +   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
> > +
> > ++#ifndef XML_DTD
> > ++  UNUSED_P(account);
> > ++#endif
> > ++
> > +   /* save one level of indirection */
> > +   DTD *const dtd = parser->m_dtd;
> > +
> > +@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const ENCODING
> > *enc, const char *s, const char *end,
> > +       }
> > +     }
> > +     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
> > ++#ifdef XML_DTD
> > ++    switch (role) {
> > ++    case XML_ROLE_INSTANCE_START: // bytes accounted in
> > contentProcessor
> > ++    case XML_ROLE_XML_DECL:       // bytes accounted in
> > processXmlDecl
> > ++    case XML_ROLE_TEXT_DECL:      // bytes accounted in
> > processXmlDecl
> > ++      break;
> > ++    default:
> > ++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> > account)) {
> > ++        accountingOnAbort(parser);
> > ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > ++      }
> > ++    }
> > ++#endif
> > +     switch (role) {
> > +     case XML_ROLE_XML_DECL: {
> > +       enum XML_Error result = processXmlDecl(parser, 0, s, next);
> > +@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING
> > *enc,
> > const char *s, const char *end,
> > +         const XML_Char *attVal;
> > +         enum XML_Error result = storeAttributeValue(
> > +             parser, enc, parser->m_declAttributeIsCdata,
> > +-            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
> > &dtd->pool);
> > ++            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
> > &dtd->pool,
> > ++            XML_ACCOUNT_NONE);
> > +         if (result)
> > +           return result;
> > +         attVal = poolStart(&dtd->pool);
> > +@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING
> > *enc,
> > const char *s, const char *end,
> > +       break;
> > +     case XML_ROLE_ENTITY_VALUE:
> > +       if (dtd->keepProcessing) {
> > +-        enum XML_Error result = storeEntityValue(
> > +-            parser, enc, s + enc->minBytesPerChar, next - enc-
> > > minBytesPerChar);
> > ++        enum XML_Error result
> > ++            = storeEntityValue(parser, enc, s + enc-
> > >minBytesPerChar,
> > ++                               next - enc->minBytesPerChar,
> > XML_ACCOUNT_NONE);
> > +         if (parser->m_declEntity) {
> > +           parser->m_declEntity->textPtr = poolStart(&dtd-
> > > entityValuePool);
> > +           parser->m_declEntity->textLen
> > +@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const ENCODING
> > *enc, const char *s, const char *end,
> > +         if (parser->m_externalEntityRefHandler) {
> > +           dtd->paramEntityRead = XML_FALSE;
> > +           entity->open = XML_TRUE;
> > ++          entityTrackingOnOpen(parser, entity, __LINE__);
> > +           if (! parser->m_externalEntityRefHandler(
> > +                   parser->m_externalEntityRefHandlerArg, 0, entity-
> > > base,
> > +                   entity->systemId, entity->publicId)) {
> > ++            entityTrackingOnClose(parser, entity, __LINE__);
> > +             entity->open = XML_FALSE;
> > +             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> > +           }
> > ++          entityTrackingOnClose(parser, entity, __LINE__);
> > +           entity->open = XML_FALSE;
> > +           handleDefault = XML_FALSE;
> > +           if (! dtd->paramEntityRead) {
> > +@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const char
> > *s, const char *end,
> > +   for (;;) {
> > +     const char *next = NULL;
> > +     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > ++#ifdef XML_DTD
> > ++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> > ++                                  XML_ACCOUNT_DIRECT)) {
> > ++      accountingOnAbort(parser);
> > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > ++    }
> > ++#endif
> > +     parser->m_eventEndPtr = next;
> > +     switch (tok) {
> > +     /* report partial linebreak - it might be the last token */
> > +@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser,
> > ENTITY
> > *entity, XML_Bool betweenDecl) {
> > +       return XML_ERROR_NO_MEMORY;
> > +   }
> > +   entity->open = XML_TRUE;
> > ++#ifdef XML_DTD
> > ++  entityTrackingOnOpen(parser, entity, __LINE__);
> > ++#endif
> > +   entity->processed = 0;
> > +   openEntity->next = parser->m_openInternalEntities;
> > +   parser->m_openInternalEntities = openEntity;
> > +@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser,
> > ENTITY *entity, XML_Bool betweenDecl) {
> > +     int tok
> > +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> > textEnd, &next);
> > +     result = doProlog(parser, parser->m_internalEncoding,
> > textStart,
> > textEnd,
> > +-                      tok, next, &next, XML_FALSE, XML_FALSE);
> > ++                      tok, next, &next, XML_FALSE, XML_FALSE,
> > ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> > +   } else
> > + #endif /* XML_DTD */
> > +     result = doContent(parser, parser->m_tagLevel, parser-
> > > m_internalEncoding,
> > +-                       textStart, textEnd, &next, XML_FALSE);
> > ++                       textStart, textEnd, &next, XML_FALSE,
> > ++                       XML_ACCOUNT_ENTITY_EXPANSION);
> > +
> > +   if (result == XML_ERROR_NONE) {
> > +     if (textEnd != next && parser->m_parsingStatus.parsing ==
> > XML_SUSPENDED) {
> > +       entity->processed = (int)(next - textStart);
> > +       parser->m_processor = internalEntityProcessor;
> > +     } else {
> > ++#ifdef XML_DTD
> > ++      entityTrackingOnClose(parser, entity, __LINE__);
> > ++#endif /* XML_DTD */
> > +       entity->open = XML_FALSE;
> > +       parser->m_openInternalEntities = openEntity->next;
> > +       /* put openEntity back in list of free instances */
> > +@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser parser,
> > const char *s, const char *end,
> > +     int tok
> > +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> > textEnd, &next);
> > +     result = doProlog(parser, parser->m_internalEncoding,
> > textStart,
> > textEnd,
> > +-                      tok, next, &next, XML_FALSE, XML_TRUE);
> > ++                      tok, next, &next, XML_FALSE, XML_TRUE,
> > ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> > +   } else
> > + #endif /* XML_DTD */
> > +     result = doContent(parser, openEntity->startTagLevel,
> > +                        parser->m_internalEncoding, textStart,
> > textEnd, &next,
> > +-                       XML_FALSE);
> > ++                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
> > +
> > +   if (result != XML_ERROR_NONE)
> > +     return result;
> > +@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser,
> > const
> > char *s, const char *end,
> > +     entity->processed = (int)(next - (char *)entity->textPtr);
> > +     return result;
> > +   } else {
> > ++#ifdef XML_DTD
> > ++    entityTrackingOnClose(parser, entity, __LINE__);
> > ++#endif
> > +     entity->open = XML_FALSE;
> > +     parser->m_openInternalEntities = openEntity->next;
> > +     /* put openEntity back in list of free instances */
> > +@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser,
> > const
> > char *s, const char *end,
> > +     parser->m_processor = prologProcessor;
> > +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > +     return doProlog(parser, parser->m_encoding, s, end, tok, next,
> > nextPtr,
> > +-                    (XML_Bool)! parser-
> > >m_parsingStatus.finalBuffer,
> > XML_TRUE);
> > ++                    (XML_Bool)! parser-
> > >m_parsingStatus.finalBuffer,
> > XML_TRUE,
> > ++                    XML_ACCOUNT_DIRECT);
> > +   } else
> > + #endif /* XML_DTD */
> > +   {
> > +@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser,
> > const
> > char *s, const char *end,
> > +     /* see externalEntityContentProcessor vs contentProcessor */
> > +     return doContent(parser, parser->m_parentParser ? 1 : 0,
> > parser-
> > > m_encoding,
> > +                      s, end, nextPtr,
> > +-                     (XML_Bool)! parser-
> > > m_parsingStatus.finalBuffer);
> > ++                     (XML_Bool)! parser-
> > >m_parsingStatus.finalBuffer,
> > ++                     XML_ACCOUNT_DIRECT);
> > +   }
> > + }
> > +
> > +@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const char
> > *s, const char *end,
> > +
> > + static enum XML_Error
> > + storeAttributeValue(XML_Parser parser, const ENCODING *enc,
> > XML_Bool
> > isCdata,
> > +-                    const char *ptr, const char *end, STRING_POOL
> > *pool) {
> > ++                    const char *ptr, const char *end, STRING_POOL
> > *pool,
> > ++                    enum XML_Account account) {
> > +   enum XML_Error result
> > +-      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
> > ++      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool,
> > account);
> > +   if (result)
> > +     return result;
> > +   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
> > +@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser, const
> > ENCODING *enc, XML_Bool isCdata,
> > +
> > + static enum XML_Error
> > + appendAttributeValue(XML_Parser parser, const ENCODING *enc,
> > XML_Bool
> > isCdata,
> > +-                     const char *ptr, const char *end, STRING_POOL
> > *pool) {
> > ++                     const char *ptr, const char *end, STRING_POOL
> > *pool,
> > ++                     enum XML_Account account) {
> > +   DTD *const dtd = parser->m_dtd; /* save one level of indirection
> > */
> > ++#ifndef XML_DTD
> > ++  UNUSED_P(account);
> > ++#endif
> > ++
> > +   for (;;) {
> > +     const char *next;
> > +     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
> > ++#ifdef XML_DTD
> > ++    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__,
> > account)) {
> > ++      accountingOnAbort(parser);
> > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > ++    }
> > ++#endif
> > +     switch (tok) {
> > +     case XML_TOK_NONE:
> > +       return XML_ERROR_NONE;
> > +@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser, const
> > ENCODING *enc, XML_Bool isCdata,
> > +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> > +           enc, ptr + enc->minBytesPerChar, next - enc-
> > > minBytesPerChar);
> > +       if (ch) {
> > ++#ifdef XML_DTD
> > ++        /* NOTE: We are replacing 4-6 characters original input for
> > 1
> > character
> > ++         *       so there is no amplification and hence recording
> > without
> > ++         *       protection. */
> > ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> > ++                                ((char *)&ch) + sizeof(XML_Char),
> > __LINE__,
> > ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> > ++#endif /* XML_DTD */
> > +         if (! poolAppendChar(pool, ch))
> > +           return XML_ERROR_NO_MEMORY;
> > +         break;
> > +@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser, const
> > ENCODING *enc, XML_Bool isCdata,
> > +         enum XML_Error result;
> > +         const XML_Char *textEnd = entity->textPtr + entity-
> > >textLen;
> > +         entity->open = XML_TRUE;
> > ++#ifdef XML_DTD
> > ++        entityTrackingOnOpen(parser, entity, __LINE__);
> > ++#endif
> > +         result = appendAttributeValue(parser, parser-
> > > m_internalEncoding,
> > +-                                      isCdata, (char *)entity-
> > > textPtr,
> > +-                                      (char *)textEnd, pool);
> > ++                                      isCdata, (const char
> > *)entity-
> > > textPtr,
> > ++                                      (const char *)textEnd, pool,
> > ++
> > XML_ACCOUNT_ENTITY_EXPANSION);
> > ++#ifdef XML_DTD
> > ++        entityTrackingOnClose(parser, entity, __LINE__);
> > ++#endif
> > +         entity->open = XML_FALSE;
> > +         if (result)
> > +           return result;
> > +@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser,
> > const
> > ENCODING *enc, XML_Bool isCdata,
> > +
> > + static enum XML_Error
> > + storeEntityValue(XML_Parser parser, const ENCODING *enc,
> > +-                 const char *entityTextPtr, const char
> > *entityTextEnd) {
> > ++                 const char *entityTextPtr, const char
> > *entityTextEnd,
> > ++                 enum XML_Account account) {
> > +   DTD *const dtd = parser->m_dtd; /* save one level of indirection
> > */
> > +   STRING_POOL *pool = &(dtd->entityValuePool);
> > +   enum XML_Error result = XML_ERROR_NONE;
> > + #ifdef XML_DTD
> > +   int oldInEntityValue = parser->m_prologState.inEntityValue;
> > +   parser->m_prologState.inEntityValue = 1;
> > ++#else
> > ++  UNUSED_P(account);
> > + #endif /* XML_DTD */
> > +   /* never return Null for the value argument in EntityDeclHandler,
> > +      since this would indicate an external entity; therefore we
> > +@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const
> > ENCODING *enc,
> > +   for (;;) {
> > +     const char *next;
> > +     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd,
> > &next);
> > ++
> > ++#ifdef XML_DTD
> > ++    if (! accountingDiffTolerated(parser, tok, entityTextPtr, next,
> > __LINE__,
> > ++                                  account)) {
> > ++      accountingOnAbort(parser);
> > ++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > ++      goto endEntityValue;
> > ++    }
> > ++#endif
> > ++
> > +     switch (tok) {
> > +     case XML_TOK_PARAM_ENTITY_REF:
> > + #ifdef XML_DTD
> > +@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser, const
> > ENCODING *enc,
> > +           if (parser->m_externalEntityRefHandler) {
> > +             dtd->paramEntityRead = XML_FALSE;
> > +             entity->open = XML_TRUE;
> > ++            entityTrackingOnOpen(parser, entity, __LINE__);
> > +             if (! parser->m_externalEntityRefHandler(
> > +                     parser->m_externalEntityRefHandlerArg, 0,
> > entity-
> > > base,
> > +                     entity->systemId, entity->publicId)) {
> > ++              entityTrackingOnClose(parser, entity, __LINE__);
> > +               entity->open = XML_FALSE;
> > +               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> > +               goto endEntityValue;
> > +             }
> > ++            entityTrackingOnClose(parser, entity, __LINE__);
> > +             entity->open = XML_FALSE;
> > +             if (! dtd->paramEntityRead)
> > +               dtd->keepProcessing = dtd->standalone;
> > +@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const
> > ENCODING *enc,
> > +             dtd->keepProcessing = dtd->standalone;
> > +         } else {
> > +           entity->open = XML_TRUE;
> > ++          entityTrackingOnOpen(parser, entity, __LINE__);
> > +           result = storeEntityValue(
> > +-              parser, parser->m_internalEncoding, (char *)entity-
> > > textPtr,
> > +-              (char *)(entity->textPtr + entity->textLen));
> > ++              parser, parser->m_internalEncoding, (const char
> > *)entity->textPtr,
> > ++              (const char *)(entity->textPtr + entity->textLen),
> > ++              XML_ACCOUNT_ENTITY_EXPANSION);
> > ++          entityTrackingOnClose(parser, entity, __LINE__);
> > +           entity->open = XML_FALSE;
> > +           if (result)
> > +             goto endEntityValue;
> > +@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const
> > XML_Memory_Handling_Suite *memsuite) {
> > +   memcpy(result, s, charsRequired * sizeof(XML_Char));
> > +   return result;
> > + }
> > ++
> > ++#ifdef XML_DTD
> > ++
> > ++static float
> > ++accountingGetCurrentAmplification(XML_Parser rootParser) {
> > ++  const XmlBigCount countBytesOutput
> > ++      = rootParser->m_accounting.countBytesDirect
> > ++        + rootParser->m_accounting.countBytesIndirect;
> > ++  const float amplificationFactor
> > ++      = rootParser->m_accounting.countBytesDirect
> > ++            ? (countBytesOutput
> > ++               / (float)(rootParser-
> > >m_accounting.countBytesDirect))
> > ++            : 1.0f;
> > ++  assert(! rootParser->m_parentParser);
> > ++  return amplificationFactor;
> > ++}
> > ++
> > ++static void
> > ++accountingReportStats(XML_Parser originParser, const char *epilog)
> > {
> > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > NULL);
> > ++  assert(! rootParser->m_parentParser);
> > ++
> > ++  if (rootParser->m_accounting.debugLevel < 1) {
> > ++    return;
> > ++  }
> > ++
> > ++  const float amplificationFactor
> > ++      = accountingGetCurrentAmplification(rootParser);
> > ++  fprintf(stderr,
> > ++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
> > ++              "10") ", indirect " EXPAT_FMT_ULL("10") ",
> > amplification %8.2f%s",
> > ++          (void *)rootParser, rootParser-
> > > m_accounting.countBytesDirect,
> > ++          rootParser->m_accounting.countBytesIndirect,
> > ++          (double)amplificationFactor, epilog);
> > ++}
> > ++
> > ++static void
> > ++accountingOnAbort(XML_Parser originParser) {
> > ++  accountingReportStats(originParser, " ABORTING\n");
> > ++}
> > ++
> > ++static void
> > ++accountingReportDiff(XML_Parser rootParser,
> > ++                     unsigned int levelsAwayFromRootParser, const
> > char *before,
> > ++                     const char *after, ptrdiff_t bytesMore, int
> > source_line,
> > ++                     enum XML_Account account) {
> > ++  assert(! rootParser->m_parentParser);
> > ++
> > ++  fprintf(stderr,
> > ++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d,
> > xmlparse.c:%d) %*s\"",
> > ++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" :
> > "EXP",
> > ++          levelsAwayFromRootParser, source_line, 10, "");
> > ++
> > ++  const char ellipis[] = "[..]";
> > ++  const size_t ellipsisLength = sizeof(ellipis) /* because compile-
> > time */ - 1;
> > ++  const unsigned int contextLength = 10;
> > ++
> > ++  /* Note: Performance is of no concern here */
> > ++  const char *walker = before;
> > ++  if ((rootParser->m_accounting.debugLevel >= 3)
> > ++      || (after - before)
> > ++             <= (ptrdiff_t)(contextLength + ellipsisLength +
> > contextLength)) {
> > ++    for (; walker < after; walker++) {
> > ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> > ++    }
> > ++  } else {
> > ++    for (; walker < before + contextLength; walker++) {
> > ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> > ++    }
> > ++    fprintf(stderr, ellipis);
> > ++    walker = after - contextLength;
> > ++    for (; walker < after; walker++) {
> > ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> > ++    }
> > ++  }
> > ++  fprintf(stderr, "\"\n");
> > ++}
> > ++
> > ++static XML_Bool
> > ++accountingDiffTolerated(XML_Parser originParser, int tok, const
> > char
> > *before,
> > ++                        const char *after, int source_line,
> > ++                        enum XML_Account account) {
> > ++  /* Note: We need to check the token type *first* to be sure that
> > ++   *       we can even access variable <after>, safely.
> > ++   *       E.g. for XML_TOK_NONE <after> may hold an invalid
> > pointer.
> > */
> > ++  switch (tok) {
> > ++  case XML_TOK_INVALID:
> > ++  case XML_TOK_PARTIAL:
> > ++  case XML_TOK_PARTIAL_CHAR:
> > ++  case XML_TOK_NONE:
> > ++    return XML_TRUE;
> > ++  }
> > ++
> > ++  if (account == XML_ACCOUNT_NONE)
> > ++    return XML_TRUE; /* because these bytes have been accounted
> > for,
> > already */
> > ++
> > ++  unsigned int levelsAwayFromRootParser;
> > ++  const XML_Parser rootParser
> > ++      = getRootParserOf(originParser, &levelsAwayFromRootParser);
> > ++  assert(! rootParser->m_parentParser);
> > ++
> > ++  const int isDirect
> > ++      = (account == XML_ACCOUNT_DIRECT) && (originParser ==
> > rootParser);
> > ++  const ptrdiff_t bytesMore = after - before;
> > ++
> > ++  XmlBigCount *const additionTarget
> > ++      = isDirect ? &rootParser->m_accounting.countBytesDirect
> > ++                 : &rootParser->m_accounting.countBytesIndirect;
> > ++
> > ++  /* Detect and avoid integer overflow */
> > ++  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
> > ++    return XML_FALSE;
> > ++  *additionTarget += bytesMore;
> > ++
> > ++  const XmlBigCount countBytesOutput
> > ++      = rootParser->m_accounting.countBytesDirect
> > ++        + rootParser->m_accounting.countBytesIndirect;
> > ++  const float amplificationFactor
> > ++      = accountingGetCurrentAmplification(rootParser);
> > ++  const XML_Bool tolerated
> > ++      = (countBytesOutput < rootParser-
> > > m_accounting.activationThresholdBytes)
> > ++        || (amplificationFactor
> > ++            <= rootParser-
> > >m_accounting.maximumAmplificationFactor);
> > ++
> > ++  if (rootParser->m_accounting.debugLevel >= 2) {
> > ++    accountingReportStats(rootParser, "");
> > ++    accountingReportDiff(rootParser, levelsAwayFromRootParser,
> > before, after,
> > ++                         bytesMore, source_line, account);
> > ++  }
> > ++
> > ++  return tolerated;
> > ++}
> > ++
> > ++static void
> > ++entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
> > ++                          const char *action, int sourceLine) {
> > ++  assert(! rootParser->m_parentParser);
> > ++  if (rootParser->m_entity_stats.debugLevel < 1)
> > ++    return;
> > ++
> > ++#  if defined(XML_UNICODE)
> > ++  const char *const entityName = "[..]";
> > ++#  else
> > ++  const char *const entityName = entity->name;
> > ++#  endif
> > ++
> > ++  fprintf(
> > ++      stderr,
> > ++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s
> > length %d (xmlparse.c:%d)\n",
> > ++      (void *)rootParser, rootParser-
> > >m_entity_stats.countEverOpened,
> > ++      rootParser->m_entity_stats.currentDepth,
> > ++      rootParser->m_entity_stats.maximumDepthSeen,
> > ++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
> > ++      entity->is_param ? "%" : "&", entityName, action, entity-
> > > textLen,
> > ++      sourceLine);
> > ++}
> > ++
> > ++static void
> > ++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int
> > sourceLine) {
> > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > NULL);
> > ++  assert(! rootParser->m_parentParser);
> > ++
> > ++  rootParser->m_entity_stats.countEverOpened++;
> > ++  rootParser->m_entity_stats.currentDepth++;
> > ++  if (rootParser->m_entity_stats.currentDepth
> > ++      > rootParser->m_entity_stats.maximumDepthSeen) {
> > ++    rootParser->m_entity_stats.maximumDepthSeen++;
> > ++  }
> > ++
> > ++  entityTrackingReportStats(rootParser, entity, "OPEN ",
> > sourceLine);
> > ++}
> > ++
> > ++static void
> > ++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int
> > sourceLine) {
> > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > NULL);
> > ++  assert(! rootParser->m_parentParser);
> > ++
> > ++  entityTrackingReportStats(rootParser, entity, "CLOSE",
> > sourceLine);
> > ++  rootParser->m_entity_stats.currentDepth--;
> > ++}
> > ++
> > ++static XML_Parser
> > ++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
> > ++  XML_Parser rootParser = parser;
> > ++  unsigned int stepsTakenUpwards = 0;
> > ++  while (rootParser->m_parentParser) {
> > ++    rootParser = rootParser->m_parentParser;
> > ++    stepsTakenUpwards++;
> > ++  }
> > ++  assert(! rootParser->m_parentParser);
> > ++  if (outLevelDiff != NULL) {
> > ++    *outLevelDiff = stepsTakenUpwards;
> > ++  }
> > ++  return rootParser;
> > ++}
> > ++
> > ++static const char *
> > ++unsignedCharToPrintable(unsigned char c) {
> > ++  switch (c) {
> > ++  case 0:
> > ++    return "\\0";
> > ++  case 1:
> > ++    return "\\x1";
> > ++  case 2:
> > ++    return "\\x2";
> > ++  case 3:
> > ++    return "\\x3";
> > ++  case 4:
> > ++    return "\\x4";
> > ++  case 5:
> > ++    return "\\x5";
> > ++  case 6:
> > ++    return "\\x6";
> > ++  case 7:
> > ++    return "\\x7";
> > ++  case 8:
> > ++    return "\\x8";
> > ++  case 9:
> > ++    return "\\t";
> > ++  case 10:
> > ++    return "\\n";
> > ++  case 11:
> > ++    return "\\xB";
> > ++  case 12:
> > ++    return "\\xC";
> > ++  case 13:
> > ++    return "\\r";
> > ++  case 14:
> > ++    return "\\xE";
> > ++  case 15:
> > ++    return "\\xF";
> > ++  case 16:
> > ++    return "\\x10";
> > ++  case 17:
> > ++    return "\\x11";
> > ++  case 18:
> > ++    return "\\x12";
> > ++  case 19:
> > ++    return "\\x13";
> > ++  case 20:
> > ++    return "\\x14";
> > ++  case 21:
> > ++    return "\\x15";
> > ++  case 22:
> > ++    return "\\x16";
> > ++  case 23:
> > ++    return "\\x17";
> > ++  case 24:
> > ++    return "\\x18";
> > ++  case 25:
> > ++    return "\\x19";
> > ++  case 26:
> > ++    return "\\x1A";
> > ++  case 27:
> > ++    return "\\x1B";
> > ++  case 28:
> > ++    return "\\x1C";
> > ++  case 29:
> > ++    return "\\x1D";
> > ++  case 30:
> > ++    return "\\x1E";
> > ++  case 31:
> > ++    return "\\x1F";
> > ++  case 32:
> > ++    return " ";
> > ++  case 33:
> > ++    return "!";
> > ++  case 34:
> > ++    return "\\\"";
> > ++  case 35:
> > ++    return "#";
> > ++  case 36:
> > ++    return "$";
> > ++  case 37:
> > ++    return "%";
> > ++  case 38:
> > ++    return "&";
> > ++  case 39:
> > ++    return "'";
> > ++  case 40:
> > ++    return "(";
> > ++  case 41:
> > ++    return ")";
> > ++  case 42:
> > ++    return "*";
> > ++  case 43:
> > ++    return "+";
> > ++  case 44:
> > ++    return ",";
> > ++  case 45:
> > ++    return "-";
> > ++  case 46:
> > ++    return ".";
> > ++  case 47:
> > ++    return "/";
> > ++  case 48:
> > ++    return "0";
> > ++  case 49:
> > ++    return "1";
> > ++  case 50:
> > ++    return "2";
> > ++  case 51:
> > ++    return "3";
> > ++  case 52:
> > ++    return "4";
> > ++  case 53:
> > ++    return "5";
> > ++  case 54:
> > ++    return "6";
> > ++  case 55:
> > ++    return "7";
> > ++  case 56:
> > ++    return "8";
> > ++  case 57:
> > ++    return "9";
> > ++  case 58:
> > ++    return ":";
> > ++  case 59:
> > ++    return ";";
> > ++  case 60:
> > ++    return "<";
> > ++  case 61:
> > ++    return "=";
> > ++  case 62:
> > ++    return ">";
> > ++  case 63:
> > ++    return "?";
> > ++  case 64:
> > ++    return "@";
> > ++  case 65:
> > ++    return "A";
> > ++  case 66:
> > ++    return "B";
> > ++  case 67:
> > ++    return "C";
> > ++  case 68:
> > ++    return "D";
> > ++  case 69:
> > ++    return "E";
> > ++  case 70:
> > ++    return "F";
> > ++  case 71:
> > ++    return "G";
> > ++  case 72:
> > ++    return "H";
> > ++  case 73:
> > ++    return "I";
> > ++  case 74:
> > ++    return "J";
> > ++  case 75:
> > ++    return "K";
> > ++  case 76:
> > ++    return "L";
> > ++  case 77:
> > ++    return "M";
> > ++  case 78:
> > ++    return "N";
> > ++  case 79:
> > ++    return "O";
> > ++  case 80:
> > ++    return "P";
> > ++  case 81:
> > ++    return "Q";
> > ++  case 82:
> > ++    return "R";
> > ++  case 83:
> > ++    return "S";
> > ++  case 84:
> > ++    return "T";
> > ++  case 85:
> > ++    return "U";
> > ++  case 86:
> > ++    return "V";
> > ++  case 87:
> > ++    return "W";
> > ++  case 88:
> > ++    return "X";
> > ++  case 89:
> > ++    return "Y";
> > ++  case 90:
> > ++    return "Z";
> > ++  case 91:
> > ++    return "[";
> > ++  case 92:
> > ++    return "\\\\";
> > ++  case 93:
> > ++    return "]";
> > ++  case 94:
> > ++    return "^";
> > ++  case 95:
> > ++    return "_";
> > ++  case 96:
> > ++    return "`";
> > ++  case 97:
> > ++    return "a";
> > ++  case 98:
> > ++    return "b";
> > ++  case 99:
> > ++    return "c";
> > ++  case 100:
> > ++    return "d";
> > ++  case 101:
> > ++    return "e";
> > ++  case 102:
> > ++    return "f";
> > ++  case 103:
> > ++    return "g";
> > ++  case 104:
> > ++    return "h";
> > ++  case 105:
> > ++    return "i";
> > ++  case 106:
> > ++    return "j";
> > ++  case 107:
> > ++    return "k";
> > ++  case 108:
> > ++    return "l";
> > ++  case 109:
> > ++    return "m";
> > ++  case 110:
> > ++    return "n";
> > ++  case 111:
> > ++    return "o";
> > ++  case 112:
> > ++    return "p";
> > ++  case 113:
> > ++    return "q";
> > ++  case 114:
> > ++    return "r";
> > ++  case 115:
> > ++    return "s";
> > ++  case 116:
> > ++    return "t";
> > ++  case 117:
> > ++    return "u";
> > ++  case 118:
> > ++    return "v";
> > ++  case 119:
> > ++    return "w";
> > ++  case 120:
> > ++    return "x";
> > ++  case 121:
> > ++    return "y";
> > ++  case 122:
> > ++    return "z";
> > ++  case 123:
> > ++    return "{";
> > ++  case 124:
> > ++    return "|";
> > ++  case 125:
> > ++    return "}";
> > ++  case 126:
> > ++    return "~";
> > ++  case 127:
> > ++    return "\\x7F";
> > ++  case 128:
> > ++    return "\\x80";
> > ++  case 129:
> > ++    return "\\x81";
> > ++  case 130:
> > ++    return "\\x82";
> > ++  case 131:
> > ++    return "\\x83";
> > ++  case 132:
> > ++    return "\\x84";
> > ++  case 133:
> > ++    return "\\x85";
> > ++  case 134:
> > ++    return "\\x86";
> > ++  case 135:
> > ++    return "\\x87";
> > ++  case 136:
> > ++    return "\\x88";
> > ++  case 137:
> > ++    return "\\x89";
> > ++  case 138:
> > ++    return "\\x8A";
> > ++  case 139:
> > ++    return "\\x8B";
> > ++  case 140:
> > ++    return "\\x8C";
> > ++  case 141:
> > ++    return "\\x8D";
> > ++  case 142:
> > ++    return "\\x8E";
> > ++  case 143:
> > ++    return "\\x8F";
> > ++  case 144:
> > ++    return "\\x90";
> > ++  case 145:
> > ++    return "\\x91";
> > ++  case 146:
> > ++    return "\\x92";
> > ++  case 147:
> > ++    return "\\x93";
> > ++  case 148:
> > ++    return "\\x94";
> > ++  case 149:
> > ++    return "\\x95";
> > ++  case 150:
> > ++    return "\\x96";
> > ++  case 151:
> > ++    return "\\x97";
> > ++  case 152:
> > ++    return "\\x98";
> > ++  case 153:
> > ++    return "\\x99";
> > ++  case 154:
> > ++    return "\\x9A";
> > ++  case 155:
> > ++    return "\\x9B";
> > ++  case 156:
> > ++    return "\\x9C";
> > ++  case 157:
> > ++    return "\\x9D";
> > ++  case 158:
> > ++    return "\\x9E";
> > ++  case 159:
> > ++    return "\\x9F";
> > ++  case 160:
> > ++    return "\\xA0";
> > ++  case 161:
> > ++    return "\\xA1";
> > ++  case 162:
> > ++    return "\\xA2";
> > ++  case 163:
> > ++    return "\\xA3";
> > ++  case 164:
> > ++    return "\\xA4";
> > ++  case 165:
> > ++    return "\\xA5";
> > ++  case 166:
> > ++    return "\\xA6";
> > ++  case 167:
> > ++    return "\\xA7";
> > ++  case 168:
> > ++    return "\\xA8";
> > ++  case 169:
> > ++    return "\\xA9";
> > ++  case 170:
> > ++    return "\\xAA";
> > ++  case 171:
> > ++    return "\\xAB";
> > ++  case 172:
> > ++    return "\\xAC";
> > ++  case 173:
> > ++    return "\\xAD";
> > ++  case 174:
> > ++    return "\\xAE";
> > ++  case 175:
> > ++    return "\\xAF";
> > ++  case 176:
> > ++    return "\\xB0";
> > ++  case 177:
> > ++    return "\\xB1";
> > ++  case 178:
> > ++    return "\\xB2";
> > ++  case 179:
> > ++    return "\\xB3";
> > ++  case 180:
> > ++    return "\\xB4";
> > ++  case 181:
> > ++    return "\\xB5";
> > ++  case 182:
> > ++    return "\\xB6";
> > ++  case 183:
> > ++    return "\\xB7";
> > ++  case 184:
> > ++    return "\\xB8";
> > ++  case 185:
> > ++    return "\\xB9";
> > ++  case 186:
> > ++    return "\\xBA";
> > ++  case 187:
> > ++    return "\\xBB";
> > ++  case 188:
> > ++    return "\\xBC";
> > ++  case 189:
> > ++    return "\\xBD";
> > ++  case 190:
> > ++    return "\\xBE";
> > ++  case 191:
> > ++    return "\\xBF";
> > ++  case 192:
> > ++    return "\\xC0";
> > ++  case 193:
> > ++    return "\\xC1";
> > ++  case 194:
> > ++    return "\\xC2";
> > ++  case 195:
> > ++    return "\\xC3";
> > ++  case 196:
> > ++    return "\\xC4";
> > ++  case 197:
> > ++    return "\\xC5";
> > ++  case 198:
> > ++    return "\\xC6";
> > ++  case 199:
> > ++    return "\\xC7";
> > ++  case 200:
> > ++    return "\\xC8";
> > ++  case 201:
> > ++    return "\\xC9";
> > ++  case 202:
> > ++    return "\\xCA";
> > ++  case 203:
> > ++    return "\\xCB";
> > ++  case 204:
> > ++    return "\\xCC";
> > ++  case 205:
> > ++    return "\\xCD";
> > ++  case 206:
> > ++    return "\\xCE";
> > ++  case 207:
> > ++    return "\\xCF";
> > ++  case 208:
> > ++    return "\\xD0";
> > ++  case 209:
> > ++    return "\\xD1";
> > ++  case 210:
> > ++    return "\\xD2";
> > ++  case 211:
> > ++    return "\\xD3";
> > ++  case 212:
> > ++    return "\\xD4";
> > ++  case 213:
> > ++    return "\\xD5";
> > ++  case 214:
> > ++    return "\\xD6";
> > ++  case 215:
> > ++    return "\\xD7";
> > ++  case 216:
> > ++    return "\\xD8";
> > ++  case 217:
> > ++    return "\\xD9";
> > ++  case 218:
> > ++    return "\\xDA";
> > ++  case 219:
> > ++    return "\\xDB";
> > ++  case 220:
> > ++    return "\\xDC";
> > ++  case 221:
> > ++    return "\\xDD";
> > ++  case 222:
> > ++    return "\\xDE";
> > ++  case 223:
> > ++    return "\\xDF";
> > ++  case 224:
> > ++    return "\\xE0";
> > ++  case 225:
> > ++    return "\\xE1";
> > ++  case 226:
> > ++    return "\\xE2";
> > ++  case 227:
> > ++    return "\\xE3";
> > ++  case 228:
> > ++    return "\\xE4";
> > ++  case 229:
> > ++    return "\\xE5";
> > ++  case 230:
> > ++    return "\\xE6";
> > ++  case 231:
> > ++    return "\\xE7";
> > ++  case 232:
> > ++    return "\\xE8";
> > ++  case 233:
> > ++    return "\\xE9";
> > ++  case 234:
> > ++    return "\\xEA";
> > ++  case 235:
> > ++    return "\\xEB";
> > ++  case 236:
> > ++    return "\\xEC";
> > ++  case 237:
> > ++    return "\\xED";
> > ++  case 238:
> > ++    return "\\xEE";
> > ++  case 239:
> > ++    return "\\xEF";
> > ++  case 240:
> > ++    return "\\xF0";
> > ++  case 241:
> > ++    return "\\xF1";
> > ++  case 242:
> > ++    return "\\xF2";
> > ++  case 243:
> > ++    return "\\xF3";
> > ++  case 244:
> > ++    return "\\xF4";
> > ++  case 245:
> > ++    return "\\xF5";
> > ++  case 246:
> > ++    return "\\xF6";
> > ++  case 247:
> > ++    return "\\xF7";
> > ++  case 248:
> > ++    return "\\xF8";
> > ++  case 249:
> > ++    return "\\xF9";
> > ++  case 250:
> > ++    return "\\xFA";
> > ++  case 251:
> > ++    return "\\xFB";
> > ++  case 252:
> > ++    return "\\xFC";
> > ++  case 253:
> > ++    return "\\xFD";
> > ++  case 254:
> > ++    return "\\xFE";
> > ++  case 255:
> > ++    return "\\xFF";
> > ++  default:
> > ++    assert(0); /* never gets here */
> > ++    return "dead code";
> > ++  }
> > ++  assert(0); /* never gets here */
> > ++}
> > ++
> > ++#endif /* XML_DTD */
> > ++
> > ++static unsigned long
> > ++getDebugLevel(const char *variableName, unsigned long
> > defaultDebugLevel) {
> > ++  const char *const valueOrNull = getenv(variableName);
> > ++  if (valueOrNull == NULL) {
> > ++    return defaultDebugLevel;
> > ++  }
> > ++  const char *const value = valueOrNull;
> > ++
> > ++  errno = 0;
> > ++  char *afterValue = (char *)value;
> > ++  unsigned long debugLevel = strtoul(value, &afterValue, 10);
> > ++  if ((errno != 0) || (afterValue[0] != '\0')) {
> > ++    errno = 0;
> > ++    return defaultDebugLevel;
> > ++  }
> > ++
> > ++  return debugLevel;
> > ++}
> > +--
> > +2.32.0
> > +
> > diff --git a/meta/recipes-core/expat/expat_2.2.9.bb b/meta/recipes-
> > core/expat/expat_2.2.9.bb
> > index 8f3db41352..3af457b2af 100644
> > --- a/meta/recipes-core/expat/expat_2.2.9.bb
> > +++ b/meta/recipes-core/expat/expat_2.2.9.bb
> > @@ -6,8 +6,9 @@ LICENSE = "MIT"
> >
> >  LIC_FILES_CHKSUM =
> > "file://COPYING;md5=5b8620d98e49772d95fc1d291c26aa79"
> >
> > -SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}.tar.bz2 \
> > +SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}-RENAMED-
> > VULNERABLE-
> > PLEASE-USE-2.4.1-INSTEAD.tar.bz2 \
> >             file://libtool-tag.patch \
> > +           file://0001-expat-Backport-fix-for-CVE-2013-0340.patch \
> >           "
> >
> >  SRC_URI[md5sum] = "875a2c2ff3e8eb9e5a5cd62db2033ab5"
> >
> >
> >
> -----BEGIN PGP SIGNATURE-----
>
> iQEzBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKDygACgkQYgqew07V
> MNVpHAgAjxDiHJ+0Zl+xxBRKkD3E3bGlKlwsn4MOlP1HWN5zjComuAdnyQwvTmAj
> 2HRDxGUQ/ZnXUlSDbNzHSgrG2IDa1dlBWGRASRX3YxIXTJ1UL5LWHuprDL2P3xNp
> XMaAeX2a86gJKDBA7/XXkrbVuCafjGZ6r0+urvcqpJFO1FR1Qb0aklAe/pEVtEYS
> XcN2tWfqeOy9HBOvLIBfFwkRE07oBfr0eWxKzECOq1MPOUYr9k/E4LwqGEWcrOrq
> rJM2U07Esu0NkQQSPZXP+NTYO9v5ztZjCLzOb0eI7tGbduW3ay7fOlawfP8fgiON
> YVMOzcvA9DFOK7Z3ur3nCL7MWnN3OA==
> =JFZY
> -----END PGP SIGNATURE-----
>
> 
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
  2021-06-16 15:09   ` Steve Sakoman
@ 2021-06-16 15:17     ` Jasper Orschulko
  2021-06-16 16:15       ` Steve Sakoman
  2021-06-16 15:26     ` Jasper Orschulko
  1 sibling, 1 reply; 11+ messages in thread
From: Jasper Orschulko @ 2021-06-16 15:17 UTC (permalink / raw)
  To: steve; +Cc: openembedded-core

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hi Steve!

Thanks for the quick feedback! I just noticed that the archive folder
structure from sourceforge differs to to the git content, thus the
"inner" patch currently fails. Oops!

I'm thinking about setting the git repository as SRC_URI, as the expat
project is currently moving away from sourceforge towards github. Also,
we would not be affected by random archive renaming ;) What do you
think?

- -- 
With best regards

Jasper Orschulko
DevOps Engineer

Tel. +49 30 58 58 14 265
Fax +49 30 58 58 14 999
Jasper.Orschulko@iris-sensing.com

• • • • • • • • • • • • • • • • • • • • • • • • • •

iris-GmbH
infrared & intelligent sensors
Ostendstraße 1-14 | 12459 Berlin

https://iris-sensing.com/




On Wed, 2021-06-16 at 05:09 -1000, Steve Sakoman wrote:
> On Wed, Jun 16, 2021 at 4:49 AM Jasper Orschulko
> <Jasper.Orschulko@iris-sensing.com> wrote:
> > 
> > -----BEGIN PGP SIGNED MESSAGE-----
> > Hash: SHA256
> > 
> > P.S.: I am not too familiar with expat, this particular CVE, not
> > with
> > the practise of backporting security patches, so someone(TM) should
> > definitely take a closer look at this first.
> 
> Will do!
> 
> A few initial comments:
> 
> 1. Please don't PGP sign patch emails :-)
> 2. Change the patch file name to CVE-2013-0340.patch
> 
> Other than that it looks OK at first glance.
> 
> For reference the patch requirements for CVE's are outlined at:
> 
> https://wiki.yoctoproject.org/wiki/Security
> 
> in the "Patch name convention and commit message" section.
> 
> Thanks for helping with CVEs!
> 
> Steve
> 
> 
> 
> 
> > With best regards
> > 
> > Jasper Orschulko
> > DevOps Engineer
> > 
> > Tel. +49 30 58 58 14 265
> > Fax +49 30 58 58 14 999
> > Jasper.Orschulko@iris-sensing.com
> > 
> > • • • • • • • • • • • • • • • • • • • • • • • • • •
> > 
> > iris-GmbH
> > infrared & intelligent sensors
> > Ostendstraße 1-14 | 12459 Berlin
> > 
> > https://iris-sensing.com/
> > 
> > 
> > 
> > 
> > On Wed, 2021-06-16 at 14:44 +0000, Jasper Orschulko wrote:
> > > expat < 4.0 is vulnerable to billion laughs attacks (see
> > > [https://github.com/libexpat/libexpat/issues/34]). This patch
> > > backports
> > > the commits b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> > > and 60959f2b491876199879d97c8ed956eabb0c2e73 from upstream.
> > > 
> > > Additionally, the SRC_URI had to be adjusted due to renaming of
> > > the
> > > source archive
> > > 
> > > Signed-off-by: Jasper Orschulko
> > > <Jasper.Orschulko@iris-sensing.com>
> > > ---
> > >  ...expat-Backport-fix-for-CVE-2013-0340.patch | 1758
> > > +++++++++++++++++
> > >  meta/recipes-core/expat/expat_2.2.9.bb        |    3 +-
> > >  2 files changed, 1760 insertions(+), 1 deletion(-)
> > >  create mode 100644 meta/recipes-core/expat/expat/0001-expat-
> > > Backport-
> > > fix-for-CVE-2013-0340.patch
> > > 
> > > diff --git a/meta/recipes-core/expat/expat/0001-expat-Backport-
> > > fix-
> > > for-
> > > CVE-2013-0340.patch b/meta/recipes-core/expat/expat/0001-expat-
> > > Backport-fix-for-CVE-2013-0340.patch
> > > new file mode 100644
> > > index 0000000000..b2ca066d96
> > > --- /dev/null
> > > +++ b/meta/recipes-core/expat/expat/0001-expat-Backport-fix-for-
> > > CVE-
> > > 2013-0340.patch
> > > @@ -0,0 +1,1758 @@
> > > +From 6f68eb0439f3c1807a143ff8c8972e74d404d8f0 Mon Sep 17
> > > 00:00:00
> > > 2001
> > > +From: Sebastian Pipping <sebastian@pipping.org>
> > > +Date: Mon, 19 Apr 2021 21:42:51 +0200
> > > +Subject: [PATCH] expat: Backport fix for CVE-2013-0340
> > > +
> > > +Issue: https://github.com/libexpat/libexpat/issues/34
> > > +
> > > +This patch cherry-picks the following commits from upstream
> > > release
> > > +2.4.0 onto 2.2.9:
> > > +
> > > +- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> > > +- 60959f2b491876199879d97c8ed956eabb0c2e73
> > > +
> > > +Upstream-Status: Backport
> > > +CVE: CVE-2013-0340
> > > +Signed-off-by: Jasper Orschulko
> > > <Jasper.Orschulko@iris-sensing.com>
> > > +---
> > > + expat/lib/expat.h       |   21 +-
> > > + expat/lib/internal.h    |   30 +
> > > + expat/lib/libexpat.def  |    3 +
> > > + expat/lib/libexpatw.def |    3 +
> > > + expat/lib/xmlparse.c    | 1147
> > > +++++++++++++++++++++++++++++++++++++-
> > > -
> > > + 5 files changed, 1143 insertions(+), 61 deletions(-)
> > > +
> > > +diff --git a/expat/lib/expat.h b/expat/lib/expat.h
> > > +index 48a6e2a3..796086c2 100644
> > > +--- a/expat/lib/expat.h
> > > ++++ b/expat/lib/expat.h
> > > +@@ -115,7 +115,9 @@ enum XML_Error {
> > > +   XML_ERROR_RESERVED_PREFIX_XMLNS,
> > > +   XML_ERROR_RESERVED_NAMESPACE_URI,
> > > +   /* Added in 2.2.1. */
> > > +-  XML_ERROR_INVALID_ARGUMENT
> > > ++  XML_ERROR_INVALID_ARGUMENT,
> > > ++  /* Backported from 2.4.0. */
> > > ++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
> > > + };
> > > +
> > > + enum XML_Content_Type {
> > > +@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
> > > +   XML_FEATURE_SIZEOF_XML_LCHAR,
> > > +   XML_FEATURE_NS,
> > > +   XML_FEATURE_LARGE_SIZE,
> > > +-  XML_FEATURE_ATTR_INFO
> > > ++  XML_FEATURE_ATTR_INFO,
> > > ++  /* Added in Expat 2.4.0. */
> > > ++
> > > XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATIO
> > > N_DE
> > > FA
> > > ULT,
> > > ++
> > > XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD
> > > _DEF
> > > AU
> > > LT
> > > +   /* Additional features must be added to the end of this enum.
> > > */
> > > + };
> > > +
> > > +@@ -1010,6 +1015,18 @@ typedef struct {
> > > + XMLPARSEAPI(const XML_Feature *)
> > > + XML_GetFeatureList(void);
> > > +
> > > ++#ifdef XML_DTD
> > > ++/* Backported from Expat 2.4.0. */
> > > ++XMLPARSEAPI(XML_Bool)
> > > ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> > > ++    XML_Parser parser, float maximumAmplificationFactor);
> > > ++
> > > ++/* Backported from Expat 2.4.0. */
> > > ++XMLPARSEAPI(XML_Bool)
> > > ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> > > ++    XML_Parser parser, unsigned long long
> > > activationThresholdBytes);
> > > ++#endif
> > > ++
> > > + /* Expat follows the semantic versioning convention.
> > > +    See http://semver.org.
> > > + */
> > > +diff --git a/expat/lib/internal.h b/expat/lib/internal.h
> > > +index 60913dab..d8b31fa2 100644
> > > +--- a/expat/lib/internal.h
> > > ++++ b/expat/lib/internal.h
> > > +@@ -101,10 +101,40 @@
> > > + #  endif
> > > + #endif
> > > +
> > > ++#include <limits.h> // ULONG_MAX
> > > ++
> > > ++#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
> > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
> > > ++#  else
> > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> > > ++#  endif
> > > ++#else
> > > ++#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
> > > ++#  if ! defined(ULONG_MAX)
> > > ++#    error Compiler did not define ULONG_MAX for us
> > > ++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
> > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
> > > ++#  else
> > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> > > ++#  endif
> > > ++#endif
> > > ++
> > > + #ifndef UNUSED_P
> > > + #  define UNUSED_P(p) (void)p
> > > + #endif
> > > +
> > > ++/* NOTE BEGIN If you ever patch these defaults to greater
> > > values
> > > ++              for non-attack XML payload in your environment,
> > > ++              please file a bug report with libexpat.  Thank
> > > you!
> > > ++*/
> > > ++#define
> > > \
> > > ++  100.0f
> > > ++#define
> > > \
> > > ++  8388608 // 8 MiB, 2^23
> > > ++/* NOTE END */
> > > ++
> > > + #ifdef __cplusplus
> > > + extern "C" {
> > > + #endif
> > > +diff --git a/expat/lib/libexpat.def b/expat/lib/libexpat.def
> > > +index 16faf595..b5e59d8d 100644
> > > +--- a/expat/lib/libexpat.def
> > > ++++ b/expat/lib/libexpat.def
> > > +@@ -76,3 +76,6 @@ EXPORTS
> > > +   XML_SetHashSalt @67
> > > + ; added with version 2.2.5
> > > +   _INTERNAL_trim_to_complete_utf8_characters @68
> > > ++; backported from version 2.4.0
> > > ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> > > ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
> > > +diff --git a/expat/lib/libexpatw.def b/expat/lib/libexpatw.def
> > > +index 16faf595..ebd77707 100644
> > > +--- a/expat/lib/libexpatw.def
> > > ++++ b/expat/lib/libexpatw.def
> > > +@@ -76,3 +76,6 @@ EXPORTS
> > > +   XML_SetHashSalt @67
> > > + ; added with version 2.2.5
> > > +   _INTERNAL_trim_to_complete_utf8_characters @68
> > > ++; backported from version 2.4.0
> > > ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> > > ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @7
> > > +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
> > > +index 3aaf35b9..fdcc7296 100644
> > > +--- a/expat/lib/xmlparse.c
> > > ++++ b/expat/lib/xmlparse.c
> > > +@@ -47,6 +47,8 @@
> > > + #include <limits.h> /* UINT_MAX */
> > > + #include <stdio.h>  /* fprintf */
> > > + #include <stdlib.h> /* getenv, rand_s */
> > > ++#include <stdint.h> /* uintptr_t */
> > > ++#include <math.h>   /* isnan */
> > > +
> > > + #ifdef _WIN32
> > > + #  define getpid GetCurrentProcessId
> > > +@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
> > > +   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
> > > + } OPEN_INTERNAL_ENTITY;
> > > +
> > > ++enum XML_Account {
> > > ++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the
> > > Expat
> > > parser */
> > > ++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced
> > > during
> > > entity
> > > ++                                   expansion */
> > > ++  XML_ACCOUNT_NONE              /* i.e. do not account, was
> > > accounted
> > > already */
> > > ++};
> > > ++
> > > ++#ifdef XML_DTD
> > > ++typedef unsigned long long XmlBigCount;
> > > ++typedef struct accounting {
> > > ++  XmlBigCount countBytesDirect;
> > > ++  XmlBigCount countBytesIndirect;
> > > ++  int debugLevel;
> > > ++  float maximumAmplificationFactor; // >=1.0
> > > ++  unsigned long long activationThresholdBytes;
> > > ++} ACCOUNTING;
> > > ++
> > > ++typedef struct entity_stats {
> > > ++  unsigned int countEverOpened;
> > > ++  unsigned int currentDepth;
> > > ++  unsigned int maximumDepthSeen;
> > > ++  int debugLevel;
> > > ++} ENTITY_STATS;
> > > ++#endif /* XML_DTD */
> > > ++
> > > + typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
> > > const
> > > char *start,
> > > +                                          const char *end, const
> > > char
> > > **endPtr);
> > > +
> > > +@@ -403,16 +430,18 @@ static enum XML_Error
> > > initializeEncoding(XML_Parser parser);
> > > + static enum XML_Error doProlog(XML_Parser parser, const
> > > ENCODING
> > > *enc,
> > > +                                const char *s, const char *end,
> > > int
> > > tok,
> > > +                                const char *next, const char
> > > **nextPtr,
> > > +-                               XML_Bool haveMore, XML_Bool
> > > allowClosingDoctype);
> > > ++                               XML_Bool haveMore, XML_Bool
> > > allowClosingDoctype,
> > > ++                               enum XML_Account account);
> > > + static enum XML_Error processInternalEntity(XML_Parser parser,
> > > ENTITY
> > > *entity,
> > > +                                             XML_Bool
> > > betweenDecl);
> > > + static enum XML_Error doContent(XML_Parser parser, int
> > > startTagLevel,
> > > +                                 const ENCODING *enc, const char
> > > *start,
> > > +                                 const char *end, const char
> > > **endPtr,
> > > +-                                XML_Bool haveMore);
> > > ++                                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,
> > > +@@ -422,7 +451,8 @@ static enum XML_Error
> > > doIgnoreSection(XML_Parser
> > > parser, const ENCODING *,
> > > + static void freeBindings(XML_Parser parser, BINDING *bindings);
> > > + static enum XML_Error storeAtts(XML_Parser parser, const
> > > ENCODING
> > > *,
> > > +                                 const char *s, TAG_NAME
> > > *tagNamePtr,
> > > +-                                BINDING **bindingsPtr);
> > > ++                                BINDING **bindingsPtr,
> > > ++                                enum XML_Account account);
> > > + static enum XML_Error addBinding(XML_Parser parser, PREFIX
> > > *prefix,
> > > +                                  const ATTRIBUTE_ID *attId,
> > > const
> > > XML_Char *uri,
> > > +                                  BINDING **bindingsPtr);
> > > +@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE
> > > *type,
> > > ATTRIBUTE_ID *, XML_Bool isCdata,
> > > +                            XML_Parser parser);
> > > + static enum XML_Error storeAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *,
> > > +                                           XML_Bool isCdata,
> > > const
> > > char *,
> > > +-                                          const char *,
> > > STRING_POOL
> > > *);
> > > ++                                          const char *,
> > > STRING_POOL
> > > *,
> > > ++                                          enum XML_Account
> > > account);
> > > + static enum XML_Error appendAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *,
> > > +                                            XML_Bool isCdata,
> > > const
> > > char *,
> > > +-                                           const char *,
> > > STRING_POOL
> > > *);
> > > ++                                           const char *,
> > > STRING_POOL
> > > *,
> > > ++                                           enum XML_Account
> > > account);
> > > + static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const
> > > ENCODING
> > > *enc,
> > > +                                     const char *start, const
> > > char
> > > *end);
> > > + static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE
> > > *);
> > > + static enum XML_Error storeEntityValue(XML_Parser parser, const
> > > ENCODING *enc,
> > > +-                                       const char *start, const
> > > char
> > > *end);
> > > ++                                       const char *start, const
> > > char
> > > *end,
> > > ++                                       enum XML_Account
> > > account);
> > > + static int reportProcessingInstruction(XML_Parser parser, const
> > > ENCODING *enc,
> > > +                                        const char *start, const
> > > char
> > > *end);
> > > + static int reportComment(XML_Parser parser, const ENCODING
> > > *enc,
> > > +@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const
> > > XML_Char
> > > *encodingName,
> > > +
> > > + static void parserInit(XML_Parser parser, const XML_Char
> > > *encodingName);
> > > +
> > > ++#ifdef XML_DTD
> > > ++static float accountingGetCurrentAmplification(XML_Parser
> > > rootParser);
> > > ++static void accountingReportStats(XML_Parser originParser,
> > > const
> > > char
> > > *epilog);
> > > ++static void accountingOnAbort(XML_Parser originParser);
> > > ++static void accountingReportDiff(XML_Parser rootParser,
> > > ++                                 unsigned int
> > > levelsAwayFromRootParser,
> > > ++                                 const char *before, const char
> > > *after,
> > > ++                                 ptrdiff_t bytesMore, int
> > > source_line,
> > > ++                                 enum XML_Account account);
> > > ++static XML_Bool accountingDiffTolerated(XML_Parser
> > > originParser,
> > > int
> > > tok,
> > > ++                                        const char *before,
> > > const
> > > char *after,
> > > ++                                        int source_line,
> > > ++                                        enum XML_Account
> > > account);
> > > ++
> > > ++static void entityTrackingReportStats(XML_Parser parser, ENTITY
> > > *entity,
> > > ++                                      const char *action, int
> > > sourceLine);
> > > ++static void entityTrackingOnOpen(XML_Parser parser, ENTITY
> > > *entity,
> > > ++                                 int sourceLine);
> > > ++static void entityTrackingOnClose(XML_Parser parser, ENTITY
> > > *entity,
> > > ++                                  int sourceLine);
> > > ++
> > > ++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,
> > > ++                                   unsigned long
> > > defaultDebugLevel);
> > > ++
> > > + #define poolStart(pool) ((pool)->start)
> > > + #define poolEnd(pool) ((pool)->ptr)
> > > + #define poolLength(pool) ((pool)->ptr - (pool)->start)
> > > +@@ -616,6 +678,10 @@ struct XML_ParserStruct {
> > > +   enum XML_ParamEntityParsing m_paramEntityParsing;
> > > + #endif
> > > +   unsigned long m_hash_secret_salt;
> > > ++#ifdef XML_DTD
> > > ++  ACCOUNTING m_accounting;
> > > ++  ENTITY_STATS m_entity_stats;
> > > ++#endif
> > > + };
> > > +
> > > + #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
> > > +@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const
> > > XML_Char
> > > *encodingName) {
> > > +   parser->m_paramEntityParsing =
> > > XML_PARAM_ENTITY_PARSING_NEVER;
> > > + #endif
> > > +   parser->m_hash_secret_salt = 0;
> > > ++
> > > ++#ifdef XML_DTD
> > > ++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
> > > ++  parser->m_accounting.debugLevel =
> > > getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
> > > ++  parser->m_accounting.maximumAmplificationFactor
> > > ++      =
> > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFA
> > > ULT;
> > > ++  parser->m_accounting.activationThresholdBytes
> > > ++      =
> > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAU
> > > LT;
> > > ++
> > > ++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
> > > ++  parser->m_entity_stats.debugLevel =
> > > getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
> > > ++#endif
> > > + }
> > > +
> > > + /* moves list of bindings to m_freeBindingList */
> > > +@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
> > > +   /* Added in 2.2.5. */
> > > +   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1,
> > > already */
> > > +     return XML_L("invalid argument");
> > > ++  /* Backported from 2.4.0. */
> > > ++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
> > > ++    return XML_L(
> > > ++        "limit on input amplification factor (from DTD and
> > > entities)
> > > breached");
> > > +   }
> > > +   return NULL;
> > > + }
> > > +@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
> > > +
> > > + const XML_Feature *XMLCALL
> > > + XML_GetFeatureList(void) {
> > > +-  static const XML_Feature features[]
> > > +-      = {{XML_FEATURE_SIZEOF_XML_CHAR,
> > > XML_L("sizeof(XML_Char)"),
> > > +-          sizeof(XML_Char)},
> > > +-         {XML_FEATURE_SIZEOF_XML_LCHAR,
> > > XML_L("sizeof(XML_LChar)"),
> > > +-          sizeof(XML_LChar)},
> > > ++  static const XML_Feature features[] = {
> > > ++      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
> > > ++       sizeof(XML_Char)},
> > > ++      {XML_FEATURE_SIZEOF_XML_LCHAR,
> > > XML_L("sizeof(XML_LChar)"),
> > > ++       sizeof(XML_LChar)},
> > > + #ifdef XML_UNICODE
> > > +-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> > > ++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> > > + #endif
> > > + #ifdef XML_UNICODE_WCHAR_T
> > > +-         {XML_FEATURE_UNICODE_WCHAR_T,
> > > XML_L("XML_UNICODE_WCHAR_T"),
> > > 0},
> > > ++      {XML_FEATURE_UNICODE_WCHAR_T,
> > > XML_L("XML_UNICODE_WCHAR_T"),
> > > 0},
> > > + #endif
> > > + #ifdef XML_DTD
> > > +-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> > > ++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> > > + #endif
> > > + #ifdef XML_CONTEXT_BYTES
> > > +-         {XML_FEATURE_CONTEXT_BYTES,
> > > XML_L("XML_CONTEXT_BYTES"),
> > > +-          XML_CONTEXT_BYTES},
> > > ++      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
> > > ++       XML_CONTEXT_BYTES},
> > > + #endif
> > > + #ifdef XML_MIN_SIZE
> > > +-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> > > ++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> > > + #endif
> > > + #ifdef XML_NS
> > > +-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> > > ++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> > > + #endif
> > > + #ifdef XML_LARGE_SIZE
> > > +-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> > > ++      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> > > + #endif
> > > + #ifdef XML_ATTR_INFO
> > > +-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> > > ++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> > > + #endif
> > > +-         {XML_FEATURE_END, NULL, 0}};
> > > ++#ifdef XML_DTD
> > > ++      /* Added in Expat 2.4.0. */
> > > ++
> > > {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATI
> > > ON_D
> > > EF
> > > AULT,
> > > ++       XML_L("XML_BLAP_MAX_AMP"),
> > > ++       (long int)
> > > ++
> > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFA
> > > ULT}
> > > ,
> > > ++
> > > {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOL
> > > D_DE
> > > FA
> > > ULT,
> > > ++       XML_L("XML_BLAP_ACT_THRES"),
> > > ++
> > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAU
> > > LT},
> > > ++#endif
> > > ++      {XML_FEATURE_END, NULL, 0}};
> > > +
> > > +   return features;
> > > + }
> > > +
> > > ++#ifdef XML_DTD
> > > ++XML_Bool XMLCALL
> > > ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> > > ++    XML_Parser parser, float maximumAmplificationFactor) {
> > > ++  if ((parser == NULL) || (parser->m_parentParser != NULL)
> > > ++      || isnan(maximumAmplificationFactor)
> > > ++      || (maximumAmplificationFactor < 1.0f)) {
> > > ++    return XML_FALSE;
> > > ++  }
> > > ++  parser->m_accounting.maximumAmplificationFactor =
> > > maximumAmplificationFactor;
> > > ++  return XML_TRUE;
> > > ++}
> > > ++
> > > ++XML_Bool XMLCALL
> > > ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> > > ++    XML_Parser parser, unsigned long long
> > > activationThresholdBytes)
> > > {
> > > ++  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
> > > ++    return XML_FALSE;
> > > ++  }
> > > ++  parser->m_accounting.activationThresholdBytes =
> > > activationThresholdBytes;
> > > ++  return XML_TRUE;
> > > ++}
> > > ++#endif /* XML_DTD */
> > > ++
> > > + /* Initially tag->rawName always points into the parse buffer;
> > > +    for those TAG instances opened while the current parse
> > > buffer
> > > was
> > > +    processed, and not yet closed, we need to store tag->rawName
> > > in
> > > a
> > > more
> > > +@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
> > > + static enum XML_Error PTRCALL
> > > + contentProcessor(XML_Parser parser, const char *start, const
> > > char
> > > *end,
> > > +                  const char **endPtr) {
> > > +-  enum XML_Error result
> > > +-      = doContent(parser, 0, parser->m_encoding, start, end,
> > > endPtr,
> > > +-                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer);
> > > ++  enum XML_Error result = doContent(
> > > ++      parser, 0, parser->m_encoding, start, end, endPtr,
> > > ++      (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> > > XML_ACCOUNT_DIRECT);
> > > +   if (result == XML_ERROR_NONE) {
> > > +     if (! storeRawNames(parser))
> > > +       return XML_ERROR_NO_MEMORY;
> > > +@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser
> > > parser,
> > > const char *start,
> > > +   int tok = XmlContentTok(parser->m_encoding, start, end,
> > > &next);
> > > +   switch (tok) {
> > > +   case XML_TOK_BOM:
> > > ++#ifdef XML_DTD
> > > ++    if (! accountingDiffTolerated(parser, tok, start, next,
> > > __LINE__,
> > > ++                                  XML_ACCOUNT_DIRECT)) {
> > > ++      accountingOnAbort(parser);
> > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++    }
> > > ++#endif /* XML_DTD */
> > > ++
> > > +     /* If we are at the end of the buffer, this would cause the
> > > next
> > > stage,
> > > +        i.e. externalEntityInitProcessor3, to pass control
> > > directly
> > > to
> > > +        doContent (by detecting XML_TOK_NONE) without processing
> > > any
> > > xml text
> > > +@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser
> > > parser,
> > > const char *start,
> > > +   const char *next = start; /* XmlContentTok doesn't always set
> > > the
> > > last arg */
> > > +   parser->m_eventPtr = start;
> > > +   tok = XmlContentTok(parser->m_encoding, start, end, &next);
> > > ++  /* Note: These bytes are accounted later in:
> > > ++           - processXmlDecl
> > > ++           - externalEntityContentProcessor
> > > ++  */
> > > +   parser->m_eventEndPtr = next;
> > > +
> > > +   switch (tok) {
> > > +@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser
> > > parser, const char *start,
> > > +                                const char *end, const char
> > > **endPtr)
> > > {
> > > +   enum XML_Error result
> > > +       = doContent(parser, 1, parser->m_encoding, start, end,
> > > endPtr,
> > > +-                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer);
> > > ++                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer,
> > > ++                  XML_ACCOUNT_ENTITY_EXPANSION);
> > > +   if (result == XML_ERROR_NONE) {
> > > +     if (! storeRawNames(parser))
> > > +       return XML_ERROR_NO_MEMORY;
> > > +@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser
> > > parser, const char *start,
> > > + static enum XML_Error
> > > + doContent(XML_Parser parser, int startTagLevel, const ENCODING
> > > *enc,
> > > +           const char *s, const char *end, const char **nextPtr,
> > > +-          XML_Bool haveMore) {
> > > ++          XML_Bool haveMore, enum XML_Account account) {
> > > +   /* save one level of indirection */
> > > +   DTD *const dtd = parser->m_dtd;
> > > +
> > > +@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int
> > > startTagLevel,
> > > const ENCODING *enc,
> > > +   for (;;) {
> > > +     const char *next = s; /* XmlContentTok doesn't always set
> > > the
> > > last arg */
> > > +     int tok = XmlContentTok(enc, s, end, &next);
> > > ++#ifdef XML_DTD
> > > ++    const char *accountAfter
> > > ++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok ==
> > > XML_TOK_TRAILING_CR))
> > > ++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
> > > ++              : next;
> > > ++    if (! accountingDiffTolerated(parser, tok, s, accountAfter,
> > > __LINE__,
> > > ++                                  account)) {
> > > ++      accountingOnAbort(parser);
> > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++    }
> > > ++#endif
> > > +     *eventEndPP = next;
> > > +     switch (tok) {
> > > +     case XML_TOK_TRAILING_CR:
> > > +@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int
> > > startTagLevel,
> > > const ENCODING *enc,
> > > +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> > > +           enc, s + enc->minBytesPerChar, next - enc-
> > > > minBytesPerChar);
> > > +       if (ch) {
> > > ++#ifdef XML_DTD
> > > ++        /* NOTE: We are replacing 4-6 characters original input
> > > for
> > > 1
> > > character
> > > ++         *       so there is no amplification and hence
> > > recording
> > > without
> > > ++         *       protection. */
> > > ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> > > ++                                ((char *)&ch) +
> > > sizeof(XML_Char),
> > > __LINE__,
> > > ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> > > ++#endif /* XML_DTD */
> > > +         if (parser->m_characterDataHandler)
> > > +           parser->m_characterDataHandler(parser->m_handlerArg,
> > > &ch,
> > > 1);
> > > +         else if (parser->m_defaultHandler)
> > > +@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int
> > > startTagLevel,
> > > const ENCODING *enc,
> > > +       }
> > > +       tag->name.str = (XML_Char *)tag->buf;
> > > +       *toPtr = XML_T('\0');
> > > +-      result = storeAtts(parser, enc, s, &(tag->name), &(tag-
> > > > bindings));
> > > ++      result
> > > ++          = storeAtts(parser, enc, s, &(tag->name), &(tag-
> > > > bindings),
> > > account);
> > > +       if (result)
> > > +         return result;
> > > +       if (parser->m_startElementHandler)
> > > +@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int
> > > startTagLevel,
> > > const ENCODING *enc,
> > > +       if (! name.str)
> > > +         return XML_ERROR_NO_MEMORY;
> > > +       poolFinish(&parser->m_tempPool);
> > > +-      result = storeAtts(parser, enc, s, &name, &bindings);
> > > ++      result = storeAtts(parser, enc, s, &name, &bindings,
> > > ++                         XML_ACCOUNT_NONE /* token spans whole
> > > start
> > > tag */);
> > > +       if (result != XML_ERROR_NONE) {
> > > +         freeBindings(parser, bindings);
> > > +         return result;
> > > +@@ -2907,7 +3057,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) {
> > > +@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING
> > > *bindings) {
> > > + */
> > > + static enum XML_Error
> > > + storeAtts(XML_Parser parser, const ENCODING *enc, const char
> > > *attStr,
> > > +-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
> > > ++          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
> > > ++          enum XML_Account account) {
> > > +   DTD *const dtd = parser->m_dtd; /* save one level of
> > > indirection
> > > */
> > > +   ELEMENT_TYPE *elementType;
> > > +   int nDefaultAtts;
> > > +@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const
> > > ENCODING
> > > *enc, const char *attStr,
> > > +       /* normalize the attribute value */
> > > +       result = storeAttributeValue(
> > > +           parser, enc, isCdata, parser->m_atts[i].valuePtr,
> > > +-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
> > > ++          parser->m_atts[i].valueEnd, &parser->m_tempPool,
> > > account);
> > > +       if (result)
> > > +         return result;
> > > +       appAtts[attIndex] = poolStart(&parser->m_tempPool);
> > > +@@ -3535,9 +3687,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) {
> > > +@@ -3557,7 +3709,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;
> > > +@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const
> > > ENCODING *enc, const char **startPtr,
> > > +   for (;;) {
> > > +     const char *next;
> > > +     int tok = XmlCdataSectionTok(enc, s, end, &next);
> > > ++#ifdef XML_DTD
> > > ++    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) {
> > > +     case XML_TOK_CDATA_SECT_CLOSE:
> > > +@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const
> > > ENCODING *enc, const char **startPtr,
> > > +   *eventPP = s;
> > > +   *startPtr = NULL;
> > > +   tok = XmlIgnoreSectionTok(enc, s, end, &next);
> > > ++#  ifdef XML_DTD
> > > ++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> > > ++                                XML_ACCOUNT_DIRECT)) {
> > > ++    accountingOnAbort(parser);
> > > ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++  }
> > > ++#  endif
> > > +   *eventEndPP = next;
> > > +   switch (tok) {
> > > +   case XML_TOK_IGNORE_SECT:
> > > +@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int
> > > isGeneralTextEntity, const char *s,
> > > +   const char *versionend;
> > > +   const XML_Char *storedversion = NULL;
> > > +   int standalone = -1;
> > > ++
> > > ++#ifdef XML_DTD
> > > ++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s,
> > > next,
> > > __LINE__,
> > > ++                                XML_ACCOUNT_DIRECT)) {
> > > ++    accountingOnAbort(parser);
> > > ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++  }
> > > ++#endif
> > > ++
> > > +   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
> > > +           isGeneralTextEntity, parser->m_encoding, s, next,
> > > &parser-
> > > > m_eventPtr,
> > > +           &version, &versionend, &encodingName, &newEncoding,
> > > &standalone)) {
> > > +@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser
> > > parser,
> > > const char *s, const char *end,
> > > +
> > > +   for (;;) {
> > > +     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
> > > ++    /* Note: Except for XML_TOK_BOM below, these bytes are
> > > accounted
> > > later in:
> > > ++             - storeEntityValue
> > > ++             - processXmlDecl
> > > ++    */
> > > +     parser->m_eventEndPtr = next;
> > > +     if (tok <= 0) {
> > > +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> > > XML_TOK_INVALID) {
> > > +@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser
> > > parser,
> > > const char *s, const char *end,
> > > +         break;
> > > +       }
> > > +       /* found end of entity value - can store it now */
> > > +-      return storeEntityValue(parser, parser->m_encoding, s,
> > > end);
> > > ++      return storeEntityValue(parser, parser->m_encoding, s,
> > > end,
> > > ++                              XML_ACCOUNT_DIRECT);
> > > +     } else if (tok == XML_TOK_XML_DECL) {
> > > +       enum XML_Error result;
> > > +       result = processXmlDecl(parser, 0, start, next);
> > > +@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser
> > > parser,
> > > const char *s, const char *end,
> > > +     */
> > > +     else if (tok == XML_TOK_BOM && next == end
> > > +              && ! parser->m_parsingStatus.finalBuffer) {
> > > ++#  ifdef XML_DTD
> > > ++      if (! accountingDiffTolerated(parser, tok, s, next,
> > > __LINE__,
> > > ++                                    XML_ACCOUNT_DIRECT)) {
> > > ++        accountingOnAbort(parser);
> > > ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++      }
> > > ++#  endif
> > > ++
> > > +       *nextPtr = next;
> > > +       return XML_ERROR_NONE;
> > > +     }
> > > +@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser
> > > parser,
> > > const char *s, const char *end,
> > > +   }
> > > +   /* This would cause the next stage, i.e. doProlog to be
> > > passed
> > > XML_TOK_BOM.
> > > +      However, when parsing an external subset, doProlog will
> > > not
> > > accept a BOM
> > > +-     as valid, and report a syntax error, so we have to skip
> > > the
> > > BOM
> > > ++     as valid, and report a syntax error, so we have to skip
> > > the
> > > BOM,
> > > and
> > > ++     account for the BOM bytes.
> > > +   */
> > > +   else if (tok == XML_TOK_BOM) {
> > > ++    if (! accountingDiffTolerated(parser, tok, s, next,
> > > __LINE__,
> > > ++                                  XML_ACCOUNT_DIRECT)) {
> > > ++      accountingOnAbort(parser);
> > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++    }
> > > ++
> > > +     s = next;
> > > +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > +   }
> > > +
> > > +   parser->m_processor = prologProcessor;
> > > +   return doProlog(parser, parser->m_encoding, s, end, tok,
> > > next,
> > > nextPtr,
> > > +-                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer,
> > > XML_TRUE);
> > > ++                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer,
> > > XML_TRUE,
> > > ++                  XML_ACCOUNT_DIRECT);
> > > + }
> > > +
> > > + static enum XML_Error PTRCALL
> > > +@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser,
> > > const
> > > char *s, const char *end,
> > > +
> > > +   for (;;) {
> > > +     tok = XmlPrologTok(enc, start, end, &next);
> > > ++    /* Note: These bytes are accounted later in:
> > > ++             - storeEntityValue
> > > ++    */
> > > +     if (tok <= 0) {
> > > +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> > > XML_TOK_INVALID) {
> > > +         *nextPtr = s;
> > > +@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser,
> > > const
> > > char *s, const char *end,
> > > +         break;
> > > +       }
> > > +       /* found end of entity value - can store it now */
> > > +-      return storeEntityValue(parser, enc, s, end);
> > > ++      return storeEntityValue(parser, enc, s, end,
> > > XML_ACCOUNT_DIRECT);
> > > +     }
> > > +     start = next;
> > > +   }
> > > +@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const
> > > char
> > > *s, const char *end,
> > > +   const char *next = s;
> > > +   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > +   return doProlog(parser, parser->m_encoding, s, end, tok,
> > > next,
> > > nextPtr,
> > > +-                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer,
> > > XML_TRUE);
> > > ++                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer,
> > > XML_TRUE,
> > > ++                  XML_ACCOUNT_DIRECT);
> > > + }
> > > +
> > > + static enum XML_Error
> > > + doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
> > > const
> > > char *end,
> > > +          int tok, const char *next, const char **nextPtr,
> > > XML_Bool
> > > haveMore,
> > > +-         XML_Bool allowClosingDoctype) {
> > > ++         XML_Bool allowClosingDoctype, enum XML_Account
> > > account) {
> > > + #ifdef XML_DTD
> > > +   static const XML_Char externalSubsetName[] = {ASCII_HASH,
> > > '\0'};
> > > + #endif /* XML_DTD */
> > > +@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const
> > > ENCODING
> > > *enc, const char *s, const char *end,
> > > +   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
> > > +   static const XML_Char enumValueStart[] = {ASCII_LPAREN,
> > > '\0'};
> > > +
> > > ++#ifndef XML_DTD
> > > ++  UNUSED_P(account);
> > > ++#endif
> > > ++
> > > +   /* save one level of indirection */
> > > +   DTD *const dtd = parser->m_dtd;
> > > +
> > > +@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const
> > > ENCODING
> > > *enc, const char *s, const char *end,
> > > +       }
> > > +     }
> > > +     role = XmlTokenRole(&parser->m_prologState, tok, s, next,
> > > enc);
> > > ++#ifdef XML_DTD
> > > ++    switch (role) {
> > > ++    case XML_ROLE_INSTANCE_START: // bytes accounted in
> > > contentProcessor
> > > ++    case XML_ROLE_XML_DECL:       // bytes accounted in
> > > processXmlDecl
> > > ++    case XML_ROLE_TEXT_DECL:      // bytes accounted in
> > > processXmlDecl
> > > ++      break;
> > > ++    default:
> > > ++      if (! accountingDiffTolerated(parser, tok, s, next,
> > > __LINE__,
> > > account)) {
> > > ++        accountingOnAbort(parser);
> > > ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++      }
> > > ++    }
> > > ++#endif
> > > +     switch (role) {
> > > +     case XML_ROLE_XML_DECL: {
> > > +       enum XML_Error result = processXmlDecl(parser, 0, s,
> > > next);
> > > +@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING
> > > *enc,
> > > const char *s, const char *end,
> > > +         const XML_Char *attVal;
> > > +         enum XML_Error result = storeAttributeValue(
> > > +             parser, enc, parser->m_declAttributeIsCdata,
> > > +-            s + enc->minBytesPerChar, next - enc-
> > > >minBytesPerChar,
> > > &dtd->pool);
> > > ++            s + enc->minBytesPerChar, next - enc-
> > > >minBytesPerChar,
> > > &dtd->pool,
> > > ++            XML_ACCOUNT_NONE);
> > > +         if (result)
> > > +           return result;
> > > +         attVal = poolStart(&dtd->pool);
> > > +@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING
> > > *enc,
> > > const char *s, const char *end,
> > > +       break;
> > > +     case XML_ROLE_ENTITY_VALUE:
> > > +       if (dtd->keepProcessing) {
> > > +-        enum XML_Error result = storeEntityValue(
> > > +-            parser, enc, s + enc->minBytesPerChar, next - enc-
> > > > minBytesPerChar);
> > > ++        enum XML_Error result
> > > ++            = storeEntityValue(parser, enc, s + enc-
> > > > minBytesPerChar,
> > > ++                               next - enc->minBytesPerChar,
> > > XML_ACCOUNT_NONE);
> > > +         if (parser->m_declEntity) {
> > > +           parser->m_declEntity->textPtr = poolStart(&dtd-
> > > > entityValuePool);
> > > +           parser->m_declEntity->textLen
> > > +@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const
> > > ENCODING
> > > *enc, const char *s, const char *end,
> > > +         if (parser->m_externalEntityRefHandler) {
> > > +           dtd->paramEntityRead = XML_FALSE;
> > > +           entity->open = XML_TRUE;
> > > ++          entityTrackingOnOpen(parser, entity, __LINE__);
> > > +           if (! parser->m_externalEntityRefHandler(
> > > +                   parser->m_externalEntityRefHandlerArg, 0,
> > > entity-
> > > > base,
> > > +                   entity->systemId, entity->publicId)) {
> > > ++            entityTrackingOnClose(parser, entity, __LINE__);
> > > +             entity->open = XML_FALSE;
> > > +             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> > > +           }
> > > ++          entityTrackingOnClose(parser, entity, __LINE__);
> > > +           entity->open = XML_FALSE;
> > > +           handleDefault = XML_FALSE;
> > > +           if (! dtd->paramEntityRead) {
> > > +@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const
> > > char
> > > *s, const char *end,
> > > +   for (;;) {
> > > +     const char *next = NULL;
> > > +     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > ++#ifdef XML_DTD
> > > ++    if (! accountingDiffTolerated(parser, tok, s, next,
> > > __LINE__,
> > > ++                                  XML_ACCOUNT_DIRECT)) {
> > > ++      accountingOnAbort(parser);
> > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++    }
> > > ++#endif
> > > +     parser->m_eventEndPtr = next;
> > > +     switch (tok) {
> > > +     /* report partial linebreak - it might be the last token */
> > > +@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser,
> > > ENTITY
> > > *entity, XML_Bool betweenDecl) {
> > > +       return XML_ERROR_NO_MEMORY;
> > > +   }
> > > +   entity->open = XML_TRUE;
> > > ++#ifdef XML_DTD
> > > ++  entityTrackingOnOpen(parser, entity, __LINE__);
> > > ++#endif
> > > +   entity->processed = 0;
> > > +   openEntity->next = parser->m_openInternalEntities;
> > > +   parser->m_openInternalEntities = openEntity;
> > > +@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser,
> > > ENTITY *entity, XML_Bool betweenDecl) {
> > > +     int tok
> > > +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> > > textEnd, &next);
> > > +     result = doProlog(parser, parser->m_internalEncoding,
> > > textStart,
> > > textEnd,
> > > +-                      tok, next, &next, XML_FALSE, XML_FALSE);
> > > ++                      tok, next, &next, XML_FALSE, XML_FALSE,
> > > ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> > > +   } else
> > > + #endif /* XML_DTD */
> > > +     result = doContent(parser, parser->m_tagLevel, parser-
> > > > m_internalEncoding,
> > > +-                       textStart, textEnd, &next, XML_FALSE);
> > > ++                       textStart, textEnd, &next, XML_FALSE,
> > > ++                       XML_ACCOUNT_ENTITY_EXPANSION);
> > > +
> > > +   if (result == XML_ERROR_NONE) {
> > > +     if (textEnd != next && parser->m_parsingStatus.parsing ==
> > > XML_SUSPENDED) {
> > > +       entity->processed = (int)(next - textStart);
> > > +       parser->m_processor = internalEntityProcessor;
> > > +     } else {
> > > ++#ifdef XML_DTD
> > > ++      entityTrackingOnClose(parser, entity, __LINE__);
> > > ++#endif /* XML_DTD */
> > > +       entity->open = XML_FALSE;
> > > +       parser->m_openInternalEntities = openEntity->next;
> > > +       /* put openEntity back in list of free instances */
> > > +@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser
> > > parser,
> > > const char *s, const char *end,
> > > +     int tok
> > > +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> > > textEnd, &next);
> > > +     result = doProlog(parser, parser->m_internalEncoding,
> > > textStart,
> > > textEnd,
> > > +-                      tok, next, &next, XML_FALSE, XML_TRUE);
> > > ++                      tok, next, &next, XML_FALSE, XML_TRUE,
> > > ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> > > +   } else
> > > + #endif /* XML_DTD */
> > > +     result = doContent(parser, openEntity->startTagLevel,
> > > +                        parser->m_internalEncoding, textStart,
> > > textEnd, &next,
> > > +-                       XML_FALSE);
> > > ++                       XML_FALSE,
> > > XML_ACCOUNT_ENTITY_EXPANSION);
> > > +
> > > +   if (result != XML_ERROR_NONE)
> > > +     return result;
> > > +@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser,
> > > const
> > > char *s, const char *end,
> > > +     entity->processed = (int)(next - (char *)entity->textPtr);
> > > +     return result;
> > > +   } else {
> > > ++#ifdef XML_DTD
> > > ++    entityTrackingOnClose(parser, entity, __LINE__);
> > > ++#endif
> > > +     entity->open = XML_FALSE;
> > > +     parser->m_openInternalEntities = openEntity->next;
> > > +     /* put openEntity back in list of free instances */
> > > +@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser,
> > > const
> > > char *s, const char *end,
> > > +     parser->m_processor = prologProcessor;
> > > +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > +     return doProlog(parser, parser->m_encoding, s, end, tok,
> > > next,
> > > nextPtr,
> > > +-                    (XML_Bool)! parser-
> > > > m_parsingStatus.finalBuffer,
> > > XML_TRUE);
> > > ++                    (XML_Bool)! parser-
> > > > m_parsingStatus.finalBuffer,
> > > XML_TRUE,
> > > ++                    XML_ACCOUNT_DIRECT);
> > > +   } else
> > > + #endif /* XML_DTD */
> > > +   {
> > > +@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser,
> > > const
> > > char *s, const char *end,
> > > +     /* see externalEntityContentProcessor vs contentProcessor
> > > */
> > > +     return doContent(parser, parser->m_parentParser ? 1 : 0,
> > > parser-
> > > > m_encoding,
> > > +                      s, end, nextPtr,
> > > +-                     (XML_Bool)! parser-
> > > > m_parsingStatus.finalBuffer);
> > > ++                     (XML_Bool)! parser-
> > > > m_parsingStatus.finalBuffer,
> > > ++                     XML_ACCOUNT_DIRECT);
> > > +   }
> > > + }
> > > +
> > > +@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const
> > > char
> > > *s, const char *end,
> > > +
> > > + static enum XML_Error
> > > + storeAttributeValue(XML_Parser parser, const ENCODING *enc,
> > > XML_Bool
> > > isCdata,
> > > +-                    const char *ptr, const char *end,
> > > STRING_POOL
> > > *pool) {
> > > ++                    const char *ptr, const char *end,
> > > STRING_POOL
> > > *pool,
> > > ++                    enum XML_Account account) {
> > > +   enum XML_Error result
> > > +-      = appendAttributeValue(parser, enc, isCdata, ptr, end,
> > > pool);
> > > ++      = appendAttributeValue(parser, enc, isCdata, ptr, end,
> > > pool,
> > > account);
> > > +   if (result)
> > > +     return result;
> > > +   if (! isCdata && poolLength(pool) && poolLastChar(pool) ==
> > > 0x20)
> > > +@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *enc, XML_Bool isCdata,
> > > +
> > > + static enum XML_Error
> > > + appendAttributeValue(XML_Parser parser, const ENCODING *enc,
> > > XML_Bool
> > > isCdata,
> > > +-                     const char *ptr, const char *end,
> > > STRING_POOL
> > > *pool) {
> > > ++                     const char *ptr, const char *end,
> > > STRING_POOL
> > > *pool,
> > > ++                     enum XML_Account account) {
> > > +   DTD *const dtd = parser->m_dtd; /* save one level of
> > > indirection
> > > */
> > > ++#ifndef XML_DTD
> > > ++  UNUSED_P(account);
> > > ++#endif
> > > ++
> > > +   for (;;) {
> > > +     const char *next;
> > > +     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
> > > ++#ifdef XML_DTD
> > > ++    if (! accountingDiffTolerated(parser, tok, ptr, next,
> > > __LINE__,
> > > account)) {
> > > ++      accountingOnAbort(parser);
> > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++    }
> > > ++#endif
> > > +     switch (tok) {
> > > +     case XML_TOK_NONE:
> > > +       return XML_ERROR_NONE;
> > > +@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *enc, XML_Bool isCdata,
> > > +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> > > +           enc, ptr + enc->minBytesPerChar, next - enc-
> > > > minBytesPerChar);
> > > +       if (ch) {
> > > ++#ifdef XML_DTD
> > > ++        /* NOTE: We are replacing 4-6 characters original input
> > > for
> > > 1
> > > character
> > > ++         *       so there is no amplification and hence
> > > recording
> > > without
> > > ++         *       protection. */
> > > ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> > > ++                                ((char *)&ch) +
> > > sizeof(XML_Char),
> > > __LINE__,
> > > ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> > > ++#endif /* XML_DTD */
> > > +         if (! poolAppendChar(pool, ch))
> > > +           return XML_ERROR_NO_MEMORY;
> > > +         break;
> > > +@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *enc, XML_Bool isCdata,
> > > +         enum XML_Error result;
> > > +         const XML_Char *textEnd = entity->textPtr + entity-
> > > > textLen;
> > > +         entity->open = XML_TRUE;
> > > ++#ifdef XML_DTD
> > > ++        entityTrackingOnOpen(parser, entity, __LINE__);
> > > ++#endif
> > > +         result = appendAttributeValue(parser, parser-
> > > > m_internalEncoding,
> > > +-                                      isCdata, (char *)entity-
> > > > textPtr,
> > > +-                                      (char *)textEnd, pool);
> > > ++                                      isCdata, (const char
> > > *)entity-
> > > > textPtr,
> > > ++                                      (const char *)textEnd,
> > > pool,
> > > ++
> > > XML_ACCOUNT_ENTITY_EXPANSION);
> > > ++#ifdef XML_DTD
> > > ++        entityTrackingOnClose(parser, entity, __LINE__);
> > > ++#endif
> > > +         entity->open = XML_FALSE;
> > > +         if (result)
> > > +           return result;
> > > +@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *enc, XML_Bool isCdata,
> > > +
> > > + static enum XML_Error
> > > + storeEntityValue(XML_Parser parser, const ENCODING *enc,
> > > +-                 const char *entityTextPtr, const char
> > > *entityTextEnd) {
> > > ++                 const char *entityTextPtr, const char
> > > *entityTextEnd,
> > > ++                 enum XML_Account account) {
> > > +   DTD *const dtd = parser->m_dtd; /* save one level of
> > > indirection
> > > */
> > > +   STRING_POOL *pool = &(dtd->entityValuePool);
> > > +   enum XML_Error result = XML_ERROR_NONE;
> > > + #ifdef XML_DTD
> > > +   int oldInEntityValue = parser->m_prologState.inEntityValue;
> > > +   parser->m_prologState.inEntityValue = 1;
> > > ++#else
> > > ++  UNUSED_P(account);
> > > + #endif /* XML_DTD */
> > > +   /* never return Null for the value argument in
> > > EntityDeclHandler,
> > > +      since this would indicate an external entity; therefore we
> > > +@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const
> > > ENCODING *enc,
> > > +   for (;;) {
> > > +     const char *next;
> > > +     int tok = XmlEntityValueTok(enc, entityTextPtr,
> > > entityTextEnd,
> > > &next);
> > > ++
> > > ++#ifdef XML_DTD
> > > ++    if (! accountingDiffTolerated(parser, tok, entityTextPtr,
> > > next,
> > > __LINE__,
> > > ++                                  account)) {
> > > ++      accountingOnAbort(parser);
> > > ++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++      goto endEntityValue;
> > > ++    }
> > > ++#endif
> > > ++
> > > +     switch (tok) {
> > > +     case XML_TOK_PARAM_ENTITY_REF:
> > > + #ifdef XML_DTD
> > > +@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser,
> > > const
> > > ENCODING *enc,
> > > +           if (parser->m_externalEntityRefHandler) {
> > > +             dtd->paramEntityRead = XML_FALSE;
> > > +             entity->open = XML_TRUE;
> > > ++            entityTrackingOnOpen(parser, entity, __LINE__);
> > > +             if (! parser->m_externalEntityRefHandler(
> > > +                     parser->m_externalEntityRefHandlerArg, 0,
> > > entity-
> > > > base,
> > > +                     entity->systemId, entity->publicId)) {
> > > ++              entityTrackingOnClose(parser, entity, __LINE__);
> > > +               entity->open = XML_FALSE;
> > > +               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> > > +               goto endEntityValue;
> > > +             }
> > > ++            entityTrackingOnClose(parser, entity, __LINE__);
> > > +             entity->open = XML_FALSE;
> > > +             if (! dtd->paramEntityRead)
> > > +               dtd->keepProcessing = dtd->standalone;
> > > +@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const
> > > ENCODING *enc,
> > > +             dtd->keepProcessing = dtd->standalone;
> > > +         } else {
> > > +           entity->open = XML_TRUE;
> > > ++          entityTrackingOnOpen(parser, entity, __LINE__);
> > > +           result = storeEntityValue(
> > > +-              parser, parser->m_internalEncoding, (char
> > > *)entity-
> > > > textPtr,
> > > +-              (char *)(entity->textPtr + entity->textLen));
> > > ++              parser, parser->m_internalEncoding, (const char
> > > *)entity->textPtr,
> > > ++              (const char *)(entity->textPtr + entity-
> > > >textLen),
> > > ++              XML_ACCOUNT_ENTITY_EXPANSION);
> > > ++          entityTrackingOnClose(parser, entity, __LINE__);
> > > +           entity->open = XML_FALSE;
> > > +           if (result)
> > > +             goto endEntityValue;
> > > +@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const
> > > XML_Memory_Handling_Suite *memsuite) {
> > > +   memcpy(result, s, charsRequired * sizeof(XML_Char));
> > > +   return result;
> > > + }
> > > ++
> > > ++#ifdef XML_DTD
> > > ++
> > > ++static float
> > > ++accountingGetCurrentAmplification(XML_Parser rootParser) {
> > > ++  const XmlBigCount countBytesOutput
> > > ++      = rootParser->m_accounting.countBytesDirect
> > > ++        + rootParser->m_accounting.countBytesIndirect;
> > > ++  const float amplificationFactor
> > > ++      = rootParser->m_accounting.countBytesDirect
> > > ++            ? (countBytesOutput
> > > ++               / (float)(rootParser-
> > > > m_accounting.countBytesDirect))
> > > ++            : 1.0f;
> > > ++  assert(! rootParser->m_parentParser);
> > > ++  return amplificationFactor;
> > > ++}
> > > ++
> > > ++static void
> > > ++accountingReportStats(XML_Parser originParser, const char
> > > *epilog)
> > > {
> > > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > > NULL);
> > > ++  assert(! rootParser->m_parentParser);
> > > ++
> > > ++  if (rootParser->m_accounting.debugLevel < 1) {
> > > ++    return;
> > > ++  }
> > > ++
> > > ++  const float amplificationFactor
> > > ++      = accountingGetCurrentAmplification(rootParser);
> > > ++  fprintf(stderr,
> > > ++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
> > > ++              "10") ", indirect " EXPAT_FMT_ULL("10") ",
> > > amplification %8.2f%s",
> > > ++          (void *)rootParser, rootParser-
> > > > m_accounting.countBytesDirect,
> > > ++          rootParser->m_accounting.countBytesIndirect,
> > > ++          (double)amplificationFactor, epilog);
> > > ++}
> > > ++
> > > ++static void
> > > ++accountingOnAbort(XML_Parser originParser) {
> > > ++  accountingReportStats(originParser, " ABORTING\n");
> > > ++}
> > > ++
> > > ++static void
> > > ++accountingReportDiff(XML_Parser rootParser,
> > > ++                     unsigned int levelsAwayFromRootParser,
> > > const
> > > char *before,
> > > ++                     const char *after, ptrdiff_t bytesMore,
> > > int
> > > source_line,
> > > ++                     enum XML_Account account) {
> > > ++  assert(! rootParser->m_parentParser);
> > > ++
> > > ++  fprintf(stderr,
> > > ++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d,
> > > xmlparse.c:%d) %*s\"",
> > > ++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" :
> > > "EXP",
> > > ++          levelsAwayFromRootParser, source_line, 10, "");
> > > ++
> > > ++  const char ellipis[] = "[..]";
> > > ++  const size_t ellipsisLength = sizeof(ellipis) /* because
> > > compile-
> > > time */ - 1;
> > > ++  const unsigned int contextLength = 10;
> > > ++
> > > ++  /* Note: Performance is of no concern here */
> > > ++  const char *walker = before;
> > > ++  if ((rootParser->m_accounting.debugLevel >= 3)
> > > ++      || (after - before)
> > > ++             <= (ptrdiff_t)(contextLength + ellipsisLength +
> > > contextLength)) {
> > > ++    for (; walker < after; walker++) {
> > > ++      fprintf(stderr, "%s",
> > > unsignedCharToPrintable(walker[0]));
> > > ++    }
> > > ++  } else {
> > > ++    for (; walker < before + contextLength; walker++) {
> > > ++      fprintf(stderr, "%s",
> > > unsignedCharToPrintable(walker[0]));
> > > ++    }
> > > ++    fprintf(stderr, ellipis);
> > > ++    walker = after - contextLength;
> > > ++    for (; walker < after; walker++) {
> > > ++      fprintf(stderr, "%s",
> > > unsignedCharToPrintable(walker[0]));
> > > ++    }
> > > ++  }
> > > ++  fprintf(stderr, "\"\n");
> > > ++}
> > > ++
> > > ++static XML_Bool
> > > ++accountingDiffTolerated(XML_Parser originParser, int tok, const
> > > char
> > > *before,
> > > ++                        const char *after, int source_line,
> > > ++                        enum XML_Account account) {
> > > ++  /* Note: We need to check the token type *first* to be sure
> > > that
> > > ++   *       we can even access variable <after>, safely.
> > > ++   *       E.g. for XML_TOK_NONE <after> may hold an invalid
> > > pointer.
> > > */
> > > ++  switch (tok) {
> > > ++  case XML_TOK_INVALID:
> > > ++  case XML_TOK_PARTIAL:
> > > ++  case XML_TOK_PARTIAL_CHAR:
> > > ++  case XML_TOK_NONE:
> > > ++    return XML_TRUE;
> > > ++  }
> > > ++
> > > ++  if (account == XML_ACCOUNT_NONE)
> > > ++    return XML_TRUE; /* because these bytes have been accounted
> > > for,
> > > already */
> > > ++
> > > ++  unsigned int levelsAwayFromRootParser;
> > > ++  const XML_Parser rootParser
> > > ++      = getRootParserOf(originParser,
> > > &levelsAwayFromRootParser);
> > > ++  assert(! rootParser->m_parentParser);
> > > ++
> > > ++  const int isDirect
> > > ++      = (account == XML_ACCOUNT_DIRECT) && (originParser ==
> > > rootParser);
> > > ++  const ptrdiff_t bytesMore = after - before;
> > > ++
> > > ++  XmlBigCount *const additionTarget
> > > ++      = isDirect ? &rootParser->m_accounting.countBytesDirect
> > > ++                 : &rootParser-
> > > >m_accounting.countBytesIndirect;
> > > ++
> > > ++  /* Detect and avoid integer overflow */
> > > ++  if (*additionTarget > (XmlBigCount)(-1) -
> > > (XmlBigCount)bytesMore)
> > > ++    return XML_FALSE;
> > > ++  *additionTarget += bytesMore;
> > > ++
> > > ++  const XmlBigCount countBytesOutput
> > > ++      = rootParser->m_accounting.countBytesDirect
> > > ++        + rootParser->m_accounting.countBytesIndirect;
> > > ++  const float amplificationFactor
> > > ++      = accountingGetCurrentAmplification(rootParser);
> > > ++  const XML_Bool tolerated
> > > ++      = (countBytesOutput < rootParser-
> > > > m_accounting.activationThresholdBytes)
> > > ++        || (amplificationFactor
> > > ++            <= rootParser-
> > > > m_accounting.maximumAmplificationFactor);
> > > ++
> > > ++  if (rootParser->m_accounting.debugLevel >= 2) {
> > > ++    accountingReportStats(rootParser, "");
> > > ++    accountingReportDiff(rootParser, levelsAwayFromRootParser,
> > > before, after,
> > > ++                         bytesMore, source_line, account);
> > > ++  }
> > > ++
> > > ++  return tolerated;
> > > ++}
> > > ++
> > > ++static void
> > > ++entityTrackingReportStats(XML_Parser rootParser, ENTITY
> > > *entity,
> > > ++                          const char *action, int sourceLine) {
> > > ++  assert(! rootParser->m_parentParser);
> > > ++  if (rootParser->m_entity_stats.debugLevel < 1)
> > > ++    return;
> > > ++
> > > ++#  if defined(XML_UNICODE)
> > > ++  const char *const entityName = "[..]";
> > > ++#  else
> > > ++  const char *const entityName = entity->name;
> > > ++#  endif
> > > ++
> > > ++  fprintf(
> > > ++      stderr,
> > > ++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s;
> > > %s
> > > length %d (xmlparse.c:%d)\n",
> > > ++      (void *)rootParser, rootParser-
> > > > m_entity_stats.countEverOpened,
> > > ++      rootParser->m_entity_stats.currentDepth,
> > > ++      rootParser->m_entity_stats.maximumDepthSeen,
> > > ++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
> > > ++      entity->is_param ? "%" : "&", entityName, action, entity-
> > > > textLen,
> > > ++      sourceLine);
> > > ++}
> > > ++
> > > ++static void
> > > ++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity,
> > > int
> > > sourceLine) {
> > > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > > NULL);
> > > ++  assert(! rootParser->m_parentParser);
> > > ++
> > > ++  rootParser->m_entity_stats.countEverOpened++;
> > > ++  rootParser->m_entity_stats.currentDepth++;
> > > ++  if (rootParser->m_entity_stats.currentDepth
> > > ++      > rootParser->m_entity_stats.maximumDepthSeen) {
> > > ++    rootParser->m_entity_stats.maximumDepthSeen++;
> > > ++  }
> > > ++
> > > ++  entityTrackingReportStats(rootParser, entity, "OPEN ",
> > > sourceLine);
> > > ++}
> > > ++
> > > ++static void
> > > ++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity,
> > > int
> > > sourceLine) {
> > > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > > NULL);
> > > ++  assert(! rootParser->m_parentParser);
> > > ++
> > > ++  entityTrackingReportStats(rootParser, entity, "CLOSE",
> > > sourceLine);
> > > ++  rootParser->m_entity_stats.currentDepth--;
> > > ++}
> > > ++
> > > ++static XML_Parser
> > > ++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff)
> > > {
> > > ++  XML_Parser rootParser = parser;
> > > ++  unsigned int stepsTakenUpwards = 0;
> > > ++  while (rootParser->m_parentParser) {
> > > ++    rootParser = rootParser->m_parentParser;
> > > ++    stepsTakenUpwards++;
> > > ++  }
> > > ++  assert(! rootParser->m_parentParser);
> > > ++  if (outLevelDiff != NULL) {
> > > ++    *outLevelDiff = stepsTakenUpwards;
> > > ++  }
> > > ++  return rootParser;
> > > ++}
> > > ++
> > > ++static const char *
> > > ++unsignedCharToPrintable(unsigned char c) {
> > > ++  switch (c) {
> > > ++  case 0:
> > > ++    return "\\0";
> > > ++  case 1:
> > > ++    return "\\x1";
> > > ++  case 2:
> > > ++    return "\\x2";
> > > ++  case 3:
> > > ++    return "\\x3";
> > > ++  case 4:
> > > ++    return "\\x4";
> > > ++  case 5:
> > > ++    return "\\x5";
> > > ++  case 6:
> > > ++    return "\\x6";
> > > ++  case 7:
> > > ++    return "\\x7";
> > > ++  case 8:
> > > ++    return "\\x8";
> > > ++  case 9:
> > > ++    return "\\t";
> > > ++  case 10:
> > > ++    return "\\n";
> > > ++  case 11:
> > > ++    return "\\xB";
> > > ++  case 12:
> > > ++    return "\\xC";
> > > ++  case 13:
> > > ++    return "\\r";
> > > ++  case 14:
> > > ++    return "\\xE";
> > > ++  case 15:
> > > ++    return "\\xF";
> > > ++  case 16:
> > > ++    return "\\x10";
> > > ++  case 17:
> > > ++    return "\\x11";
> > > ++  case 18:
> > > ++    return "\\x12";
> > > ++  case 19:
> > > ++    return "\\x13";
> > > ++  case 20:
> > > ++    return "\\x14";
> > > ++  case 21:
> > > ++    return "\\x15";
> > > ++  case 22:
> > > ++    return "\\x16";
> > > ++  case 23:
> > > ++    return "\\x17";
> > > ++  case 24:
> > > ++    return "\\x18";
> > > ++  case 25:
> > > ++    return "\\x19";
> > > ++  case 26:
> > > ++    return "\\x1A";
> > > ++  case 27:
> > > ++    return "\\x1B";
> > > ++  case 28:
> > > ++    return "\\x1C";
> > > ++  case 29:
> > > ++    return "\\x1D";
> > > ++  case 30:
> > > ++    return "\\x1E";
> > > ++  case 31:
> > > ++    return "\\x1F";
> > > ++  case 32:
> > > ++    return " ";
> > > ++  case 33:
> > > ++    return "!";
> > > ++  case 34:
> > > ++    return "\\\"";
> > > ++  case 35:
> > > ++    return "#";
> > > ++  case 36:
> > > ++    return "$";
> > > ++  case 37:
> > > ++    return "%";
> > > ++  case 38:
> > > ++    return "&";
> > > ++  case 39:
> > > ++    return "'";
> > > ++  case 40:
> > > ++    return "(";
> > > ++  case 41:
> > > ++    return ")";
> > > ++  case 42:
> > > ++    return "*";
> > > ++  case 43:
> > > ++    return "+";
> > > ++  case 44:
> > > ++    return ",";
> > > ++  case 45:
> > > ++    return "-";
> > > ++  case 46:
> > > ++    return ".";
> > > ++  case 47:
> > > ++    return "/";
> > > ++  case 48:
> > > ++    return "0";
> > > ++  case 49:
> > > ++    return "1";
> > > ++  case 50:
> > > ++    return "2";
> > > ++  case 51:
> > > ++    return "3";
> > > ++  case 52:
> > > ++    return "4";
> > > ++  case 53:
> > > ++    return "5";
> > > ++  case 54:
> > > ++    return "6";
> > > ++  case 55:
> > > ++    return "7";
> > > ++  case 56:
> > > ++    return "8";
> > > ++  case 57:
> > > ++    return "9";
> > > ++  case 58:
> > > ++    return ":";
> > > ++  case 59:
> > > ++    return ";";
> > > ++  case 60:
> > > ++    return "<";
> > > ++  case 61:
> > > ++    return "=";
> > > ++  case 62:
> > > ++    return ">";
> > > ++  case 63:
> > > ++    return "?";
> > > ++  case 64:
> > > ++    return "@";
> > > ++  case 65:
> > > ++    return "A";
> > > ++  case 66:
> > > ++    return "B";
> > > ++  case 67:
> > > ++    return "C";
> > > ++  case 68:
> > > ++    return "D";
> > > ++  case 69:
> > > ++    return "E";
> > > ++  case 70:
> > > ++    return "F";
> > > ++  case 71:
> > > ++    return "G";
> > > ++  case 72:
> > > ++    return "H";
> > > ++  case 73:
> > > ++    return "I";
> > > ++  case 74:
> > > ++    return "J";
> > > ++  case 75:
> > > ++    return "K";
> > > ++  case 76:
> > > ++    return "L";
> > > ++  case 77:
> > > ++    return "M";
> > > ++  case 78:
> > > ++    return "N";
> > > ++  case 79:
> > > ++    return "O";
> > > ++  case 80:
> > > ++    return "P";
> > > ++  case 81:
> > > ++    return "Q";
> > > ++  case 82:
> > > ++    return "R";
> > > ++  case 83:
> > > ++    return "S";
> > > ++  case 84:
> > > ++    return "T";
> > > ++  case 85:
> > > ++    return "U";
> > > ++  case 86:
> > > ++    return "V";
> > > ++  case 87:
> > > ++    return "W";
> > > ++  case 88:
> > > ++    return "X";
> > > ++  case 89:
> > > ++    return "Y";
> > > ++  case 90:
> > > ++    return "Z";
> > > ++  case 91:
> > > ++    return "[";
> > > ++  case 92:
> > > ++    return "\\\\";
> > > ++  case 93:
> > > ++    return "]";
> > > ++  case 94:
> > > ++    return "^";
> > > ++  case 95:
> > > ++    return "_";
> > > ++  case 96:
> > > ++    return "`";
> > > ++  case 97:
> > > ++    return "a";
> > > ++  case 98:
> > > ++    return "b";
> > > ++  case 99:
> > > ++    return "c";
> > > ++  case 100:
> > > ++    return "d";
> > > ++  case 101:
> > > ++    return "e";
> > > ++  case 102:
> > > ++    return "f";
> > > ++  case 103:
> > > ++    return "g";
> > > ++  case 104:
> > > ++    return "h";
> > > ++  case 105:
> > > ++    return "i";
> > > ++  case 106:
> > > ++    return "j";
> > > ++  case 107:
> > > ++    return "k";
> > > ++  case 108:
> > > ++    return "l";
> > > ++  case 109:
> > > ++    return "m";
> > > ++  case 110:
> > > ++    return "n";
> > > ++  case 111:
> > > ++    return "o";
> > > ++  case 112:
> > > ++    return "p";
> > > ++  case 113:
> > > ++    return "q";
> > > ++  case 114:
> > > ++    return "r";
> > > ++  case 115:
> > > ++    return "s";
> > > ++  case 116:
> > > ++    return "t";
> > > ++  case 117:
> > > ++    return "u";
> > > ++  case 118:
> > > ++    return "v";
> > > ++  case 119:
> > > ++    return "w";
> > > ++  case 120:
> > > ++    return "x";
> > > ++  case 121:
> > > ++    return "y";
> > > ++  case 122:
> > > ++    return "z";
> > > ++  case 123:
> > > ++    return "{";
> > > ++  case 124:
> > > ++    return "|";
> > > ++  case 125:
> > > ++    return "}";
> > > ++  case 126:
> > > ++    return "~";
> > > ++  case 127:
> > > ++    return "\\x7F";
> > > ++  case 128:
> > > ++    return "\\x80";
> > > ++  case 129:
> > > ++    return "\\x81";
> > > ++  case 130:
> > > ++    return "\\x82";
> > > ++  case 131:
> > > ++    return "\\x83";
> > > ++  case 132:
> > > ++    return "\\x84";
> > > ++  case 133:
> > > ++    return "\\x85";
> > > ++  case 134:
> > > ++    return "\\x86";
> > > ++  case 135:
> > > ++    return "\\x87";
> > > ++  case 136:
> > > ++    return "\\x88";
> > > ++  case 137:
> > > ++    return "\\x89";
> > > ++  case 138:
> > > ++    return "\\x8A";
> > > ++  case 139:
> > > ++    return "\\x8B";
> > > ++  case 140:
> > > ++    return "\\x8C";
> > > ++  case 141:
> > > ++    return "\\x8D";
> > > ++  case 142:
> > > ++    return "\\x8E";
> > > ++  case 143:
> > > ++    return "\\x8F";
> > > ++  case 144:
> > > ++    return "\\x90";
> > > ++  case 145:
> > > ++    return "\\x91";
> > > ++  case 146:
> > > ++    return "\\x92";
> > > ++  case 147:
> > > ++    return "\\x93";
> > > ++  case 148:
> > > ++    return "\\x94";
> > > ++  case 149:
> > > ++    return "\\x95";
> > > ++  case 150:
> > > ++    return "\\x96";
> > > ++  case 151:
> > > ++    return "\\x97";
> > > ++  case 152:
> > > ++    return "\\x98";
> > > ++  case 153:
> > > ++    return "\\x99";
> > > ++  case 154:
> > > ++    return "\\x9A";
> > > ++  case 155:
> > > ++    return "\\x9B";
> > > ++  case 156:
> > > ++    return "\\x9C";
> > > ++  case 157:
> > > ++    return "\\x9D";
> > > ++  case 158:
> > > ++    return "\\x9E";
> > > ++  case 159:
> > > ++    return "\\x9F";
> > > ++  case 160:
> > > ++    return "\\xA0";
> > > ++  case 161:
> > > ++    return "\\xA1";
> > > ++  case 162:
> > > ++    return "\\xA2";
> > > ++  case 163:
> > > ++    return "\\xA3";
> > > ++  case 164:
> > > ++    return "\\xA4";
> > > ++  case 165:
> > > ++    return "\\xA5";
> > > ++  case 166:
> > > ++    return "\\xA6";
> > > ++  case 167:
> > > ++    return "\\xA7";
> > > ++  case 168:
> > > ++    return "\\xA8";
> > > ++  case 169:
> > > ++    return "\\xA9";
> > > ++  case 170:
> > > ++    return "\\xAA";
> > > ++  case 171:
> > > ++    return "\\xAB";
> > > ++  case 172:
> > > ++    return "\\xAC";
> > > ++  case 173:
> > > ++    return "\\xAD";
> > > ++  case 174:
> > > ++    return "\\xAE";
> > > ++  case 175:
> > > ++    return "\\xAF";
> > > ++  case 176:
> > > ++    return "\\xB0";
> > > ++  case 177:
> > > ++    return "\\xB1";
> > > ++  case 178:
> > > ++    return "\\xB2";
> > > ++  case 179:
> > > ++    return "\\xB3";
> > > ++  case 180:
> > > ++    return "\\xB4";
> > > ++  case 181:
> > > ++    return "\\xB5";
> > > ++  case 182:
> > > ++    return "\\xB6";
> > > ++  case 183:
> > > ++    return "\\xB7";
> > > ++  case 184:
> > > ++    return "\\xB8";
> > > ++  case 185:
> > > ++    return "\\xB9";
> > > ++  case 186:
> > > ++    return "\\xBA";
> > > ++  case 187:
> > > ++    return "\\xBB";
> > > ++  case 188:
> > > ++    return "\\xBC";
> > > ++  case 189:
> > > ++    return "\\xBD";
> > > ++  case 190:
> > > ++    return "\\xBE";
> > > ++  case 191:
> > > ++    return "\\xBF";
> > > ++  case 192:
> > > ++    return "\\xC0";
> > > ++  case 193:
> > > ++    return "\\xC1";
> > > ++  case 194:
> > > ++    return "\\xC2";
> > > ++  case 195:
> > > ++    return "\\xC3";
> > > ++  case 196:
> > > ++    return "\\xC4";
> > > ++  case 197:
> > > ++    return "\\xC5";
> > > ++  case 198:
> > > ++    return "\\xC6";
> > > ++  case 199:
> > > ++    return "\\xC7";
> > > ++  case 200:
> > > ++    return "\\xC8";
> > > ++  case 201:
> > > ++    return "\\xC9";
> > > ++  case 202:
> > > ++    return "\\xCA";
> > > ++  case 203:
> > > ++    return "\\xCB";
> > > ++  case 204:
> > > ++    return "\\xCC";
> > > ++  case 205:
> > > ++    return "\\xCD";
> > > ++  case 206:
> > > ++    return "\\xCE";
> > > ++  case 207:
> > > ++    return "\\xCF";
> > > ++  case 208:
> > > ++    return "\\xD0";
> > > ++  case 209:
> > > ++    return "\\xD1";
> > > ++  case 210:
> > > ++    return "\\xD2";
> > > ++  case 211:
> > > ++    return "\\xD3";
> > > ++  case 212:
> > > ++    return "\\xD4";
> > > ++  case 213:
> > > ++    return "\\xD5";
> > > ++  case 214:
> > > ++    return "\\xD6";
> > > ++  case 215:
> > > ++    return "\\xD7";
> > > ++  case 216:
> > > ++    return "\\xD8";
> > > ++  case 217:
> > > ++    return "\\xD9";
> > > ++  case 218:
> > > ++    return "\\xDA";
> > > ++  case 219:
> > > ++    return "\\xDB";
> > > ++  case 220:
> > > ++    return "\\xDC";
> > > ++  case 221:
> > > ++    return "\\xDD";
> > > ++  case 222:
> > > ++    return "\\xDE";
> > > ++  case 223:
> > > ++    return "\\xDF";
> > > ++  case 224:
> > > ++    return "\\xE0";
> > > ++  case 225:
> > > ++    return "\\xE1";
> > > ++  case 226:
> > > ++    return "\\xE2";
> > > ++  case 227:
> > > ++    return "\\xE3";
> > > ++  case 228:
> > > ++    return "\\xE4";
> > > ++  case 229:
> > > ++    return "\\xE5";
> > > ++  case 230:
> > > ++    return "\\xE6";
> > > ++  case 231:
> > > ++    return "\\xE7";
> > > ++  case 232:
> > > ++    return "\\xE8";
> > > ++  case 233:
> > > ++    return "\\xE9";
> > > ++  case 234:
> > > ++    return "\\xEA";
> > > ++  case 235:
> > > ++    return "\\xEB";
> > > ++  case 236:
> > > ++    return "\\xEC";
> > > ++  case 237:
> > > ++    return "\\xED";
> > > ++  case 238:
> > > ++    return "\\xEE";
> > > ++  case 239:
> > > ++    return "\\xEF";
> > > ++  case 240:
> > > ++    return "\\xF0";
> > > ++  case 241:
> > > ++    return "\\xF1";
> > > ++  case 242:
> > > ++    return "\\xF2";
> > > ++  case 243:
> > > ++    return "\\xF3";
> > > ++  case 244:
> > > ++    return "\\xF4";
> > > ++  case 245:
> > > ++    return "\\xF5";
> > > ++  case 246:
> > > ++    return "\\xF6";
> > > ++  case 247:
> > > ++    return "\\xF7";
> > > ++  case 248:
> > > ++    return "\\xF8";
> > > ++  case 249:
> > > ++    return "\\xF9";
> > > ++  case 250:
> > > ++    return "\\xFA";
> > > ++  case 251:
> > > ++    return "\\xFB";
> > > ++  case 252:
> > > ++    return "\\xFC";
> > > ++  case 253:
> > > ++    return "\\xFD";
> > > ++  case 254:
> > > ++    return "\\xFE";
> > > ++  case 255:
> > > ++    return "\\xFF";
> > > ++  default:
> > > ++    assert(0); /* never gets here */
> > > ++    return "dead code";
> > > ++  }
> > > ++  assert(0); /* never gets here */
> > > ++}
> > > ++
> > > ++#endif /* XML_DTD */
> > > ++
> > > ++static unsigned long
> > > ++getDebugLevel(const char *variableName, unsigned long
> > > defaultDebugLevel) {
> > > ++  const char *const valueOrNull = getenv(variableName);
> > > ++  if (valueOrNull == NULL) {
> > > ++    return defaultDebugLevel;
> > > ++  }
> > > ++  const char *const value = valueOrNull;
> > > ++
> > > ++  errno = 0;
> > > ++  char *afterValue = (char *)value;
> > > ++  unsigned long debugLevel = strtoul(value, &afterValue, 10);
> > > ++  if ((errno != 0) || (afterValue[0] != '\0')) {
> > > ++    errno = 0;
> > > ++    return defaultDebugLevel;
> > > ++  }
> > > ++
> > > ++  return debugLevel;
> > > ++}
> > > +--
> > > +2.32.0
> > > +
> > > diff --git a/meta/recipes-core/expat/expat_2.2.9.bb
> > > b/meta/recipes-
> > > core/expat/expat_2.2.9.bb
> > > index 8f3db41352..3af457b2af 100644
> > > --- a/meta/recipes-core/expat/expat_2.2.9.bb
> > > +++ b/meta/recipes-core/expat/expat_2.2.9.bb
> > > @@ -6,8 +6,9 @@ LICENSE = "MIT"
> > > 
> > >  LIC_FILES_CHKSUM =
> > > "file://COPYING;md5=5b8620d98e49772d95fc1d291c26aa79"
> > > 
> > > -SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}.tar.bz2 \
> > > +SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}-RENAMED-
> > > VULNERABLE-
> > > PLEASE-USE-2.4.1-INSTEAD.tar.bz2 \
> > >             file://libtool-tag.patch \
> > > +          
> > > file://0001-expat-Backport-fix-for-CVE-2013-0340.patch \
> > >           "
> > > 
> > >  SRC_URI[md5sum] = "875a2c2ff3e8eb9e5a5cd62db2033ab5"
> > > 
> > > 
> > > 
> > -----BEGIN PGP SIGNATURE-----
> > 
> > iQEzBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKDygACgkQYgqew07V
> > MNVpHAgAjxDiHJ+0Zl+xxBRKkD3E3bGlKlwsn4MOlP1HWN5zjComuAdnyQwvTmAj
> > 2HRDxGUQ/ZnXUlSDbNzHSgrG2IDa1dlBWGRASRX3YxIXTJ1UL5LWHuprDL2P3xNp
> > XMaAeX2a86gJKDBA7/XXkrbVuCafjGZ6r0+urvcqpJFO1FR1Qb0aklAe/pEVtEYS
> > XcN2tWfqeOy9HBOvLIBfFwkRE07oBfr0eWxKzECOq1MPOUYr9k/E4LwqGEWcrOrq
> > rJM2U07Esu0NkQQSPZXP+NTYO9v5ztZjCLzOb0eI7tGbduW3ay7fOlawfP8fgiON
> > YVMOzcvA9DFOK7Z3ur3nCL7MWnN3OA==
> > =JFZY
> > -----END PGP SIGNATURE-----
> > 
> > 
> > 
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKFcIACgkQYgqew07V
MNU6Rgf/dePOk4Svf4RuduZErXPaVZS+RmQ7eeiirdeuBA5HwEorNRYc//gIAc2N
Cz5vtjm2DIKDcQ3kBJPaF37kdACvHOLaC4rVgoGpLlCn6hs6RNFhMOPo6ZFbbbng
wLN23bFSAaBfLjoM/0QgvIDnxqSQP/98xpRxIhEHq1buOZ1SKvaRdRHgn3Tpcu0H
KQcgaM9ao13u57kFVxLHNzPJ10b0SYIFavRUtIsw7/Miz9xBeHHnKz1Ldm3eG2e4
Ut+JlzBABOT3deviTeNSON42iwe+9L4k8sFcUK4FBoeecFfdb+znUcsT3/XkC5t3
QrZGsUKhZcTmG1vkhU/8Xqu6B6SHdw==
=P/nu
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
  2021-06-16 15:09   ` Steve Sakoman
  2021-06-16 15:17     ` Jasper Orschulko
@ 2021-06-16 15:26     ` Jasper Orschulko
  1 sibling, 0 replies; 11+ messages in thread
From: Jasper Orschulko @ 2021-06-16 15:26 UTC (permalink / raw)
  To: steve; +Cc: openembedded-core

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

P.S.: I was looking
at https://www.openembedded.org/wiki/Commit_Patch_Message_Guidelines#Example:_CVE_patch_header
and this page as far as I can tell only mentions the patch header
convention, not the file name itself. Maybe this needs an update? :)
 
- -- 
With best regards

Jasper Orschulko
DevOps Engineer

Tel. +49 30 58 58 14 265
Fax +49 30 58 58 14 999
Jasper.Orschulko@iris-sensing.com

• • • • • • • • • • • • • • • • • • • • • • • • • •

iris-GmbH
infrared & intelligent sensors
Ostendstraße 1-14 | 12459 Berlin

https://iris-sensing.com/




On Wed, 2021-06-16 at 05:09 -1000, Steve Sakoman wrote:
> On Wed, Jun 16, 2021 at 4:49 AM Jasper Orschulko
> <Jasper.Orschulko@iris-sensing.com> wrote:
> > 
> > -----BEGIN PGP SIGNED MESSAGE-----
> > Hash: SHA256
> > 
> > P.S.: I am not too familiar with expat, this particular CVE, not with
> > the practise of backporting security patches, so someone(TM) should
> > definitely take a closer look at this first.
> 
> Will do!
> 
> A few initial comments:
> 
> 1. Please don't PGP sign patch emails :-)
> 2. Change the patch file name to CVE-2013-0340.patch
> 
> Other than that it looks OK at first glance.
> 
> For reference the patch requirements for CVE's are outlined at:
> 
> https://wiki.yoctoproject.org/wiki/Security
> 
> in the "Patch name convention and commit message" section.
> 
> Thanks for helping with CVEs!
> 
> Steve
> 
> 
> 
> 
> > With best regards
> > 
> > Jasper Orschulko
> > DevOps Engineer
> > 
> > Tel. +49 30 58 58 14 265
> > Fax +49 30 58 58 14 999
> > Jasper.Orschulko@iris-sensing.com
> > 
> > • • • • • • • • • • • • • • • • • • • • • • • • • •
> > 
> > iris-GmbH
> > infrared & intelligent sensors
> > Ostendstraße 1-14 | 12459 Berlin
> > 
> > https://iris-sensing.com/
> > 
> > 
> > 
> > 
> > On Wed, 2021-06-16 at 14:44 +0000, Jasper Orschulko wrote:
> > > expat < 4.0 is vulnerable to billion laughs attacks (see
> > > [https://github.com/libexpat/libexpat/issues/34]). This patch
> > > backports
> > > the commits b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> > > and 60959f2b491876199879d97c8ed956eabb0c2e73 from upstream.
> > > 
> > > Additionally, the SRC_URI had to be adjusted due to renaming of the
> > > source archive
> > > 
> > > Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
> > > ---
> > >  ...expat-Backport-fix-for-CVE-2013-0340.patch | 1758
> > > +++++++++++++++++
> > >  meta/recipes-core/expat/expat_2.2.9.bb        |    3 +-
> > >  2 files changed, 1760 insertions(+), 1 deletion(-)
> > >  create mode 100644 meta/recipes-core/expat/expat/0001-expat-
> > > Backport-
> > > fix-for-CVE-2013-0340.patch
> > > 
> > > diff --git a/meta/recipes-core/expat/expat/0001-expat-Backport-fix-
> > > for-
> > > CVE-2013-0340.patch b/meta/recipes-core/expat/expat/0001-expat-
> > > Backport-fix-for-CVE-2013-0340.patch
> > > new file mode 100644
> > > index 0000000000..b2ca066d96
> > > --- /dev/null
> > > +++ b/meta/recipes-core/expat/expat/0001-expat-Backport-fix-for-
> > > CVE-
> > > 2013-0340.patch
> > > @@ -0,0 +1,1758 @@
> > > +From 6f68eb0439f3c1807a143ff8c8972e74d404d8f0 Mon Sep 17 00:00:00
> > > 2001
> > > +From: Sebastian Pipping <sebastian@pipping.org>
> > > +Date: Mon, 19 Apr 2021 21:42:51 +0200
> > > +Subject: [PATCH] expat: Backport fix for CVE-2013-0340
> > > +
> > > +Issue: https://github.com/libexpat/libexpat/issues/34
> > > +
> > > +This patch cherry-picks the following commits from upstream
> > > release
> > > +2.4.0 onto 2.2.9:
> > > +
> > > +- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> > > +- 60959f2b491876199879d97c8ed956eabb0c2e73
> > > +
> > > +Upstream-Status: Backport
> > > +CVE: CVE-2013-0340
> > > +Signed-off-by: Jasper Orschulko
> > > <Jasper.Orschulko@iris-sensing.com>
> > > +---
> > > + expat/lib/expat.h       |   21 +-
> > > + expat/lib/internal.h    |   30 +
> > > + expat/lib/libexpat.def  |    3 +
> > > + expat/lib/libexpatw.def |    3 +
> > > + expat/lib/xmlparse.c    | 1147
> > > +++++++++++++++++++++++++++++++++++++-
> > > -
> > > + 5 files changed, 1143 insertions(+), 61 deletions(-)
> > > +
> > > +diff --git a/expat/lib/expat.h b/expat/lib/expat.h
> > > +index 48a6e2a3..796086c2 100644
> > > +--- a/expat/lib/expat.h
> > > ++++ b/expat/lib/expat.h
> > > +@@ -115,7 +115,9 @@ enum XML_Error {
> > > +   XML_ERROR_RESERVED_PREFIX_XMLNS,
> > > +   XML_ERROR_RESERVED_NAMESPACE_URI,
> > > +   /* Added in 2.2.1. */
> > > +-  XML_ERROR_INVALID_ARGUMENT
> > > ++  XML_ERROR_INVALID_ARGUMENT,
> > > ++  /* Backported from 2.4.0. */
> > > ++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
> > > + };
> > > +
> > > + enum XML_Content_Type {
> > > +@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
> > > +   XML_FEATURE_SIZEOF_XML_LCHAR,
> > > +   XML_FEATURE_NS,
> > > +   XML_FEATURE_LARGE_SIZE,
> > > +-  XML_FEATURE_ATTR_INFO
> > > ++  XML_FEATURE_ATTR_INFO,
> > > ++  /* Added in Expat 2.4.0. */
> > > ++
> > > XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_
> > > DE
> > > FA
> > > ULT,
> > > ++
> > > XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_D
> > > EF
> > > AU
> > > LT
> > > +   /* Additional features must be added to the end of this enum.
> > > */
> > > + };
> > > +
> > > +@@ -1010,6 +1015,18 @@ typedef struct {
> > > + XMLPARSEAPI(const XML_Feature *)
> > > + XML_GetFeatureList(void);
> > > +
> > > ++#ifdef XML_DTD
> > > ++/* Backported from Expat 2.4.0. */
> > > ++XMLPARSEAPI(XML_Bool)
> > > ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> > > ++    XML_Parser parser, float maximumAmplificationFactor);
> > > ++
> > > ++/* Backported from Expat 2.4.0. */
> > > ++XMLPARSEAPI(XML_Bool)
> > > ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> > > ++    XML_Parser parser, unsigned long long
> > > activationThresholdBytes);
> > > ++#endif
> > > ++
> > > + /* Expat follows the semantic versioning convention.
> > > +    See http://semver.org.
> > > + */
> > > +diff --git a/expat/lib/internal.h b/expat/lib/internal.h
> > > +index 60913dab..d8b31fa2 100644
> > > +--- a/expat/lib/internal.h
> > > ++++ b/expat/lib/internal.h
> > > +@@ -101,10 +101,40 @@
> > > + #  endif
> > > + #endif
> > > +
> > > ++#include <limits.h> // ULONG_MAX
> > > ++
> > > ++#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
> > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
> > > ++#  else
> > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> > > ++#  endif
> > > ++#else
> > > ++#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
> > > ++#  if ! defined(ULONG_MAX)
> > > ++#    error Compiler did not define ULONG_MAX for us
> > > ++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
> > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
> > > ++#  else
> > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> > > ++#  endif
> > > ++#endif
> > > ++
> > > + #ifndef UNUSED_P
> > > + #  define UNUSED_P(p) (void)p
> > > + #endif
> > > +
> > > ++/* NOTE BEGIN If you ever patch these defaults to greater values
> > > ++              for non-attack XML payload in your environment,
> > > ++              please file a bug report with libexpat.  Thank you!
> > > ++*/
> > > ++#define
> > > \
> > > ++  100.0f
> > > ++#define
> > > \
> > > ++  8388608 // 8 MiB, 2^23
> > > ++/* NOTE END */
> > > ++
> > > + #ifdef __cplusplus
> > > + extern "C" {
> > > + #endif
> > > +diff --git a/expat/lib/libexpat.def b/expat/lib/libexpat.def
> > > +index 16faf595..b5e59d8d 100644
> > > +--- a/expat/lib/libexpat.def
> > > ++++ b/expat/lib/libexpat.def
> > > +@@ -76,3 +76,6 @@ EXPORTS
> > > +   XML_SetHashSalt @67
> > > + ; added with version 2.2.5
> > > +   _INTERNAL_trim_to_complete_utf8_characters @68
> > > ++; backported from version 2.4.0
> > > ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> > > ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
> > > +diff --git a/expat/lib/libexpatw.def b/expat/lib/libexpatw.def
> > > +index 16faf595..ebd77707 100644
> > > +--- a/expat/lib/libexpatw.def
> > > ++++ b/expat/lib/libexpatw.def
> > > +@@ -76,3 +76,6 @@ EXPORTS
> > > +   XML_SetHashSalt @67
> > > + ; added with version 2.2.5
> > > +   _INTERNAL_trim_to_complete_utf8_characters @68
> > > ++; backported from version 2.4.0
> > > ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> > > ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @7
> > > +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
> > > +index 3aaf35b9..fdcc7296 100644
> > > +--- a/expat/lib/xmlparse.c
> > > ++++ b/expat/lib/xmlparse.c
> > > +@@ -47,6 +47,8 @@
> > > + #include <limits.h> /* UINT_MAX */
> > > + #include <stdio.h>  /* fprintf */
> > > + #include <stdlib.h> /* getenv, rand_s */
> > > ++#include <stdint.h> /* uintptr_t */
> > > ++#include <math.h>   /* isnan */
> > > +
> > > + #ifdef _WIN32
> > > + #  define getpid GetCurrentProcessId
> > > +@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
> > > +   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
> > > + } OPEN_INTERNAL_ENTITY;
> > > +
> > > ++enum XML_Account {
> > > ++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the
> > > Expat
> > > parser */
> > > ++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced
> > > during
> > > entity
> > > ++                                   expansion */
> > > ++  XML_ACCOUNT_NONE              /* i.e. do not account, was
> > > accounted
> > > already */
> > > ++};
> > > ++
> > > ++#ifdef XML_DTD
> > > ++typedef unsigned long long XmlBigCount;
> > > ++typedef struct accounting {
> > > ++  XmlBigCount countBytesDirect;
> > > ++  XmlBigCount countBytesIndirect;
> > > ++  int debugLevel;
> > > ++  float maximumAmplificationFactor; // >=1.0
> > > ++  unsigned long long activationThresholdBytes;
> > > ++} ACCOUNTING;
> > > ++
> > > ++typedef struct entity_stats {
> > > ++  unsigned int countEverOpened;
> > > ++  unsigned int currentDepth;
> > > ++  unsigned int maximumDepthSeen;
> > > ++  int debugLevel;
> > > ++} ENTITY_STATS;
> > > ++#endif /* XML_DTD */
> > > ++
> > > + typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const
> > > char *start,
> > > +                                          const char *end, const
> > > char
> > > **endPtr);
> > > +
> > > +@@ -403,16 +430,18 @@ static enum XML_Error
> > > initializeEncoding(XML_Parser parser);
> > > + static enum XML_Error doProlog(XML_Parser parser, const ENCODING
> > > *enc,
> > > +                                const char *s, const char *end,
> > > int
> > > tok,
> > > +                                const char *next, const char
> > > **nextPtr,
> > > +-                               XML_Bool haveMore, XML_Bool
> > > allowClosingDoctype);
> > > ++                               XML_Bool haveMore, XML_Bool
> > > allowClosingDoctype,
> > > ++                               enum XML_Account account);
> > > + static enum XML_Error processInternalEntity(XML_Parser parser,
> > > ENTITY
> > > *entity,
> > > +                                             XML_Bool
> > > betweenDecl);
> > > + static enum XML_Error doContent(XML_Parser parser, int
> > > startTagLevel,
> > > +                                 const ENCODING *enc, const char
> > > *start,
> > > +                                 const char *end, const char
> > > **endPtr,
> > > +-                                XML_Bool haveMore);
> > > ++                                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,
> > > +@@ -422,7 +451,8 @@ static enum XML_Error
> > > doIgnoreSection(XML_Parser
> > > parser, const ENCODING *,
> > > + static void freeBindings(XML_Parser parser, BINDING *bindings);
> > > + static enum XML_Error storeAtts(XML_Parser parser, const ENCODING
> > > *,
> > > +                                 const char *s, TAG_NAME
> > > *tagNamePtr,
> > > +-                                BINDING **bindingsPtr);
> > > ++                                BINDING **bindingsPtr,
> > > ++                                enum XML_Account account);
> > > + static enum XML_Error addBinding(XML_Parser parser, PREFIX
> > > *prefix,
> > > +                                  const ATTRIBUTE_ID *attId, const
> > > XML_Char *uri,
> > > +                                  BINDING **bindingsPtr);
> > > +@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE
> > > *type,
> > > ATTRIBUTE_ID *, XML_Bool isCdata,
> > > +                            XML_Parser parser);
> > > + static enum XML_Error storeAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *,
> > > +                                           XML_Bool isCdata, const
> > > char *,
> > > +-                                          const char *,
> > > STRING_POOL
> > > *);
> > > ++                                          const char *,
> > > STRING_POOL
> > > *,
> > > ++                                          enum XML_Account
> > > account);
> > > + static enum XML_Error appendAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *,
> > > +                                            XML_Bool isCdata,
> > > const
> > > char *,
> > > +-                                           const char *,
> > > STRING_POOL
> > > *);
> > > ++                                           const char *,
> > > STRING_POOL
> > > *,
> > > ++                                           enum XML_Account
> > > account);
> > > + static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const
> > > ENCODING
> > > *enc,
> > > +                                     const char *start, const char
> > > *end);
> > > + static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE
> > > *);
> > > + static enum XML_Error storeEntityValue(XML_Parser parser, const
> > > ENCODING *enc,
> > > +-                                       const char *start, const
> > > char
> > > *end);
> > > ++                                       const char *start, const
> > > char
> > > *end,
> > > ++                                       enum XML_Account account);
> > > + static int reportProcessingInstruction(XML_Parser parser, const
> > > ENCODING *enc,
> > > +                                        const char *start, const
> > > char
> > > *end);
> > > + static int reportComment(XML_Parser parser, const ENCODING *enc,
> > > +@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const XML_Char
> > > *encodingName,
> > > +
> > > + static void parserInit(XML_Parser parser, const XML_Char
> > > *encodingName);
> > > +
> > > ++#ifdef XML_DTD
> > > ++static float accountingGetCurrentAmplification(XML_Parser
> > > rootParser);
> > > ++static void accountingReportStats(XML_Parser originParser, const
> > > char
> > > *epilog);
> > > ++static void accountingOnAbort(XML_Parser originParser);
> > > ++static void accountingReportDiff(XML_Parser rootParser,
> > > ++                                 unsigned int
> > > levelsAwayFromRootParser,
> > > ++                                 const char *before, const char
> > > *after,
> > > ++                                 ptrdiff_t bytesMore, int
> > > source_line,
> > > ++                                 enum XML_Account account);
> > > ++static XML_Bool accountingDiffTolerated(XML_Parser originParser,
> > > int
> > > tok,
> > > ++                                        const char *before, const
> > > char *after,
> > > ++                                        int source_line,
> > > ++                                        enum XML_Account
> > > account);
> > > ++
> > > ++static void entityTrackingReportStats(XML_Parser parser, ENTITY
> > > *entity,
> > > ++                                      const char *action, int
> > > sourceLine);
> > > ++static void entityTrackingOnOpen(XML_Parser parser, ENTITY
> > > *entity,
> > > ++                                 int sourceLine);
> > > ++static void entityTrackingOnClose(XML_Parser parser, ENTITY
> > > *entity,
> > > ++                                  int sourceLine);
> > > ++
> > > ++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,
> > > ++                                   unsigned long
> > > defaultDebugLevel);
> > > ++
> > > + #define poolStart(pool) ((pool)->start)
> > > + #define poolEnd(pool) ((pool)->ptr)
> > > + #define poolLength(pool) ((pool)->ptr - (pool)->start)
> > > +@@ -616,6 +678,10 @@ struct XML_ParserStruct {
> > > +   enum XML_ParamEntityParsing m_paramEntityParsing;
> > > + #endif
> > > +   unsigned long m_hash_secret_salt;
> > > ++#ifdef XML_DTD
> > > ++  ACCOUNTING m_accounting;
> > > ++  ENTITY_STATS m_entity_stats;
> > > ++#endif
> > > + };
> > > +
> > > + #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
> > > +@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const
> > > XML_Char
> > > *encodingName) {
> > > +   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
> > > + #endif
> > > +   parser->m_hash_secret_salt = 0;
> > > ++
> > > ++#ifdef XML_DTD
> > > ++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
> > > ++  parser->m_accounting.debugLevel =
> > > getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
> > > ++  parser->m_accounting.maximumAmplificationFactor
> > > ++      =
> > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAUL
> > > T;
> > > ++  parser->m_accounting.activationThresholdBytes
> > > ++      =
> > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT
> > > ;
> > > ++
> > > ++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
> > > ++  parser->m_entity_stats.debugLevel =
> > > getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
> > > ++#endif
> > > + }
> > > +
> > > + /* moves list of bindings to m_freeBindingList */
> > > +@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
> > > +   /* Added in 2.2.5. */
> > > +   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1,
> > > already */
> > > +     return XML_L("invalid argument");
> > > ++  /* Backported from 2.4.0. */
> > > ++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
> > > ++    return XML_L(
> > > ++        "limit on input amplification factor (from DTD and
> > > entities)
> > > breached");
> > > +   }
> > > +   return NULL;
> > > + }
> > > +@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
> > > +
> > > + const XML_Feature *XMLCALL
> > > + XML_GetFeatureList(void) {
> > > +-  static const XML_Feature features[]
> > > +-      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
> > > +-          sizeof(XML_Char)},
> > > +-         {XML_FEATURE_SIZEOF_XML_LCHAR,
> > > XML_L("sizeof(XML_LChar)"),
> > > +-          sizeof(XML_LChar)},
> > > ++  static const XML_Feature features[] = {
> > > ++      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
> > > ++       sizeof(XML_Char)},
> > > ++      {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
> > > ++       sizeof(XML_LChar)},
> > > + #ifdef XML_UNICODE
> > > +-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> > > ++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> > > + #endif
> > > + #ifdef XML_UNICODE_WCHAR_T
> > > +-         {XML_FEATURE_UNICODE_WCHAR_T,
> > > XML_L("XML_UNICODE_WCHAR_T"),
> > > 0},
> > > ++      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"),
> > > 0},
> > > + #endif
> > > + #ifdef XML_DTD
> > > +-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> > > ++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> > > + #endif
> > > + #ifdef XML_CONTEXT_BYTES
> > > +-         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
> > > +-          XML_CONTEXT_BYTES},
> > > ++      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
> > > ++       XML_CONTEXT_BYTES},
> > > + #endif
> > > + #ifdef XML_MIN_SIZE
> > > +-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> > > ++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> > > + #endif
> > > + #ifdef XML_NS
> > > +-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> > > ++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> > > + #endif
> > > + #ifdef XML_LARGE_SIZE
> > > +-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> > > ++      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> > > + #endif
> > > + #ifdef XML_ATTR_INFO
> > > +-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> > > ++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> > > + #endif
> > > +-         {XML_FEATURE_END, NULL, 0}};
> > > ++#ifdef XML_DTD
> > > ++      /* Added in Expat 2.4.0. */
> > > ++
> > > {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION
> > > _D
> > > EF
> > > AULT,
> > > ++       XML_L("XML_BLAP_MAX_AMP"),
> > > ++       (long int)
> > > ++
> > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAUL
> > > T}
> > > ,
> > > ++
> > > {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_
> > > DE
> > > FA
> > > ULT,
> > > ++       XML_L("XML_BLAP_ACT_THRES"),
> > > ++
> > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT
> > > },
> > > ++#endif
> > > ++      {XML_FEATURE_END, NULL, 0}};
> > > +
> > > +   return features;
> > > + }
> > > +
> > > ++#ifdef XML_DTD
> > > ++XML_Bool XMLCALL
> > > ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> > > ++    XML_Parser parser, float maximumAmplificationFactor) {
> > > ++  if ((parser == NULL) || (parser->m_parentParser != NULL)
> > > ++      || isnan(maximumAmplificationFactor)
> > > ++      || (maximumAmplificationFactor < 1.0f)) {
> > > ++    return XML_FALSE;
> > > ++  }
> > > ++  parser->m_accounting.maximumAmplificationFactor =
> > > maximumAmplificationFactor;
> > > ++  return XML_TRUE;
> > > ++}
> > > ++
> > > ++XML_Bool XMLCALL
> > > ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> > > ++    XML_Parser parser, unsigned long long
> > > activationThresholdBytes)
> > > {
> > > ++  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
> > > ++    return XML_FALSE;
> > > ++  }
> > > ++  parser->m_accounting.activationThresholdBytes =
> > > activationThresholdBytes;
> > > ++  return XML_TRUE;
> > > ++}
> > > ++#endif /* XML_DTD */
> > > ++
> > > + /* Initially tag->rawName always points into the parse buffer;
> > > +    for those TAG instances opened while the current parse buffer
> > > was
> > > +    processed, and not yet closed, we need to store tag->rawName
> > > in
> > > a
> > > more
> > > +@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
> > > + static enum XML_Error PTRCALL
> > > + contentProcessor(XML_Parser parser, const char *start, const char
> > > *end,
> > > +                  const char **endPtr) {
> > > +-  enum XML_Error result
> > > +-      = doContent(parser, 0, parser->m_encoding, start, end,
> > > endPtr,
> > > +-                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer);
> > > ++  enum XML_Error result = doContent(
> > > ++      parser, 0, parser->m_encoding, start, end, endPtr,
> > > ++      (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> > > XML_ACCOUNT_DIRECT);
> > > +   if (result == XML_ERROR_NONE) {
> > > +     if (! storeRawNames(parser))
> > > +       return XML_ERROR_NO_MEMORY;
> > > +@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser
> > > parser,
> > > const char *start,
> > > +   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
> > > +   switch (tok) {
> > > +   case XML_TOK_BOM:
> > > ++#ifdef XML_DTD
> > > ++    if (! accountingDiffTolerated(parser, tok, start, next,
> > > __LINE__,
> > > ++                                  XML_ACCOUNT_DIRECT)) {
> > > ++      accountingOnAbort(parser);
> > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++    }
> > > ++#endif /* XML_DTD */
> > > ++
> > > +     /* If we are at the end of the buffer, this would cause the
> > > next
> > > stage,
> > > +        i.e. externalEntityInitProcessor3, to pass control
> > > directly
> > > to
> > > +        doContent (by detecting XML_TOK_NONE) without processing
> > > any
> > > xml text
> > > +@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser
> > > parser,
> > > const char *start,
> > > +   const char *next = start; /* XmlContentTok doesn't always set
> > > the
> > > last arg */
> > > +   parser->m_eventPtr = start;
> > > +   tok = XmlContentTok(parser->m_encoding, start, end, &next);
> > > ++  /* Note: These bytes are accounted later in:
> > > ++           - processXmlDecl
> > > ++           - externalEntityContentProcessor
> > > ++  */
> > > +   parser->m_eventEndPtr = next;
> > > +
> > > +   switch (tok) {
> > > +@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser
> > > parser, const char *start,
> > > +                                const char *end, const char
> > > **endPtr)
> > > {
> > > +   enum XML_Error result
> > > +       = doContent(parser, 1, parser->m_encoding, start, end,
> > > endPtr,
> > > +-                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer);
> > > ++                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer,
> > > ++                  XML_ACCOUNT_ENTITY_EXPANSION);
> > > +   if (result == XML_ERROR_NONE) {
> > > +     if (! storeRawNames(parser))
> > > +       return XML_ERROR_NO_MEMORY;
> > > +@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser
> > > parser, const char *start,
> > > + static enum XML_Error
> > > + doContent(XML_Parser parser, int startTagLevel, const ENCODING
> > > *enc,
> > > +           const char *s, const char *end, const char **nextPtr,
> > > +-          XML_Bool haveMore) {
> > > ++          XML_Bool haveMore, enum XML_Account account) {
> > > +   /* save one level of indirection */
> > > +   DTD *const dtd = parser->m_dtd;
> > > +
> > > +@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int
> > > startTagLevel,
> > > const ENCODING *enc,
> > > +   for (;;) {
> > > +     const char *next = s; /* XmlContentTok doesn't always set the
> > > last arg */
> > > +     int tok = XmlContentTok(enc, s, end, &next);
> > > ++#ifdef XML_DTD
> > > ++    const char *accountAfter
> > > ++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok ==
> > > XML_TOK_TRAILING_CR))
> > > ++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
> > > ++              : next;
> > > ++    if (! accountingDiffTolerated(parser, tok, s, accountAfter,
> > > __LINE__,
> > > ++                                  account)) {
> > > ++      accountingOnAbort(parser);
> > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++    }
> > > ++#endif
> > > +     *eventEndPP = next;
> > > +     switch (tok) {
> > > +     case XML_TOK_TRAILING_CR:
> > > +@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int
> > > startTagLevel,
> > > const ENCODING *enc,
> > > +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> > > +           enc, s + enc->minBytesPerChar, next - enc-
> > > > minBytesPerChar);
> > > +       if (ch) {
> > > ++#ifdef XML_DTD
> > > ++        /* NOTE: We are replacing 4-6 characters original input
> > > for
> > > 1
> > > character
> > > ++         *       so there is no amplification and hence recording
> > > without
> > > ++         *       protection. */
> > > ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> > > ++                                ((char *)&ch) + sizeof(XML_Char),
> > > __LINE__,
> > > ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> > > ++#endif /* XML_DTD */
> > > +         if (parser->m_characterDataHandler)
> > > +           parser->m_characterDataHandler(parser->m_handlerArg,
> > > &ch,
> > > 1);
> > > +         else if (parser->m_defaultHandler)
> > > +@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int
> > > startTagLevel,
> > > const ENCODING *enc,
> > > +       }
> > > +       tag->name.str = (XML_Char *)tag->buf;
> > > +       *toPtr = XML_T('\0');
> > > +-      result = storeAtts(parser, enc, s, &(tag->name), &(tag-
> > > > bindings));
> > > ++      result
> > > ++          = storeAtts(parser, enc, s, &(tag->name), &(tag-
> > > > bindings),
> > > account);
> > > +       if (result)
> > > +         return result;
> > > +       if (parser->m_startElementHandler)
> > > +@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int
> > > startTagLevel,
> > > const ENCODING *enc,
> > > +       if (! name.str)
> > > +         return XML_ERROR_NO_MEMORY;
> > > +       poolFinish(&parser->m_tempPool);
> > > +-      result = storeAtts(parser, enc, s, &name, &bindings);
> > > ++      result = storeAtts(parser, enc, s, &name, &bindings,
> > > ++                         XML_ACCOUNT_NONE /* token spans whole
> > > start
> > > tag */);
> > > +       if (result != XML_ERROR_NONE) {
> > > +         freeBindings(parser, bindings);
> > > +         return result;
> > > +@@ -2907,7 +3057,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) {
> > > +@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING
> > > *bindings) {
> > > + */
> > > + static enum XML_Error
> > > + storeAtts(XML_Parser parser, const ENCODING *enc, const char
> > > *attStr,
> > > +-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
> > > ++          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
> > > ++          enum XML_Account account) {
> > > +   DTD *const dtd = parser->m_dtd; /* save one level of
> > > indirection
> > > */
> > > +   ELEMENT_TYPE *elementType;
> > > +   int nDefaultAtts;
> > > +@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const ENCODING
> > > *enc, const char *attStr,
> > > +       /* normalize the attribute value */
> > > +       result = storeAttributeValue(
> > > +           parser, enc, isCdata, parser->m_atts[i].valuePtr,
> > > +-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
> > > ++          parser->m_atts[i].valueEnd, &parser->m_tempPool,
> > > account);
> > > +       if (result)
> > > +         return result;
> > > +       appAtts[attIndex] = poolStart(&parser->m_tempPool);
> > > +@@ -3535,9 +3687,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) {
> > > +@@ -3557,7 +3709,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;
> > > +@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const
> > > ENCODING *enc, const char **startPtr,
> > > +   for (;;) {
> > > +     const char *next;
> > > +     int tok = XmlCdataSectionTok(enc, s, end, &next);
> > > ++#ifdef XML_DTD
> > > ++    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) {
> > > +     case XML_TOK_CDATA_SECT_CLOSE:
> > > +@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const
> > > ENCODING *enc, const char **startPtr,
> > > +   *eventPP = s;
> > > +   *startPtr = NULL;
> > > +   tok = XmlIgnoreSectionTok(enc, s, end, &next);
> > > ++#  ifdef XML_DTD
> > > ++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> > > ++                                XML_ACCOUNT_DIRECT)) {
> > > ++    accountingOnAbort(parser);
> > > ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++  }
> > > ++#  endif
> > > +   *eventEndPP = next;
> > > +   switch (tok) {
> > > +   case XML_TOK_IGNORE_SECT:
> > > +@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int
> > > isGeneralTextEntity, const char *s,
> > > +   const char *versionend;
> > > +   const XML_Char *storedversion = NULL;
> > > +   int standalone = -1;
> > > ++
> > > ++#ifdef XML_DTD
> > > ++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s,
> > > next,
> > > __LINE__,
> > > ++                                XML_ACCOUNT_DIRECT)) {
> > > ++    accountingOnAbort(parser);
> > > ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++  }
> > > ++#endif
> > > ++
> > > +   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
> > > +           isGeneralTextEntity, parser->m_encoding, s, next,
> > > &parser-
> > > > m_eventPtr,
> > > +           &version, &versionend, &encodingName, &newEncoding,
> > > &standalone)) {
> > > +@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser parser,
> > > const char *s, const char *end,
> > > +
> > > +   for (;;) {
> > > +     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
> > > ++    /* Note: Except for XML_TOK_BOM below, these bytes are
> > > accounted
> > > later in:
> > > ++             - storeEntityValue
> > > ++             - processXmlDecl
> > > ++    */
> > > +     parser->m_eventEndPtr = next;
> > > +     if (tok <= 0) {
> > > +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> > > XML_TOK_INVALID) {
> > > +@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser parser,
> > > const char *s, const char *end,
> > > +         break;
> > > +       }
> > > +       /* found end of entity value - can store it now */
> > > +-      return storeEntityValue(parser, parser->m_encoding, s,
> > > end);
> > > ++      return storeEntityValue(parser, parser->m_encoding, s, end,
> > > ++                              XML_ACCOUNT_DIRECT);
> > > +     } else if (tok == XML_TOK_XML_DECL) {
> > > +       enum XML_Error result;
> > > +       result = processXmlDecl(parser, 0, start, next);
> > > +@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser parser,
> > > const char *s, const char *end,
> > > +     */
> > > +     else if (tok == XML_TOK_BOM && next == end
> > > +              && ! parser->m_parsingStatus.finalBuffer) {
> > > ++#  ifdef XML_DTD
> > > ++      if (! accountingDiffTolerated(parser, tok, s, next,
> > > __LINE__,
> > > ++                                    XML_ACCOUNT_DIRECT)) {
> > > ++        accountingOnAbort(parser);
> > > ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++      }
> > > ++#  endif
> > > ++
> > > +       *nextPtr = next;
> > > +       return XML_ERROR_NONE;
> > > +     }
> > > +@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser parser,
> > > const char *s, const char *end,
> > > +   }
> > > +   /* This would cause the next stage, i.e. doProlog to be passed
> > > XML_TOK_BOM.
> > > +      However, when parsing an external subset, doProlog will not
> > > accept a BOM
> > > +-     as valid, and report a syntax error, so we have to skip the
> > > BOM
> > > ++     as valid, and report a syntax error, so we have to skip the
> > > BOM,
> > > and
> > > ++     account for the BOM bytes.
> > > +   */
> > > +   else if (tok == XML_TOK_BOM) {
> > > ++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> > > ++                                  XML_ACCOUNT_DIRECT)) {
> > > ++      accountingOnAbort(parser);
> > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++    }
> > > ++
> > > +     s = next;
> > > +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > +   }
> > > +
> > > +   parser->m_processor = prologProcessor;
> > > +   return doProlog(parser, parser->m_encoding, s, end, tok, next,
> > > nextPtr,
> > > +-                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer,
> > > XML_TRUE);
> > > ++                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer,
> > > XML_TRUE,
> > > ++                  XML_ACCOUNT_DIRECT);
> > > + }
> > > +
> > > + static enum XML_Error PTRCALL
> > > +@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser,
> > > const
> > > char *s, const char *end,
> > > +
> > > +   for (;;) {
> > > +     tok = XmlPrologTok(enc, start, end, &next);
> > > ++    /* Note: These bytes are accounted later in:
> > > ++             - storeEntityValue
> > > ++    */
> > > +     if (tok <= 0) {
> > > +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> > > XML_TOK_INVALID) {
> > > +         *nextPtr = s;
> > > +@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser,
> > > const
> > > char *s, const char *end,
> > > +         break;
> > > +       }
> > > +       /* found end of entity value - can store it now */
> > > +-      return storeEntityValue(parser, enc, s, end);
> > > ++      return storeEntityValue(parser, enc, s, end,
> > > XML_ACCOUNT_DIRECT);
> > > +     }
> > > +     start = next;
> > > +   }
> > > +@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const
> > > char
> > > *s, const char *end,
> > > +   const char *next = s;
> > > +   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > +   return doProlog(parser, parser->m_encoding, s, end, tok, next,
> > > nextPtr,
> > > +-                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer,
> > > XML_TRUE);
> > > ++                  (XML_Bool)! parser-
> > > >m_parsingStatus.finalBuffer,
> > > XML_TRUE,
> > > ++                  XML_ACCOUNT_DIRECT);
> > > + }
> > > +
> > > + static enum XML_Error
> > > + doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
> > > const
> > > char *end,
> > > +          int tok, const char *next, const char **nextPtr,
> > > XML_Bool
> > > haveMore,
> > > +-         XML_Bool allowClosingDoctype) {
> > > ++         XML_Bool allowClosingDoctype, enum XML_Account account)
> > > {
> > > + #ifdef XML_DTD
> > > +   static const XML_Char externalSubsetName[] = {ASCII_HASH,
> > > '\0'};
> > > + #endif /* XML_DTD */
> > > +@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const ENCODING
> > > *enc, const char *s, const char *end,
> > > +   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
> > > +   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
> > > +
> > > ++#ifndef XML_DTD
> > > ++  UNUSED_P(account);
> > > ++#endif
> > > ++
> > > +   /* save one level of indirection */
> > > +   DTD *const dtd = parser->m_dtd;
> > > +
> > > +@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const ENCODING
> > > *enc, const char *s, const char *end,
> > > +       }
> > > +     }
> > > +     role = XmlTokenRole(&parser->m_prologState, tok, s, next,
> > > enc);
> > > ++#ifdef XML_DTD
> > > ++    switch (role) {
> > > ++    case XML_ROLE_INSTANCE_START: // bytes accounted in
> > > contentProcessor
> > > ++    case XML_ROLE_XML_DECL:       // bytes accounted in
> > > processXmlDecl
> > > ++    case XML_ROLE_TEXT_DECL:      // bytes accounted in
> > > processXmlDecl
> > > ++      break;
> > > ++    default:
> > > ++      if (! accountingDiffTolerated(parser, tok, s, next,
> > > __LINE__,
> > > account)) {
> > > ++        accountingOnAbort(parser);
> > > ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++      }
> > > ++    }
> > > ++#endif
> > > +     switch (role) {
> > > +     case XML_ROLE_XML_DECL: {
> > > +       enum XML_Error result = processXmlDecl(parser, 0, s, next);
> > > +@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING
> > > *enc,
> > > const char *s, const char *end,
> > > +         const XML_Char *attVal;
> > > +         enum XML_Error result = storeAttributeValue(
> > > +             parser, enc, parser->m_declAttributeIsCdata,
> > > +-            s + enc->minBytesPerChar, next - enc-
> > > >minBytesPerChar,
> > > &dtd->pool);
> > > ++            s + enc->minBytesPerChar, next - enc-
> > > >minBytesPerChar,
> > > &dtd->pool,
> > > ++            XML_ACCOUNT_NONE);
> > > +         if (result)
> > > +           return result;
> > > +         attVal = poolStart(&dtd->pool);
> > > +@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING
> > > *enc,
> > > const char *s, const char *end,
> > > +       break;
> > > +     case XML_ROLE_ENTITY_VALUE:
> > > +       if (dtd->keepProcessing) {
> > > +-        enum XML_Error result = storeEntityValue(
> > > +-            parser, enc, s + enc->minBytesPerChar, next - enc-
> > > > minBytesPerChar);
> > > ++        enum XML_Error result
> > > ++            = storeEntityValue(parser, enc, s + enc-
> > > > minBytesPerChar,
> > > ++                               next - enc->minBytesPerChar,
> > > XML_ACCOUNT_NONE);
> > > +         if (parser->m_declEntity) {
> > > +           parser->m_declEntity->textPtr = poolStart(&dtd-
> > > > entityValuePool);
> > > +           parser->m_declEntity->textLen
> > > +@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const ENCODING
> > > *enc, const char *s, const char *end,
> > > +         if (parser->m_externalEntityRefHandler) {
> > > +           dtd->paramEntityRead = XML_FALSE;
> > > +           entity->open = XML_TRUE;
> > > ++          entityTrackingOnOpen(parser, entity, __LINE__);
> > > +           if (! parser->m_externalEntityRefHandler(
> > > +                   parser->m_externalEntityRefHandlerArg, 0,
> > > entity-
> > > > base,
> > > +                   entity->systemId, entity->publicId)) {
> > > ++            entityTrackingOnClose(parser, entity, __LINE__);
> > > +             entity->open = XML_FALSE;
> > > +             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> > > +           }
> > > ++          entityTrackingOnClose(parser, entity, __LINE__);
> > > +           entity->open = XML_FALSE;
> > > +           handleDefault = XML_FALSE;
> > > +           if (! dtd->paramEntityRead) {
> > > +@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const
> > > char
> > > *s, const char *end,
> > > +   for (;;) {
> > > +     const char *next = NULL;
> > > +     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > ++#ifdef XML_DTD
> > > ++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> > > ++                                  XML_ACCOUNT_DIRECT)) {
> > > ++      accountingOnAbort(parser);
> > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++    }
> > > ++#endif
> > > +     parser->m_eventEndPtr = next;
> > > +     switch (tok) {
> > > +     /* report partial linebreak - it might be the last token */
> > > +@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser,
> > > ENTITY
> > > *entity, XML_Bool betweenDecl) {
> > > +       return XML_ERROR_NO_MEMORY;
> > > +   }
> > > +   entity->open = XML_TRUE;
> > > ++#ifdef XML_DTD
> > > ++  entityTrackingOnOpen(parser, entity, __LINE__);
> > > ++#endif
> > > +   entity->processed = 0;
> > > +   openEntity->next = parser->m_openInternalEntities;
> > > +   parser->m_openInternalEntities = openEntity;
> > > +@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser,
> > > ENTITY *entity, XML_Bool betweenDecl) {
> > > +     int tok
> > > +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> > > textEnd, &next);
> > > +     result = doProlog(parser, parser->m_internalEncoding,
> > > textStart,
> > > textEnd,
> > > +-                      tok, next, &next, XML_FALSE, XML_FALSE);
> > > ++                      tok, next, &next, XML_FALSE, XML_FALSE,
> > > ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> > > +   } else
> > > + #endif /* XML_DTD */
> > > +     result = doContent(parser, parser->m_tagLevel, parser-
> > > > m_internalEncoding,
> > > +-                       textStart, textEnd, &next, XML_FALSE);
> > > ++                       textStart, textEnd, &next, XML_FALSE,
> > > ++                       XML_ACCOUNT_ENTITY_EXPANSION);
> > > +
> > > +   if (result == XML_ERROR_NONE) {
> > > +     if (textEnd != next && parser->m_parsingStatus.parsing ==
> > > XML_SUSPENDED) {
> > > +       entity->processed = (int)(next - textStart);
> > > +       parser->m_processor = internalEntityProcessor;
> > > +     } else {
> > > ++#ifdef XML_DTD
> > > ++      entityTrackingOnClose(parser, entity, __LINE__);
> > > ++#endif /* XML_DTD */
> > > +       entity->open = XML_FALSE;
> > > +       parser->m_openInternalEntities = openEntity->next;
> > > +       /* put openEntity back in list of free instances */
> > > +@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser parser,
> > > const char *s, const char *end,
> > > +     int tok
> > > +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> > > textEnd, &next);
> > > +     result = doProlog(parser, parser->m_internalEncoding,
> > > textStart,
> > > textEnd,
> > > +-                      tok, next, &next, XML_FALSE, XML_TRUE);
> > > ++                      tok, next, &next, XML_FALSE, XML_TRUE,
> > > ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> > > +   } else
> > > + #endif /* XML_DTD */
> > > +     result = doContent(parser, openEntity->startTagLevel,
> > > +                        parser->m_internalEncoding, textStart,
> > > textEnd, &next,
> > > +-                       XML_FALSE);
> > > ++                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
> > > +
> > > +   if (result != XML_ERROR_NONE)
> > > +     return result;
> > > +@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser,
> > > const
> > > char *s, const char *end,
> > > +     entity->processed = (int)(next - (char *)entity->textPtr);
> > > +     return result;
> > > +   } else {
> > > ++#ifdef XML_DTD
> > > ++    entityTrackingOnClose(parser, entity, __LINE__);
> > > ++#endif
> > > +     entity->open = XML_FALSE;
> > > +     parser->m_openInternalEntities = openEntity->next;
> > > +     /* put openEntity back in list of free instances */
> > > +@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser,
> > > const
> > > char *s, const char *end,
> > > +     parser->m_processor = prologProcessor;
> > > +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > +     return doProlog(parser, parser->m_encoding, s, end, tok,
> > > next,
> > > nextPtr,
> > > +-                    (XML_Bool)! parser-
> > > > m_parsingStatus.finalBuffer,
> > > XML_TRUE);
> > > ++                    (XML_Bool)! parser-
> > > > m_parsingStatus.finalBuffer,
> > > XML_TRUE,
> > > ++                    XML_ACCOUNT_DIRECT);
> > > +   } else
> > > + #endif /* XML_DTD */
> > > +   {
> > > +@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser,
> > > const
> > > char *s, const char *end,
> > > +     /* see externalEntityContentProcessor vs contentProcessor */
> > > +     return doContent(parser, parser->m_parentParser ? 1 : 0,
> > > parser-
> > > > m_encoding,
> > > +                      s, end, nextPtr,
> > > +-                     (XML_Bool)! parser-
> > > > m_parsingStatus.finalBuffer);
> > > ++                     (XML_Bool)! parser-
> > > > m_parsingStatus.finalBuffer,
> > > ++                     XML_ACCOUNT_DIRECT);
> > > +   }
> > > + }
> > > +
> > > +@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const
> > > char
> > > *s, const char *end,
> > > +
> > > + static enum XML_Error
> > > + storeAttributeValue(XML_Parser parser, const ENCODING *enc,
> > > XML_Bool
> > > isCdata,
> > > +-                    const char *ptr, const char *end, STRING_POOL
> > > *pool) {
> > > ++                    const char *ptr, const char *end, STRING_POOL
> > > *pool,
> > > ++                    enum XML_Account account) {
> > > +   enum XML_Error result
> > > +-      = appendAttributeValue(parser, enc, isCdata, ptr, end,
> > > pool);
> > > ++      = appendAttributeValue(parser, enc, isCdata, ptr, end,
> > > pool,
> > > account);
> > > +   if (result)
> > > +     return result;
> > > +   if (! isCdata && poolLength(pool) && poolLastChar(pool) ==
> > > 0x20)
> > > +@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *enc, XML_Bool isCdata,
> > > +
> > > + static enum XML_Error
> > > + appendAttributeValue(XML_Parser parser, const ENCODING *enc,
> > > XML_Bool
> > > isCdata,
> > > +-                     const char *ptr, const char *end,
> > > STRING_POOL
> > > *pool) {
> > > ++                     const char *ptr, const char *end,
> > > STRING_POOL
> > > *pool,
> > > ++                     enum XML_Account account) {
> > > +   DTD *const dtd = parser->m_dtd; /* save one level of
> > > indirection
> > > */
> > > ++#ifndef XML_DTD
> > > ++  UNUSED_P(account);
> > > ++#endif
> > > ++
> > > +   for (;;) {
> > > +     const char *next;
> > > +     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
> > > ++#ifdef XML_DTD
> > > ++    if (! accountingDiffTolerated(parser, tok, ptr, next,
> > > __LINE__,
> > > account)) {
> > > ++      accountingOnAbort(parser);
> > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++    }
> > > ++#endif
> > > +     switch (tok) {
> > > +     case XML_TOK_NONE:
> > > +       return XML_ERROR_NONE;
> > > +@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *enc, XML_Bool isCdata,
> > > +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> > > +           enc, ptr + enc->minBytesPerChar, next - enc-
> > > > minBytesPerChar);
> > > +       if (ch) {
> > > ++#ifdef XML_DTD
> > > ++        /* NOTE: We are replacing 4-6 characters original input
> > > for
> > > 1
> > > character
> > > ++         *       so there is no amplification and hence recording
> > > without
> > > ++         *       protection. */
> > > ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> > > ++                                ((char *)&ch) + sizeof(XML_Char),
> > > __LINE__,
> > > ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> > > ++#endif /* XML_DTD */
> > > +         if (! poolAppendChar(pool, ch))
> > > +           return XML_ERROR_NO_MEMORY;
> > > +         break;
> > > +@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *enc, XML_Bool isCdata,
> > > +         enum XML_Error result;
> > > +         const XML_Char *textEnd = entity->textPtr + entity-
> > > > textLen;
> > > +         entity->open = XML_TRUE;
> > > ++#ifdef XML_DTD
> > > ++        entityTrackingOnOpen(parser, entity, __LINE__);
> > > ++#endif
> > > +         result = appendAttributeValue(parser, parser-
> > > > m_internalEncoding,
> > > +-                                      isCdata, (char *)entity-
> > > > textPtr,
> > > +-                                      (char *)textEnd, pool);
> > > ++                                      isCdata, (const char
> > > *)entity-
> > > > textPtr,
> > > ++                                      (const char *)textEnd,
> > > pool,
> > > ++
> > > XML_ACCOUNT_ENTITY_EXPANSION);
> > > ++#ifdef XML_DTD
> > > ++        entityTrackingOnClose(parser, entity, __LINE__);
> > > ++#endif
> > > +         entity->open = XML_FALSE;
> > > +         if (result)
> > > +           return result;
> > > +@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser,
> > > const
> > > ENCODING *enc, XML_Bool isCdata,
> > > +
> > > + static enum XML_Error
> > > + storeEntityValue(XML_Parser parser, const ENCODING *enc,
> > > +-                 const char *entityTextPtr, const char
> > > *entityTextEnd) {
> > > ++                 const char *entityTextPtr, const char
> > > *entityTextEnd,
> > > ++                 enum XML_Account account) {
> > > +   DTD *const dtd = parser->m_dtd; /* save one level of
> > > indirection
> > > */
> > > +   STRING_POOL *pool = &(dtd->entityValuePool);
> > > +   enum XML_Error result = XML_ERROR_NONE;
> > > + #ifdef XML_DTD
> > > +   int oldInEntityValue = parser->m_prologState.inEntityValue;
> > > +   parser->m_prologState.inEntityValue = 1;
> > > ++#else
> > > ++  UNUSED_P(account);
> > > + #endif /* XML_DTD */
> > > +   /* never return Null for the value argument in
> > > EntityDeclHandler,
> > > +      since this would indicate an external entity; therefore we
> > > +@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const
> > > ENCODING *enc,
> > > +   for (;;) {
> > > +     const char *next;
> > > +     int tok = XmlEntityValueTok(enc, entityTextPtr,
> > > entityTextEnd,
> > > &next);
> > > ++
> > > ++#ifdef XML_DTD
> > > ++    if (! accountingDiffTolerated(parser, tok, entityTextPtr,
> > > next,
> > > __LINE__,
> > > ++                                  account)) {
> > > ++      accountingOnAbort(parser);
> > > ++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > ++      goto endEntityValue;
> > > ++    }
> > > ++#endif
> > > ++
> > > +     switch (tok) {
> > > +     case XML_TOK_PARAM_ENTITY_REF:
> > > + #ifdef XML_DTD
> > > +@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser, const
> > > ENCODING *enc,
> > > +           if (parser->m_externalEntityRefHandler) {
> > > +             dtd->paramEntityRead = XML_FALSE;
> > > +             entity->open = XML_TRUE;
> > > ++            entityTrackingOnOpen(parser, entity, __LINE__);
> > > +             if (! parser->m_externalEntityRefHandler(
> > > +                     parser->m_externalEntityRefHandlerArg, 0,
> > > entity-
> > > > base,
> > > +                     entity->systemId, entity->publicId)) {
> > > ++              entityTrackingOnClose(parser, entity, __LINE__);
> > > +               entity->open = XML_FALSE;
> > > +               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> > > +               goto endEntityValue;
> > > +             }
> > > ++            entityTrackingOnClose(parser, entity, __LINE__);
> > > +             entity->open = XML_FALSE;
> > > +             if (! dtd->paramEntityRead)
> > > +               dtd->keepProcessing = dtd->standalone;
> > > +@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const
> > > ENCODING *enc,
> > > +             dtd->keepProcessing = dtd->standalone;
> > > +         } else {
> > > +           entity->open = XML_TRUE;
> > > ++          entityTrackingOnOpen(parser, entity, __LINE__);
> > > +           result = storeEntityValue(
> > > +-              parser, parser->m_internalEncoding, (char *)entity-
> > > > textPtr,
> > > +-              (char *)(entity->textPtr + entity->textLen));
> > > ++              parser, parser->m_internalEncoding, (const char
> > > *)entity->textPtr,
> > > ++              (const char *)(entity->textPtr + entity->textLen),
> > > ++              XML_ACCOUNT_ENTITY_EXPANSION);
> > > ++          entityTrackingOnClose(parser, entity, __LINE__);
> > > +           entity->open = XML_FALSE;
> > > +           if (result)
> > > +             goto endEntityValue;
> > > +@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const
> > > XML_Memory_Handling_Suite *memsuite) {
> > > +   memcpy(result, s, charsRequired * sizeof(XML_Char));
> > > +   return result;
> > > + }
> > > ++
> > > ++#ifdef XML_DTD
> > > ++
> > > ++static float
> > > ++accountingGetCurrentAmplification(XML_Parser rootParser) {
> > > ++  const XmlBigCount countBytesOutput
> > > ++      = rootParser->m_accounting.countBytesDirect
> > > ++        + rootParser->m_accounting.countBytesIndirect;
> > > ++  const float amplificationFactor
> > > ++      = rootParser->m_accounting.countBytesDirect
> > > ++            ? (countBytesOutput
> > > ++               / (float)(rootParser-
> > > > m_accounting.countBytesDirect))
> > > ++            : 1.0f;
> > > ++  assert(! rootParser->m_parentParser);
> > > ++  return amplificationFactor;
> > > ++}
> > > ++
> > > ++static void
> > > ++accountingReportStats(XML_Parser originParser, const char
> > > *epilog)
> > > {
> > > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > > NULL);
> > > ++  assert(! rootParser->m_parentParser);
> > > ++
> > > ++  if (rootParser->m_accounting.debugLevel < 1) {
> > > ++    return;
> > > ++  }
> > > ++
> > > ++  const float amplificationFactor
> > > ++      = accountingGetCurrentAmplification(rootParser);
> > > ++  fprintf(stderr,
> > > ++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
> > > ++              "10") ", indirect " EXPAT_FMT_ULL("10") ",
> > > amplification %8.2f%s",
> > > ++          (void *)rootParser, rootParser-
> > > > m_accounting.countBytesDirect,
> > > ++          rootParser->m_accounting.countBytesIndirect,
> > > ++          (double)amplificationFactor, epilog);
> > > ++}
> > > ++
> > > ++static void
> > > ++accountingOnAbort(XML_Parser originParser) {
> > > ++  accountingReportStats(originParser, " ABORTING\n");
> > > ++}
> > > ++
> > > ++static void
> > > ++accountingReportDiff(XML_Parser rootParser,
> > > ++                     unsigned int levelsAwayFromRootParser, const
> > > char *before,
> > > ++                     const char *after, ptrdiff_t bytesMore, int
> > > source_line,
> > > ++                     enum XML_Account account) {
> > > ++  assert(! rootParser->m_parentParser);
> > > ++
> > > ++  fprintf(stderr,
> > > ++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d,
> > > xmlparse.c:%d) %*s\"",
> > > ++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" :
> > > "EXP",
> > > ++          levelsAwayFromRootParser, source_line, 10, "");
> > > ++
> > > ++  const char ellipis[] = "[..]";
> > > ++  const size_t ellipsisLength = sizeof(ellipis) /* because
> > > compile-
> > > time */ - 1;
> > > ++  const unsigned int contextLength = 10;
> > > ++
> > > ++  /* Note: Performance is of no concern here */
> > > ++  const char *walker = before;
> > > ++  if ((rootParser->m_accounting.debugLevel >= 3)
> > > ++      || (after - before)
> > > ++             <= (ptrdiff_t)(contextLength + ellipsisLength +
> > > contextLength)) {
> > > ++    for (; walker < after; walker++) {
> > > ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> > > ++    }
> > > ++  } else {
> > > ++    for (; walker < before + contextLength; walker++) {
> > > ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> > > ++    }
> > > ++    fprintf(stderr, ellipis);
> > > ++    walker = after - contextLength;
> > > ++    for (; walker < after; walker++) {
> > > ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> > > ++    }
> > > ++  }
> > > ++  fprintf(stderr, "\"\n");
> > > ++}
> > > ++
> > > ++static XML_Bool
> > > ++accountingDiffTolerated(XML_Parser originParser, int tok, const
> > > char
> > > *before,
> > > ++                        const char *after, int source_line,
> > > ++                        enum XML_Account account) {
> > > ++  /* Note: We need to check the token type *first* to be sure
> > > that
> > > ++   *       we can even access variable <after>, safely.
> > > ++   *       E.g. for XML_TOK_NONE <after> may hold an invalid
> > > pointer.
> > > */
> > > ++  switch (tok) {
> > > ++  case XML_TOK_INVALID:
> > > ++  case XML_TOK_PARTIAL:
> > > ++  case XML_TOK_PARTIAL_CHAR:
> > > ++  case XML_TOK_NONE:
> > > ++    return XML_TRUE;
> > > ++  }
> > > ++
> > > ++  if (account == XML_ACCOUNT_NONE)
> > > ++    return XML_TRUE; /* because these bytes have been accounted
> > > for,
> > > already */
> > > ++
> > > ++  unsigned int levelsAwayFromRootParser;
> > > ++  const XML_Parser rootParser
> > > ++      = getRootParserOf(originParser, &levelsAwayFromRootParser);
> > > ++  assert(! rootParser->m_parentParser);
> > > ++
> > > ++  const int isDirect
> > > ++      = (account == XML_ACCOUNT_DIRECT) && (originParser ==
> > > rootParser);
> > > ++  const ptrdiff_t bytesMore = after - before;
> > > ++
> > > ++  XmlBigCount *const additionTarget
> > > ++      = isDirect ? &rootParser->m_accounting.countBytesDirect
> > > ++                 : &rootParser->m_accounting.countBytesIndirect;
> > > ++
> > > ++  /* Detect and avoid integer overflow */
> > > ++  if (*additionTarget > (XmlBigCount)(-1) -
> > > (XmlBigCount)bytesMore)
> > > ++    return XML_FALSE;
> > > ++  *additionTarget += bytesMore;
> > > ++
> > > ++  const XmlBigCount countBytesOutput
> > > ++      = rootParser->m_accounting.countBytesDirect
> > > ++        + rootParser->m_accounting.countBytesIndirect;
> > > ++  const float amplificationFactor
> > > ++      = accountingGetCurrentAmplification(rootParser);
> > > ++  const XML_Bool tolerated
> > > ++      = (countBytesOutput < rootParser-
> > > > m_accounting.activationThresholdBytes)
> > > ++        || (amplificationFactor
> > > ++            <= rootParser-
> > > > m_accounting.maximumAmplificationFactor);
> > > ++
> > > ++  if (rootParser->m_accounting.debugLevel >= 2) {
> > > ++    accountingReportStats(rootParser, "");
> > > ++    accountingReportDiff(rootParser, levelsAwayFromRootParser,
> > > before, after,
> > > ++                         bytesMore, source_line, account);
> > > ++  }
> > > ++
> > > ++  return tolerated;
> > > ++}
> > > ++
> > > ++static void
> > > ++entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
> > > ++                          const char *action, int sourceLine) {
> > > ++  assert(! rootParser->m_parentParser);
> > > ++  if (rootParser->m_entity_stats.debugLevel < 1)
> > > ++    return;
> > > ++
> > > ++#  if defined(XML_UNICODE)
> > > ++  const char *const entityName = "[..]";
> > > ++#  else
> > > ++  const char *const entityName = entity->name;
> > > ++#  endif
> > > ++
> > > ++  fprintf(
> > > ++      stderr,
> > > ++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s
> > > length %d (xmlparse.c:%d)\n",
> > > ++      (void *)rootParser, rootParser-
> > > > m_entity_stats.countEverOpened,
> > > ++      rootParser->m_entity_stats.currentDepth,
> > > ++      rootParser->m_entity_stats.maximumDepthSeen,
> > > ++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
> > > ++      entity->is_param ? "%" : "&", entityName, action, entity-
> > > > textLen,
> > > ++      sourceLine);
> > > ++}
> > > ++
> > > ++static void
> > > ++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int
> > > sourceLine) {
> > > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > > NULL);
> > > ++  assert(! rootParser->m_parentParser);
> > > ++
> > > ++  rootParser->m_entity_stats.countEverOpened++;
> > > ++  rootParser->m_entity_stats.currentDepth++;
> > > ++  if (rootParser->m_entity_stats.currentDepth
> > > ++      > rootParser->m_entity_stats.maximumDepthSeen) {
> > > ++    rootParser->m_entity_stats.maximumDepthSeen++;
> > > ++  }
> > > ++
> > > ++  entityTrackingReportStats(rootParser, entity, "OPEN ",
> > > sourceLine);
> > > ++}
> > > ++
> > > ++static void
> > > ++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity,
> > > int
> > > sourceLine) {
> > > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > > NULL);
> > > ++  assert(! rootParser->m_parentParser);
> > > ++
> > > ++  entityTrackingReportStats(rootParser, entity, "CLOSE",
> > > sourceLine);
> > > ++  rootParser->m_entity_stats.currentDepth--;
> > > ++}
> > > ++
> > > ++static XML_Parser
> > > ++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
> > > ++  XML_Parser rootParser = parser;
> > > ++  unsigned int stepsTakenUpwards = 0;
> > > ++  while (rootParser->m_parentParser) {
> > > ++    rootParser = rootParser->m_parentParser;
> > > ++    stepsTakenUpwards++;
> > > ++  }
> > > ++  assert(! rootParser->m_parentParser);
> > > ++  if (outLevelDiff != NULL) {
> > > ++    *outLevelDiff = stepsTakenUpwards;
> > > ++  }
> > > ++  return rootParser;
> > > ++}
> > > ++
> > > ++static const char *
> > > ++unsignedCharToPrintable(unsigned char c) {
> > > ++  switch (c) {
> > > ++  case 0:
> > > ++    return "\\0";
> > > ++  case 1:
> > > ++    return "\\x1";
> > > ++  case 2:
> > > ++    return "\\x2";
> > > ++  case 3:
> > > ++    return "\\x3";
> > > ++  case 4:
> > > ++    return "\\x4";
> > > ++  case 5:
> > > ++    return "\\x5";
> > > ++  case 6:
> > > ++    return "\\x6";
> > > ++  case 7:
> > > ++    return "\\x7";
> > > ++  case 8:
> > > ++    return "\\x8";
> > > ++  case 9:
> > > ++    return "\\t";
> > > ++  case 10:
> > > ++    return "\\n";
> > > ++  case 11:
> > > ++    return "\\xB";
> > > ++  case 12:
> > > ++    return "\\xC";
> > > ++  case 13:
> > > ++    return "\\r";
> > > ++  case 14:
> > > ++    return "\\xE";
> > > ++  case 15:
> > > ++    return "\\xF";
> > > ++  case 16:
> > > ++    return "\\x10";
> > > ++  case 17:
> > > ++    return "\\x11";
> > > ++  case 18:
> > > ++    return "\\x12";
> > > ++  case 19:
> > > ++    return "\\x13";
> > > ++  case 20:
> > > ++    return "\\x14";
> > > ++  case 21:
> > > ++    return "\\x15";
> > > ++  case 22:
> > > ++    return "\\x16";
> > > ++  case 23:
> > > ++    return "\\x17";
> > > ++  case 24:
> > > ++    return "\\x18";
> > > ++  case 25:
> > > ++    return "\\x19";
> > > ++  case 26:
> > > ++    return "\\x1A";
> > > ++  case 27:
> > > ++    return "\\x1B";
> > > ++  case 28:
> > > ++    return "\\x1C";
> > > ++  case 29:
> > > ++    return "\\x1D";
> > > ++  case 30:
> > > ++    return "\\x1E";
> > > ++  case 31:
> > > ++    return "\\x1F";
> > > ++  case 32:
> > > ++    return " ";
> > > ++  case 33:
> > > ++    return "!";
> > > ++  case 34:
> > > ++    return "\\\"";
> > > ++  case 35:
> > > ++    return "#";
> > > ++  case 36:
> > > ++    return "$";
> > > ++  case 37:
> > > ++    return "%";
> > > ++  case 38:
> > > ++    return "&";
> > > ++  case 39:
> > > ++    return "'";
> > > ++  case 40:
> > > ++    return "(";
> > > ++  case 41:
> > > ++    return ")";
> > > ++  case 42:
> > > ++    return "*";
> > > ++  case 43:
> > > ++    return "+";
> > > ++  case 44:
> > > ++    return ",";
> > > ++  case 45:
> > > ++    return "-";
> > > ++  case 46:
> > > ++    return ".";
> > > ++  case 47:
> > > ++    return "/";
> > > ++  case 48:
> > > ++    return "0";
> > > ++  case 49:
> > > ++    return "1";
> > > ++  case 50:
> > > ++    return "2";
> > > ++  case 51:
> > > ++    return "3";
> > > ++  case 52:
> > > ++    return "4";
> > > ++  case 53:
> > > ++    return "5";
> > > ++  case 54:
> > > ++    return "6";
> > > ++  case 55:
> > > ++    return "7";
> > > ++  case 56:
> > > ++    return "8";
> > > ++  case 57:
> > > ++    return "9";
> > > ++  case 58:
> > > ++    return ":";
> > > ++  case 59:
> > > ++    return ";";
> > > ++  case 60:
> > > ++    return "<";
> > > ++  case 61:
> > > ++    return "=";
> > > ++  case 62:
> > > ++    return ">";
> > > ++  case 63:
> > > ++    return "?";
> > > ++  case 64:
> > > ++    return "@";
> > > ++  case 65:
> > > ++    return "A";
> > > ++  case 66:
> > > ++    return "B";
> > > ++  case 67:
> > > ++    return "C";
> > > ++  case 68:
> > > ++    return "D";
> > > ++  case 69:
> > > ++    return "E";
> > > ++  case 70:
> > > ++    return "F";
> > > ++  case 71:
> > > ++    return "G";
> > > ++  case 72:
> > > ++    return "H";
> > > ++  case 73:
> > > ++    return "I";
> > > ++  case 74:
> > > ++    return "J";
> > > ++  case 75:
> > > ++    return "K";
> > > ++  case 76:
> > > ++    return "L";
> > > ++  case 77:
> > > ++    return "M";
> > > ++  case 78:
> > > ++    return "N";
> > > ++  case 79:
> > > ++    return "O";
> > > ++  case 80:
> > > ++    return "P";
> > > ++  case 81:
> > > ++    return "Q";
> > > ++  case 82:
> > > ++    return "R";
> > > ++  case 83:
> > > ++    return "S";
> > > ++  case 84:
> > > ++    return "T";
> > > ++  case 85:
> > > ++    return "U";
> > > ++  case 86:
> > > ++    return "V";
> > > ++  case 87:
> > > ++    return "W";
> > > ++  case 88:
> > > ++    return "X";
> > > ++  case 89:
> > > ++    return "Y";
> > > ++  case 90:
> > > ++    return "Z";
> > > ++  case 91:
> > > ++    return "[";
> > > ++  case 92:
> > > ++    return "\\\\";
> > > ++  case 93:
> > > ++    return "]";
> > > ++  case 94:
> > > ++    return "^";
> > > ++  case 95:
> > > ++    return "_";
> > > ++  case 96:
> > > ++    return "`";
> > > ++  case 97:
> > > ++    return "a";
> > > ++  case 98:
> > > ++    return "b";
> > > ++  case 99:
> > > ++    return "c";
> > > ++  case 100:
> > > ++    return "d";
> > > ++  case 101:
> > > ++    return "e";
> > > ++  case 102:
> > > ++    return "f";
> > > ++  case 103:
> > > ++    return "g";
> > > ++  case 104:
> > > ++    return "h";
> > > ++  case 105:
> > > ++    return "i";
> > > ++  case 106:
> > > ++    return "j";
> > > ++  case 107:
> > > ++    return "k";
> > > ++  case 108:
> > > ++    return "l";
> > > ++  case 109:
> > > ++    return "m";
> > > ++  case 110:
> > > ++    return "n";
> > > ++  case 111:
> > > ++    return "o";
> > > ++  case 112:
> > > ++    return "p";
> > > ++  case 113:
> > > ++    return "q";
> > > ++  case 114:
> > > ++    return "r";
> > > ++  case 115:
> > > ++    return "s";
> > > ++  case 116:
> > > ++    return "t";
> > > ++  case 117:
> > > ++    return "u";
> > > ++  case 118:
> > > ++    return "v";
> > > ++  case 119:
> > > ++    return "w";
> > > ++  case 120:
> > > ++    return "x";
> > > ++  case 121:
> > > ++    return "y";
> > > ++  case 122:
> > > ++    return "z";
> > > ++  case 123:
> > > ++    return "{";
> > > ++  case 124:
> > > ++    return "|";
> > > ++  case 125:
> > > ++    return "}";
> > > ++  case 126:
> > > ++    return "~";
> > > ++  case 127:
> > > ++    return "\\x7F";
> > > ++  case 128:
> > > ++    return "\\x80";
> > > ++  case 129:
> > > ++    return "\\x81";
> > > ++  case 130:
> > > ++    return "\\x82";
> > > ++  case 131:
> > > ++    return "\\x83";
> > > ++  case 132:
> > > ++    return "\\x84";
> > > ++  case 133:
> > > ++    return "\\x85";
> > > ++  case 134:
> > > ++    return "\\x86";
> > > ++  case 135:
> > > ++    return "\\x87";
> > > ++  case 136:
> > > ++    return "\\x88";
> > > ++  case 137:
> > > ++    return "\\x89";
> > > ++  case 138:
> > > ++    return "\\x8A";
> > > ++  case 139:
> > > ++    return "\\x8B";
> > > ++  case 140:
> > > ++    return "\\x8C";
> > > ++  case 141:
> > > ++    return "\\x8D";
> > > ++  case 142:
> > > ++    return "\\x8E";
> > > ++  case 143:
> > > ++    return "\\x8F";
> > > ++  case 144:
> > > ++    return "\\x90";
> > > ++  case 145:
> > > ++    return "\\x91";
> > > ++  case 146:
> > > ++    return "\\x92";
> > > ++  case 147:
> > > ++    return "\\x93";
> > > ++  case 148:
> > > ++    return "\\x94";
> > > ++  case 149:
> > > ++    return "\\x95";
> > > ++  case 150:
> > > ++    return "\\x96";
> > > ++  case 151:
> > > ++    return "\\x97";
> > > ++  case 152:
> > > ++    return "\\x98";
> > > ++  case 153:
> > > ++    return "\\x99";
> > > ++  case 154:
> > > ++    return "\\x9A";
> > > ++  case 155:
> > > ++    return "\\x9B";
> > > ++  case 156:
> > > ++    return "\\x9C";
> > > ++  case 157:
> > > ++    return "\\x9D";
> > > ++  case 158:
> > > ++    return "\\x9E";
> > > ++  case 159:
> > > ++    return "\\x9F";
> > > ++  case 160:
> > > ++    return "\\xA0";
> > > ++  case 161:
> > > ++    return "\\xA1";
> > > ++  case 162:
> > > ++    return "\\xA2";
> > > ++  case 163:
> > > ++    return "\\xA3";
> > > ++  case 164:
> > > ++    return "\\xA4";
> > > ++  case 165:
> > > ++    return "\\xA5";
> > > ++  case 166:
> > > ++    return "\\xA6";
> > > ++  case 167:
> > > ++    return "\\xA7";
> > > ++  case 168:
> > > ++    return "\\xA8";
> > > ++  case 169:
> > > ++    return "\\xA9";
> > > ++  case 170:
> > > ++    return "\\xAA";
> > > ++  case 171:
> > > ++    return "\\xAB";
> > > ++  case 172:
> > > ++    return "\\xAC";
> > > ++  case 173:
> > > ++    return "\\xAD";
> > > ++  case 174:
> > > ++    return "\\xAE";
> > > ++  case 175:
> > > ++    return "\\xAF";
> > > ++  case 176:
> > > ++    return "\\xB0";
> > > ++  case 177:
> > > ++    return "\\xB1";
> > > ++  case 178:
> > > ++    return "\\xB2";
> > > ++  case 179:
> > > ++    return "\\xB3";
> > > ++  case 180:
> > > ++    return "\\xB4";
> > > ++  case 181:
> > > ++    return "\\xB5";
> > > ++  case 182:
> > > ++    return "\\xB6";
> > > ++  case 183:
> > > ++    return "\\xB7";
> > > ++  case 184:
> > > ++    return "\\xB8";
> > > ++  case 185:
> > > ++    return "\\xB9";
> > > ++  case 186:
> > > ++    return "\\xBA";
> > > ++  case 187:
> > > ++    return "\\xBB";
> > > ++  case 188:
> > > ++    return "\\xBC";
> > > ++  case 189:
> > > ++    return "\\xBD";
> > > ++  case 190:
> > > ++    return "\\xBE";
> > > ++  case 191:
> > > ++    return "\\xBF";
> > > ++  case 192:
> > > ++    return "\\xC0";
> > > ++  case 193:
> > > ++    return "\\xC1";
> > > ++  case 194:
> > > ++    return "\\xC2";
> > > ++  case 195:
> > > ++    return "\\xC3";
> > > ++  case 196:
> > > ++    return "\\xC4";
> > > ++  case 197:
> > > ++    return "\\xC5";
> > > ++  case 198:
> > > ++    return "\\xC6";
> > > ++  case 199:
> > > ++    return "\\xC7";
> > > ++  case 200:
> > > ++    return "\\xC8";
> > > ++  case 201:
> > > ++    return "\\xC9";
> > > ++  case 202:
> > > ++    return "\\xCA";
> > > ++  case 203:
> > > ++    return "\\xCB";
> > > ++  case 204:
> > > ++    return "\\xCC";
> > > ++  case 205:
> > > ++    return "\\xCD";
> > > ++  case 206:
> > > ++    return "\\xCE";
> > > ++  case 207:
> > > ++    return "\\xCF";
> > > ++  case 208:
> > > ++    return "\\xD0";
> > > ++  case 209:
> > > ++    return "\\xD1";
> > > ++  case 210:
> > > ++    return "\\xD2";
> > > ++  case 211:
> > > ++    return "\\xD3";
> > > ++  case 212:
> > > ++    return "\\xD4";
> > > ++  case 213:
> > > ++    return "\\xD5";
> > > ++  case 214:
> > > ++    return "\\xD6";
> > > ++  case 215:
> > > ++    return "\\xD7";
> > > ++  case 216:
> > > ++    return "\\xD8";
> > > ++  case 217:
> > > ++    return "\\xD9";
> > > ++  case 218:
> > > ++    return "\\xDA";
> > > ++  case 219:
> > > ++    return "\\xDB";
> > > ++  case 220:
> > > ++    return "\\xDC";
> > > ++  case 221:
> > > ++    return "\\xDD";
> > > ++  case 222:
> > > ++    return "\\xDE";
> > > ++  case 223:
> > > ++    return "\\xDF";
> > > ++  case 224:
> > > ++    return "\\xE0";
> > > ++  case 225:
> > > ++    return "\\xE1";
> > > ++  case 226:
> > > ++    return "\\xE2";
> > > ++  case 227:
> > > ++    return "\\xE3";
> > > ++  case 228:
> > > ++    return "\\xE4";
> > > ++  case 229:
> > > ++    return "\\xE5";
> > > ++  case 230:
> > > ++    return "\\xE6";
> > > ++  case 231:
> > > ++    return "\\xE7";
> > > ++  case 232:
> > > ++    return "\\xE8";
> > > ++  case 233:
> > > ++    return "\\xE9";
> > > ++  case 234:
> > > ++    return "\\xEA";
> > > ++  case 235:
> > > ++    return "\\xEB";
> > > ++  case 236:
> > > ++    return "\\xEC";
> > > ++  case 237:
> > > ++    return "\\xED";
> > > ++  case 238:
> > > ++    return "\\xEE";
> > > ++  case 239:
> > > ++    return "\\xEF";
> > > ++  case 240:
> > > ++    return "\\xF0";
> > > ++  case 241:
> > > ++    return "\\xF1";
> > > ++  case 242:
> > > ++    return "\\xF2";
> > > ++  case 243:
> > > ++    return "\\xF3";
> > > ++  case 244:
> > > ++    return "\\xF4";
> > > ++  case 245:
> > > ++    return "\\xF5";
> > > ++  case 246:
> > > ++    return "\\xF6";
> > > ++  case 247:
> > > ++    return "\\xF7";
> > > ++  case 248:
> > > ++    return "\\xF8";
> > > ++  case 249:
> > > ++    return "\\xF9";
> > > ++  case 250:
> > > ++    return "\\xFA";
> > > ++  case 251:
> > > ++    return "\\xFB";
> > > ++  case 252:
> > > ++    return "\\xFC";
> > > ++  case 253:
> > > ++    return "\\xFD";
> > > ++  case 254:
> > > ++    return "\\xFE";
> > > ++  case 255:
> > > ++    return "\\xFF";
> > > ++  default:
> > > ++    assert(0); /* never gets here */
> > > ++    return "dead code";
> > > ++  }
> > > ++  assert(0); /* never gets here */
> > > ++}
> > > ++
> > > ++#endif /* XML_DTD */
> > > ++
> > > ++static unsigned long
> > > ++getDebugLevel(const char *variableName, unsigned long
> > > defaultDebugLevel) {
> > > ++  const char *const valueOrNull = getenv(variableName);
> > > ++  if (valueOrNull == NULL) {
> > > ++    return defaultDebugLevel;
> > > ++  }
> > > ++  const char *const value = valueOrNull;
> > > ++
> > > ++  errno = 0;
> > > ++  char *afterValue = (char *)value;
> > > ++  unsigned long debugLevel = strtoul(value, &afterValue, 10);
> > > ++  if ((errno != 0) || (afterValue[0] != '\0')) {
> > > ++    errno = 0;
> > > ++    return defaultDebugLevel;
> > > ++  }
> > > ++
> > > ++  return debugLevel;
> > > ++}
> > > +--
> > > +2.32.0
> > > +
> > > diff --git a/meta/recipes-core/expat/expat_2.2.9.bb b/meta/recipes-
> > > core/expat/expat_2.2.9.bb
> > > index 8f3db41352..3af457b2af 100644
> > > --- a/meta/recipes-core/expat/expat_2.2.9.bb
> > > +++ b/meta/recipes-core/expat/expat_2.2.9.bb
> > > @@ -6,8 +6,9 @@ LICENSE = "MIT"
> > > 
> > >  LIC_FILES_CHKSUM =
> > > "file://COPYING;md5=5b8620d98e49772d95fc1d291c26aa79"
> > > 
> > > -SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}.tar.bz2 \
> > > +SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}-RENAMED-
> > > VULNERABLE-
> > > PLEASE-USE-2.4.1-INSTEAD.tar.bz2 \
> > >             file://libtool-tag.patch \
> > > +          
> > > file://0001-expat-Backport-fix-for-CVE-2013-0340.patch \
> > >           "
> > > 
> > >  SRC_URI[md5sum] = "875a2c2ff3e8eb9e5a5cd62db2033ab5"
> > > 
> > > 
> > > 
> > -----BEGIN PGP SIGNATURE-----
> > 
> > iQEzBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKDygACgkQYgqew07V
> > MNVpHAgAjxDiHJ+0Zl+xxBRKkD3E3bGlKlwsn4MOlP1HWN5zjComuAdnyQwvTmAj
> > 2HRDxGUQ/ZnXUlSDbNzHSgrG2IDa1dlBWGRASRX3YxIXTJ1UL5LWHuprDL2P3xNp
> > XMaAeX2a86gJKDBA7/XXkrbVuCafjGZ6r0+urvcqpJFO1FR1Qb0aklAe/pEVtEYS
> > XcN2tWfqeOy9HBOvLIBfFwkRE07oBfr0eWxKzECOq1MPOUYr9k/E4LwqGEWcrOrq
> > rJM2U07Esu0NkQQSPZXP+NTYO9v5ztZjCLzOb0eI7tGbduW3ay7fOlawfP8fgiON
> > YVMOzcvA9DFOK7Z3ur3nCL7MWnN3OA==
> > =JFZY
> > -----END PGP SIGNATURE-----
> > 
> > 
> > 
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKF/cACgkQYgqew07V
MNXvcQf/YAEm6pO8djPzbmLV3HxHPfZpO4wvVW29K+3Ay2RGsF4pWq8MvgUPOSch
lylzvkc7ws0fPojZ4suEnH9sEYzntuAzPH2hwO5/qSDfIuuUWId5rDjHXcLy4ziK
8x52F10xbPO8lB1N7rwbLqSvYCvbQcAfx+mZD8CLwLp0pMEWX7ksDzzLc66pSowH
x5jzFq1DGYjD0L/QgVUlyGc9TwMeI7WqQtCo3zLkXHmRpogN9rJM5gxILplOmo12
hCVQdCwXL/h+v8KPCwU0IDD67sYH+ZkjCDns52/WXSpZMy0xyCmhFYJhKMnKDyMx
1yS8roeBwwMcbkeVEx2Z05gkRPF9Zw==
=CjLa
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
  2021-06-16 15:17     ` Jasper Orschulko
@ 2021-06-16 16:15       ` Steve Sakoman
  0 siblings, 0 replies; 11+ messages in thread
From: Steve Sakoman @ 2021-06-16 16:15 UTC (permalink / raw)
  To: Jasper Orschulko; +Cc: openembedded-core

On Wed, Jun 16, 2021 at 5:17 AM Jasper Orschulko
<Jasper.Orschulko@iris-sensing.com> wrote:
>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA256
>
> Hi Steve!
>
> Thanks for the quick feedback! I just noticed that the archive folder
> structure from sourceforge differs to to the git content, thus the
> "inner" patch currently fails. Oops!
>
> I'm thinking about setting the git repository as SRC_URI, as the expat
> project is currently moving away from sourceforge towards github. Also,
> we would not be affected by random archive renaming ;) What do you
> think?

If the upstream project is moving from sourceforge to github, then yes
it makes sense to change the SRC_URI to reflect their new standard
source location.

Steve
> - --
> With best regards
>
> Jasper Orschulko
> DevOps Engineer
>
> Tel. +49 30 58 58 14 265
> Fax +49 30 58 58 14 999
> Jasper.Orschulko@iris-sensing.com
>
> • • • • • • • • • • • • • • • • • • • • • • • • • •
>
> iris-GmbH
> infrared & intelligent sensors
> Ostendstraße 1-14 | 12459 Berlin
>
> https://iris-sensing.com/
>
>
>
>
> On Wed, 2021-06-16 at 05:09 -1000, Steve Sakoman wrote:
> > On Wed, Jun 16, 2021 at 4:49 AM Jasper Orschulko
> > <Jasper.Orschulko@iris-sensing.com> wrote:
> > >
> > > -----BEGIN PGP SIGNED MESSAGE-----
> > > Hash: SHA256
> > >
> > > P.S.: I am not too familiar with expat, this particular CVE, not
> > > with
> > > the practise of backporting security patches, so someone(TM) should
> > > definitely take a closer look at this first.
> >
> > Will do!
> >
> > A few initial comments:
> >
> > 1. Please don't PGP sign patch emails :-)
> > 2. Change the patch file name to CVE-2013-0340.patch
> >
> > Other than that it looks OK at first glance.
> >
> > For reference the patch requirements for CVE's are outlined at:
> >
> > https://wiki.yoctoproject.org/wiki/Security
> >
> > in the "Patch name convention and commit message" section.
> >
> > Thanks for helping with CVEs!
> >
> > Steve
> >
> >
> >
> >
> > > With best regards
> > >
> > > Jasper Orschulko
> > > DevOps Engineer
> > >
> > > Tel. +49 30 58 58 14 265
> > > Fax +49 30 58 58 14 999
> > > Jasper.Orschulko@iris-sensing.com
> > >
> > > • • • • • • • • • • • • • • • • • • • • • • • • • •
> > >
> > > iris-GmbH
> > > infrared & intelligent sensors
> > > Ostendstraße 1-14 | 12459 Berlin
> > >
> > > https://iris-sensing.com/
> > >
> > >
> > >
> > >
> > > On Wed, 2021-06-16 at 14:44 +0000, Jasper Orschulko wrote:
> > > > expat < 4.0 is vulnerable to billion laughs attacks (see
> > > > [https://github.com/libexpat/libexpat/issues/34]). This patch
> > > > backports
> > > > the commits b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> > > > and 60959f2b491876199879d97c8ed956eabb0c2e73 from upstream.
> > > >
> > > > Additionally, the SRC_URI had to be adjusted due to renaming of
> > > > the
> > > > source archive
> > > >
> > > > Signed-off-by: Jasper Orschulko
> > > > <Jasper.Orschulko@iris-sensing.com>
> > > > ---
> > > >  ...expat-Backport-fix-for-CVE-2013-0340.patch | 1758
> > > > +++++++++++++++++
> > > >  meta/recipes-core/expat/expat_2.2.9.bb        |    3 +-
> > > >  2 files changed, 1760 insertions(+), 1 deletion(-)
> > > >  create mode 100644 meta/recipes-core/expat/expat/0001-expat-
> > > > Backport-
> > > > fix-for-CVE-2013-0340.patch
> > > >
> > > > diff --git a/meta/recipes-core/expat/expat/0001-expat-Backport-
> > > > fix-
> > > > for-
> > > > CVE-2013-0340.patch b/meta/recipes-core/expat/expat/0001-expat-
> > > > Backport-fix-for-CVE-2013-0340.patch
> > > > new file mode 100644
> > > > index 0000000000..b2ca066d96
> > > > --- /dev/null
> > > > +++ b/meta/recipes-core/expat/expat/0001-expat-Backport-fix-for-
> > > > CVE-
> > > > 2013-0340.patch
> > > > @@ -0,0 +1,1758 @@
> > > > +From 6f68eb0439f3c1807a143ff8c8972e74d404d8f0 Mon Sep 17
> > > > 00:00:00
> > > > 2001
> > > > +From: Sebastian Pipping <sebastian@pipping.org>
> > > > +Date: Mon, 19 Apr 2021 21:42:51 +0200
> > > > +Subject: [PATCH] expat: Backport fix for CVE-2013-0340
> > > > +
> > > > +Issue: https://github.com/libexpat/libexpat/issues/34
> > > > +
> > > > +This patch cherry-picks the following commits from upstream
> > > > release
> > > > +2.4.0 onto 2.2.9:
> > > > +
> > > > +- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> > > > +- 60959f2b491876199879d97c8ed956eabb0c2e73
> > > > +
> > > > +Upstream-Status: Backport
> > > > +CVE: CVE-2013-0340
> > > > +Signed-off-by: Jasper Orschulko
> > > > <Jasper.Orschulko@iris-sensing.com>
> > > > +---
> > > > + expat/lib/expat.h       |   21 +-
> > > > + expat/lib/internal.h    |   30 +
> > > > + expat/lib/libexpat.def  |    3 +
> > > > + expat/lib/libexpatw.def |    3 +
> > > > + expat/lib/xmlparse.c    | 1147
> > > > +++++++++++++++++++++++++++++++++++++-
> > > > -
> > > > + 5 files changed, 1143 insertions(+), 61 deletions(-)
> > > > +
> > > > +diff --git a/expat/lib/expat.h b/expat/lib/expat.h
> > > > +index 48a6e2a3..796086c2 100644
> > > > +--- a/expat/lib/expat.h
> > > > ++++ b/expat/lib/expat.h
> > > > +@@ -115,7 +115,9 @@ enum XML_Error {
> > > > +   XML_ERROR_RESERVED_PREFIX_XMLNS,
> > > > +   XML_ERROR_RESERVED_NAMESPACE_URI,
> > > > +   /* Added in 2.2.1. */
> > > > +-  XML_ERROR_INVALID_ARGUMENT
> > > > ++  XML_ERROR_INVALID_ARGUMENT,
> > > > ++  /* Backported from 2.4.0. */
> > > > ++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
> > > > + };
> > > > +
> > > > + enum XML_Content_Type {
> > > > +@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
> > > > +   XML_FEATURE_SIZEOF_XML_LCHAR,
> > > > +   XML_FEATURE_NS,
> > > > +   XML_FEATURE_LARGE_SIZE,
> > > > +-  XML_FEATURE_ATTR_INFO
> > > > ++  XML_FEATURE_ATTR_INFO,
> > > > ++  /* Added in Expat 2.4.0. */
> > > > ++
> > > > XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATIO
> > > > N_DE
> > > > FA
> > > > ULT,
> > > > ++
> > > > XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD
> > > > _DEF
> > > > AU
> > > > LT
> > > > +   /* Additional features must be added to the end of this enum.
> > > > */
> > > > + };
> > > > +
> > > > +@@ -1010,6 +1015,18 @@ typedef struct {
> > > > + XMLPARSEAPI(const XML_Feature *)
> > > > + XML_GetFeatureList(void);
> > > > +
> > > > ++#ifdef XML_DTD
> > > > ++/* Backported from Expat 2.4.0. */
> > > > ++XMLPARSEAPI(XML_Bool)
> > > > ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> > > > ++    XML_Parser parser, float maximumAmplificationFactor);
> > > > ++
> > > > ++/* Backported from Expat 2.4.0. */
> > > > ++XMLPARSEAPI(XML_Bool)
> > > > ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> > > > ++    XML_Parser parser, unsigned long long
> > > > activationThresholdBytes);
> > > > ++#endif
> > > > ++
> > > > + /* Expat follows the semantic versioning convention.
> > > > +    See http://semver.org.
> > > > + */
> > > > +diff --git a/expat/lib/internal.h b/expat/lib/internal.h
> > > > +index 60913dab..d8b31fa2 100644
> > > > +--- a/expat/lib/internal.h
> > > > ++++ b/expat/lib/internal.h
> > > > +@@ -101,10 +101,40 @@
> > > > + #  endif
> > > > + #endif
> > > > +
> > > > ++#include <limits.h> // ULONG_MAX
> > > > ++
> > > > ++#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
> > > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
> > > > ++#  else
> > > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> > > > ++#  endif
> > > > ++#else
> > > > ++#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
> > > > ++#  if ! defined(ULONG_MAX)
> > > > ++#    error Compiler did not define ULONG_MAX for us
> > > > ++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
> > > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
> > > > ++#  else
> > > > ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> > > > ++#  endif
> > > > ++#endif
> > > > ++
> > > > + #ifndef UNUSED_P
> > > > + #  define UNUSED_P(p) (void)p
> > > > + #endif
> > > > +
> > > > ++/* NOTE BEGIN If you ever patch these defaults to greater
> > > > values
> > > > ++              for non-attack XML payload in your environment,
> > > > ++              please file a bug report with libexpat.  Thank
> > > > you!
> > > > ++*/
> > > > ++#define
> > > > \
> > > > ++  100.0f
> > > > ++#define
> > > > \
> > > > ++  8388608 // 8 MiB, 2^23
> > > > ++/* NOTE END */
> > > > ++
> > > > + #ifdef __cplusplus
> > > > + extern "C" {
> > > > + #endif
> > > > +diff --git a/expat/lib/libexpat.def b/expat/lib/libexpat.def
> > > > +index 16faf595..b5e59d8d 100644
> > > > +--- a/expat/lib/libexpat.def
> > > > ++++ b/expat/lib/libexpat.def
> > > > +@@ -76,3 +76,6 @@ EXPORTS
> > > > +   XML_SetHashSalt @67
> > > > + ; added with version 2.2.5
> > > > +   _INTERNAL_trim_to_complete_utf8_characters @68
> > > > ++; backported from version 2.4.0
> > > > ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> > > > ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
> > > > +diff --git a/expat/lib/libexpatw.def b/expat/lib/libexpatw.def
> > > > +index 16faf595..ebd77707 100644
> > > > +--- a/expat/lib/libexpatw.def
> > > > ++++ b/expat/lib/libexpatw.def
> > > > +@@ -76,3 +76,6 @@ EXPORTS
> > > > +   XML_SetHashSalt @67
> > > > + ; added with version 2.2.5
> > > > +   _INTERNAL_trim_to_complete_utf8_characters @68
> > > > ++; backported from version 2.4.0
> > > > ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> > > > ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @7
> > > > +diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
> > > > +index 3aaf35b9..fdcc7296 100644
> > > > +--- a/expat/lib/xmlparse.c
> > > > ++++ b/expat/lib/xmlparse.c
> > > > +@@ -47,6 +47,8 @@
> > > > + #include <limits.h> /* UINT_MAX */
> > > > + #include <stdio.h>  /* fprintf */
> > > > + #include <stdlib.h> /* getenv, rand_s */
> > > > ++#include <stdint.h> /* uintptr_t */
> > > > ++#include <math.h>   /* isnan */
> > > > +
> > > > + #ifdef _WIN32
> > > > + #  define getpid GetCurrentProcessId
> > > > +@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
> > > > +   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
> > > > + } OPEN_INTERNAL_ENTITY;
> > > > +
> > > > ++enum XML_Account {
> > > > ++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the
> > > > Expat
> > > > parser */
> > > > ++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced
> > > > during
> > > > entity
> > > > ++                                   expansion */
> > > > ++  XML_ACCOUNT_NONE              /* i.e. do not account, was
> > > > accounted
> > > > already */
> > > > ++};
> > > > ++
> > > > ++#ifdef XML_DTD
> > > > ++typedef unsigned long long XmlBigCount;
> > > > ++typedef struct accounting {
> > > > ++  XmlBigCount countBytesDirect;
> > > > ++  XmlBigCount countBytesIndirect;
> > > > ++  int debugLevel;
> > > > ++  float maximumAmplificationFactor; // >=1.0
> > > > ++  unsigned long long activationThresholdBytes;
> > > > ++} ACCOUNTING;
> > > > ++
> > > > ++typedef struct entity_stats {
> > > > ++  unsigned int countEverOpened;
> > > > ++  unsigned int currentDepth;
> > > > ++  unsigned int maximumDepthSeen;
> > > > ++  int debugLevel;
> > > > ++} ENTITY_STATS;
> > > > ++#endif /* XML_DTD */
> > > > ++
> > > > + typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
> > > > const
> > > > char *start,
> > > > +                                          const char *end, const
> > > > char
> > > > **endPtr);
> > > > +
> > > > +@@ -403,16 +430,18 @@ static enum XML_Error
> > > > initializeEncoding(XML_Parser parser);
> > > > + static enum XML_Error doProlog(XML_Parser parser, const
> > > > ENCODING
> > > > *enc,
> > > > +                                const char *s, const char *end,
> > > > int
> > > > tok,
> > > > +                                const char *next, const char
> > > > **nextPtr,
> > > > +-                               XML_Bool haveMore, XML_Bool
> > > > allowClosingDoctype);
> > > > ++                               XML_Bool haveMore, XML_Bool
> > > > allowClosingDoctype,
> > > > ++                               enum XML_Account account);
> > > > + static enum XML_Error processInternalEntity(XML_Parser parser,
> > > > ENTITY
> > > > *entity,
> > > > +                                             XML_Bool
> > > > betweenDecl);
> > > > + static enum XML_Error doContent(XML_Parser parser, int
> > > > startTagLevel,
> > > > +                                 const ENCODING *enc, const char
> > > > *start,
> > > > +                                 const char *end, const char
> > > > **endPtr,
> > > > +-                                XML_Bool haveMore);
> > > > ++                                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,
> > > > +@@ -422,7 +451,8 @@ static enum XML_Error
> > > > doIgnoreSection(XML_Parser
> > > > parser, const ENCODING *,
> > > > + static void freeBindings(XML_Parser parser, BINDING *bindings);
> > > > + static enum XML_Error storeAtts(XML_Parser parser, const
> > > > ENCODING
> > > > *,
> > > > +                                 const char *s, TAG_NAME
> > > > *tagNamePtr,
> > > > +-                                BINDING **bindingsPtr);
> > > > ++                                BINDING **bindingsPtr,
> > > > ++                                enum XML_Account account);
> > > > + static enum XML_Error addBinding(XML_Parser parser, PREFIX
> > > > *prefix,
> > > > +                                  const ATTRIBUTE_ID *attId,
> > > > const
> > > > XML_Char *uri,
> > > > +                                  BINDING **bindingsPtr);
> > > > +@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE
> > > > *type,
> > > > ATTRIBUTE_ID *, XML_Bool isCdata,
> > > > +                            XML_Parser parser);
> > > > + static enum XML_Error storeAttributeValue(XML_Parser parser,
> > > > const
> > > > ENCODING *,
> > > > +                                           XML_Bool isCdata,
> > > > const
> > > > char *,
> > > > +-                                          const char *,
> > > > STRING_POOL
> > > > *);
> > > > ++                                          const char *,
> > > > STRING_POOL
> > > > *,
> > > > ++                                          enum XML_Account
> > > > account);
> > > > + static enum XML_Error appendAttributeValue(XML_Parser parser,
> > > > const
> > > > ENCODING *,
> > > > +                                            XML_Bool isCdata,
> > > > const
> > > > char *,
> > > > +-                                           const char *,
> > > > STRING_POOL
> > > > *);
> > > > ++                                           const char *,
> > > > STRING_POOL
> > > > *,
> > > > ++                                           enum XML_Account
> > > > account);
> > > > + static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const
> > > > ENCODING
> > > > *enc,
> > > > +                                     const char *start, const
> > > > char
> > > > *end);
> > > > + static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE
> > > > *);
> > > > + static enum XML_Error storeEntityValue(XML_Parser parser, const
> > > > ENCODING *enc,
> > > > +-                                       const char *start, const
> > > > char
> > > > *end);
> > > > ++                                       const char *start, const
> > > > char
> > > > *end,
> > > > ++                                       enum XML_Account
> > > > account);
> > > > + static int reportProcessingInstruction(XML_Parser parser, const
> > > > ENCODING *enc,
> > > > +                                        const char *start, const
> > > > char
> > > > *end);
> > > > + static int reportComment(XML_Parser parser, const ENCODING
> > > > *enc,
> > > > +@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const
> > > > XML_Char
> > > > *encodingName,
> > > > +
> > > > + static void parserInit(XML_Parser parser, const XML_Char
> > > > *encodingName);
> > > > +
> > > > ++#ifdef XML_DTD
> > > > ++static float accountingGetCurrentAmplification(XML_Parser
> > > > rootParser);
> > > > ++static void accountingReportStats(XML_Parser originParser,
> > > > const
> > > > char
> > > > *epilog);
> > > > ++static void accountingOnAbort(XML_Parser originParser);
> > > > ++static void accountingReportDiff(XML_Parser rootParser,
> > > > ++                                 unsigned int
> > > > levelsAwayFromRootParser,
> > > > ++                                 const char *before, const char
> > > > *after,
> > > > ++                                 ptrdiff_t bytesMore, int
> > > > source_line,
> > > > ++                                 enum XML_Account account);
> > > > ++static XML_Bool accountingDiffTolerated(XML_Parser
> > > > originParser,
> > > > int
> > > > tok,
> > > > ++                                        const char *before,
> > > > const
> > > > char *after,
> > > > ++                                        int source_line,
> > > > ++                                        enum XML_Account
> > > > account);
> > > > ++
> > > > ++static void entityTrackingReportStats(XML_Parser parser, ENTITY
> > > > *entity,
> > > > ++                                      const char *action, int
> > > > sourceLine);
> > > > ++static void entityTrackingOnOpen(XML_Parser parser, ENTITY
> > > > *entity,
> > > > ++                                 int sourceLine);
> > > > ++static void entityTrackingOnClose(XML_Parser parser, ENTITY
> > > > *entity,
> > > > ++                                  int sourceLine);
> > > > ++
> > > > ++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,
> > > > ++                                   unsigned long
> > > > defaultDebugLevel);
> > > > ++
> > > > + #define poolStart(pool) ((pool)->start)
> > > > + #define poolEnd(pool) ((pool)->ptr)
> > > > + #define poolLength(pool) ((pool)->ptr - (pool)->start)
> > > > +@@ -616,6 +678,10 @@ struct XML_ParserStruct {
> > > > +   enum XML_ParamEntityParsing m_paramEntityParsing;
> > > > + #endif
> > > > +   unsigned long m_hash_secret_salt;
> > > > ++#ifdef XML_DTD
> > > > ++  ACCOUNTING m_accounting;
> > > > ++  ENTITY_STATS m_entity_stats;
> > > > ++#endif
> > > > + };
> > > > +
> > > > + #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
> > > > +@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const
> > > > XML_Char
> > > > *encodingName) {
> > > > +   parser->m_paramEntityParsing =
> > > > XML_PARAM_ENTITY_PARSING_NEVER;
> > > > + #endif
> > > > +   parser->m_hash_secret_salt = 0;
> > > > ++
> > > > ++#ifdef XML_DTD
> > > > ++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
> > > > ++  parser->m_accounting.debugLevel =
> > > > getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
> > > > ++  parser->m_accounting.maximumAmplificationFactor
> > > > ++      =
> > > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFA
> > > > ULT;
> > > > ++  parser->m_accounting.activationThresholdBytes
> > > > ++      =
> > > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAU
> > > > LT;
> > > > ++
> > > > ++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
> > > > ++  parser->m_entity_stats.debugLevel =
> > > > getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
> > > > ++#endif
> > > > + }
> > > > +
> > > > + /* moves list of bindings to m_freeBindingList */
> > > > +@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
> > > > +   /* Added in 2.2.5. */
> > > > +   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1,
> > > > already */
> > > > +     return XML_L("invalid argument");
> > > > ++  /* Backported from 2.4.0. */
> > > > ++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
> > > > ++    return XML_L(
> > > > ++        "limit on input amplification factor (from DTD and
> > > > entities)
> > > > breached");
> > > > +   }
> > > > +   return NULL;
> > > > + }
> > > > +@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
> > > > +
> > > > + const XML_Feature *XMLCALL
> > > > + XML_GetFeatureList(void) {
> > > > +-  static const XML_Feature features[]
> > > > +-      = {{XML_FEATURE_SIZEOF_XML_CHAR,
> > > > XML_L("sizeof(XML_Char)"),
> > > > +-          sizeof(XML_Char)},
> > > > +-         {XML_FEATURE_SIZEOF_XML_LCHAR,
> > > > XML_L("sizeof(XML_LChar)"),
> > > > +-          sizeof(XML_LChar)},
> > > > ++  static const XML_Feature features[] = {
> > > > ++      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
> > > > ++       sizeof(XML_Char)},
> > > > ++      {XML_FEATURE_SIZEOF_XML_LCHAR,
> > > > XML_L("sizeof(XML_LChar)"),
> > > > ++       sizeof(XML_LChar)},
> > > > + #ifdef XML_UNICODE
> > > > +-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> > > > ++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> > > > + #endif
> > > > + #ifdef XML_UNICODE_WCHAR_T
> > > > +-         {XML_FEATURE_UNICODE_WCHAR_T,
> > > > XML_L("XML_UNICODE_WCHAR_T"),
> > > > 0},
> > > > ++      {XML_FEATURE_UNICODE_WCHAR_T,
> > > > XML_L("XML_UNICODE_WCHAR_T"),
> > > > 0},
> > > > + #endif
> > > > + #ifdef XML_DTD
> > > > +-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> > > > ++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> > > > + #endif
> > > > + #ifdef XML_CONTEXT_BYTES
> > > > +-         {XML_FEATURE_CONTEXT_BYTES,
> > > > XML_L("XML_CONTEXT_BYTES"),
> > > > +-          XML_CONTEXT_BYTES},
> > > > ++      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
> > > > ++       XML_CONTEXT_BYTES},
> > > > + #endif
> > > > + #ifdef XML_MIN_SIZE
> > > > +-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> > > > ++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> > > > + #endif
> > > > + #ifdef XML_NS
> > > > +-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> > > > ++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> > > > + #endif
> > > > + #ifdef XML_LARGE_SIZE
> > > > +-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> > > > ++      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> > > > + #endif
> > > > + #ifdef XML_ATTR_INFO
> > > > +-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> > > > ++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> > > > + #endif
> > > > +-         {XML_FEATURE_END, NULL, 0}};
> > > > ++#ifdef XML_DTD
> > > > ++      /* Added in Expat 2.4.0. */
> > > > ++
> > > > {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATI
> > > > ON_D
> > > > EF
> > > > AULT,
> > > > ++       XML_L("XML_BLAP_MAX_AMP"),
> > > > ++       (long int)
> > > > ++
> > > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFA
> > > > ULT}
> > > > ,
> > > > ++
> > > > {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOL
> > > > D_DE
> > > > FA
> > > > ULT,
> > > > ++       XML_L("XML_BLAP_ACT_THRES"),
> > > > ++
> > > > EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAU
> > > > LT},
> > > > ++#endif
> > > > ++      {XML_FEATURE_END, NULL, 0}};
> > > > +
> > > > +   return features;
> > > > + }
> > > > +
> > > > ++#ifdef XML_DTD
> > > > ++XML_Bool XMLCALL
> > > > ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> > > > ++    XML_Parser parser, float maximumAmplificationFactor) {
> > > > ++  if ((parser == NULL) || (parser->m_parentParser != NULL)
> > > > ++      || isnan(maximumAmplificationFactor)
> > > > ++      || (maximumAmplificationFactor < 1.0f)) {
> > > > ++    return XML_FALSE;
> > > > ++  }
> > > > ++  parser->m_accounting.maximumAmplificationFactor =
> > > > maximumAmplificationFactor;
> > > > ++  return XML_TRUE;
> > > > ++}
> > > > ++
> > > > ++XML_Bool XMLCALL
> > > > ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> > > > ++    XML_Parser parser, unsigned long long
> > > > activationThresholdBytes)
> > > > {
> > > > ++  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
> > > > ++    return XML_FALSE;
> > > > ++  }
> > > > ++  parser->m_accounting.activationThresholdBytes =
> > > > activationThresholdBytes;
> > > > ++  return XML_TRUE;
> > > > ++}
> > > > ++#endif /* XML_DTD */
> > > > ++
> > > > + /* Initially tag->rawName always points into the parse buffer;
> > > > +    for those TAG instances opened while the current parse
> > > > buffer
> > > > was
> > > > +    processed, and not yet closed, we need to store tag->rawName
> > > > in
> > > > a
> > > > more
> > > > +@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
> > > > + static enum XML_Error PTRCALL
> > > > + contentProcessor(XML_Parser parser, const char *start, const
> > > > char
> > > > *end,
> > > > +                  const char **endPtr) {
> > > > +-  enum XML_Error result
> > > > +-      = doContent(parser, 0, parser->m_encoding, start, end,
> > > > endPtr,
> > > > +-                  (XML_Bool)! parser-
> > > > >m_parsingStatus.finalBuffer);
> > > > ++  enum XML_Error result = doContent(
> > > > ++      parser, 0, parser->m_encoding, start, end, endPtr,
> > > > ++      (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> > > > XML_ACCOUNT_DIRECT);
> > > > +   if (result == XML_ERROR_NONE) {
> > > > +     if (! storeRawNames(parser))
> > > > +       return XML_ERROR_NO_MEMORY;
> > > > +@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser
> > > > parser,
> > > > const char *start,
> > > > +   int tok = XmlContentTok(parser->m_encoding, start, end,
> > > > &next);
> > > > +   switch (tok) {
> > > > +   case XML_TOK_BOM:
> > > > ++#ifdef XML_DTD
> > > > ++    if (! accountingDiffTolerated(parser, tok, start, next,
> > > > __LINE__,
> > > > ++                                  XML_ACCOUNT_DIRECT)) {
> > > > ++      accountingOnAbort(parser);
> > > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > > ++    }
> > > > ++#endif /* XML_DTD */
> > > > ++
> > > > +     /* If we are at the end of the buffer, this would cause the
> > > > next
> > > > stage,
> > > > +        i.e. externalEntityInitProcessor3, to pass control
> > > > directly
> > > > to
> > > > +        doContent (by detecting XML_TOK_NONE) without processing
> > > > any
> > > > xml text
> > > > +@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser
> > > > parser,
> > > > const char *start,
> > > > +   const char *next = start; /* XmlContentTok doesn't always set
> > > > the
> > > > last arg */
> > > > +   parser->m_eventPtr = start;
> > > > +   tok = XmlContentTok(parser->m_encoding, start, end, &next);
> > > > ++  /* Note: These bytes are accounted later in:
> > > > ++           - processXmlDecl
> > > > ++           - externalEntityContentProcessor
> > > > ++  */
> > > > +   parser->m_eventEndPtr = next;
> > > > +
> > > > +   switch (tok) {
> > > > +@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser
> > > > parser, const char *start,
> > > > +                                const char *end, const char
> > > > **endPtr)
> > > > {
> > > > +   enum XML_Error result
> > > > +       = doContent(parser, 1, parser->m_encoding, start, end,
> > > > endPtr,
> > > > +-                  (XML_Bool)! parser-
> > > > >m_parsingStatus.finalBuffer);
> > > > ++                  (XML_Bool)! parser-
> > > > >m_parsingStatus.finalBuffer,
> > > > ++                  XML_ACCOUNT_ENTITY_EXPANSION);
> > > > +   if (result == XML_ERROR_NONE) {
> > > > +     if (! storeRawNames(parser))
> > > > +       return XML_ERROR_NO_MEMORY;
> > > > +@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser
> > > > parser, const char *start,
> > > > + static enum XML_Error
> > > > + doContent(XML_Parser parser, int startTagLevel, const ENCODING
> > > > *enc,
> > > > +           const char *s, const char *end, const char **nextPtr,
> > > > +-          XML_Bool haveMore) {
> > > > ++          XML_Bool haveMore, enum XML_Account account) {
> > > > +   /* save one level of indirection */
> > > > +   DTD *const dtd = parser->m_dtd;
> > > > +
> > > > +@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int
> > > > startTagLevel,
> > > > const ENCODING *enc,
> > > > +   for (;;) {
> > > > +     const char *next = s; /* XmlContentTok doesn't always set
> > > > the
> > > > last arg */
> > > > +     int tok = XmlContentTok(enc, s, end, &next);
> > > > ++#ifdef XML_DTD
> > > > ++    const char *accountAfter
> > > > ++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok ==
> > > > XML_TOK_TRAILING_CR))
> > > > ++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
> > > > ++              : next;
> > > > ++    if (! accountingDiffTolerated(parser, tok, s, accountAfter,
> > > > __LINE__,
> > > > ++                                  account)) {
> > > > ++      accountingOnAbort(parser);
> > > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > > ++    }
> > > > ++#endif
> > > > +     *eventEndPP = next;
> > > > +     switch (tok) {
> > > > +     case XML_TOK_TRAILING_CR:
> > > > +@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int
> > > > startTagLevel,
> > > > const ENCODING *enc,
> > > > +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> > > > +           enc, s + enc->minBytesPerChar, next - enc-
> > > > > minBytesPerChar);
> > > > +       if (ch) {
> > > > ++#ifdef XML_DTD
> > > > ++        /* NOTE: We are replacing 4-6 characters original input
> > > > for
> > > > 1
> > > > character
> > > > ++         *       so there is no amplification and hence
> > > > recording
> > > > without
> > > > ++         *       protection. */
> > > > ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> > > > ++                                ((char *)&ch) +
> > > > sizeof(XML_Char),
> > > > __LINE__,
> > > > ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> > > > ++#endif /* XML_DTD */
> > > > +         if (parser->m_characterDataHandler)
> > > > +           parser->m_characterDataHandler(parser->m_handlerArg,
> > > > &ch,
> > > > 1);
> > > > +         else if (parser->m_defaultHandler)
> > > > +@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int
> > > > startTagLevel,
> > > > const ENCODING *enc,
> > > > +       }
> > > > +       tag->name.str = (XML_Char *)tag->buf;
> > > > +       *toPtr = XML_T('\0');
> > > > +-      result = storeAtts(parser, enc, s, &(tag->name), &(tag-
> > > > > bindings));
> > > > ++      result
> > > > ++          = storeAtts(parser, enc, s, &(tag->name), &(tag-
> > > > > bindings),
> > > > account);
> > > > +       if (result)
> > > > +         return result;
> > > > +       if (parser->m_startElementHandler)
> > > > +@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int
> > > > startTagLevel,
> > > > const ENCODING *enc,
> > > > +       if (! name.str)
> > > > +         return XML_ERROR_NO_MEMORY;
> > > > +       poolFinish(&parser->m_tempPool);
> > > > +-      result = storeAtts(parser, enc, s, &name, &bindings);
> > > > ++      result = storeAtts(parser, enc, s, &name, &bindings,
> > > > ++                         XML_ACCOUNT_NONE /* token spans whole
> > > > start
> > > > tag */);
> > > > +       if (result != XML_ERROR_NONE) {
> > > > +         freeBindings(parser, bindings);
> > > > +         return result;
> > > > +@@ -2907,7 +3057,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) {
> > > > +@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING
> > > > *bindings) {
> > > > + */
> > > > + static enum XML_Error
> > > > + storeAtts(XML_Parser parser, const ENCODING *enc, const char
> > > > *attStr,
> > > > +-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
> > > > ++          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
> > > > ++          enum XML_Account account) {
> > > > +   DTD *const dtd = parser->m_dtd; /* save one level of
> > > > indirection
> > > > */
> > > > +   ELEMENT_TYPE *elementType;
> > > > +   int nDefaultAtts;
> > > > +@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const
> > > > ENCODING
> > > > *enc, const char *attStr,
> > > > +       /* normalize the attribute value */
> > > > +       result = storeAttributeValue(
> > > > +           parser, enc, isCdata, parser->m_atts[i].valuePtr,
> > > > +-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
> > > > ++          parser->m_atts[i].valueEnd, &parser->m_tempPool,
> > > > account);
> > > > +       if (result)
> > > > +         return result;
> > > > +       appAtts[attIndex] = poolStart(&parser->m_tempPool);
> > > > +@@ -3535,9 +3687,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) {
> > > > +@@ -3557,7 +3709,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;
> > > > +@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const
> > > > ENCODING *enc, const char **startPtr,
> > > > +   for (;;) {
> > > > +     const char *next;
> > > > +     int tok = XmlCdataSectionTok(enc, s, end, &next);
> > > > ++#ifdef XML_DTD
> > > > ++    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) {
> > > > +     case XML_TOK_CDATA_SECT_CLOSE:
> > > > +@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const
> > > > ENCODING *enc, const char **startPtr,
> > > > +   *eventPP = s;
> > > > +   *startPtr = NULL;
> > > > +   tok = XmlIgnoreSectionTok(enc, s, end, &next);
> > > > ++#  ifdef XML_DTD
> > > > ++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> > > > ++                                XML_ACCOUNT_DIRECT)) {
> > > > ++    accountingOnAbort(parser);
> > > > ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > > ++  }
> > > > ++#  endif
> > > > +   *eventEndPP = next;
> > > > +   switch (tok) {
> > > > +   case XML_TOK_IGNORE_SECT:
> > > > +@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int
> > > > isGeneralTextEntity, const char *s,
> > > > +   const char *versionend;
> > > > +   const XML_Char *storedversion = NULL;
> > > > +   int standalone = -1;
> > > > ++
> > > > ++#ifdef XML_DTD
> > > > ++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s,
> > > > next,
> > > > __LINE__,
> > > > ++                                XML_ACCOUNT_DIRECT)) {
> > > > ++    accountingOnAbort(parser);
> > > > ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > > ++  }
> > > > ++#endif
> > > > ++
> > > > +   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
> > > > +           isGeneralTextEntity, parser->m_encoding, s, next,
> > > > &parser-
> > > > > m_eventPtr,
> > > > +           &version, &versionend, &encodingName, &newEncoding,
> > > > &standalone)) {
> > > > +@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser
> > > > parser,
> > > > const char *s, const char *end,
> > > > +
> > > > +   for (;;) {
> > > > +     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
> > > > ++    /* Note: Except for XML_TOK_BOM below, these bytes are
> > > > accounted
> > > > later in:
> > > > ++             - storeEntityValue
> > > > ++             - processXmlDecl
> > > > ++    */
> > > > +     parser->m_eventEndPtr = next;
> > > > +     if (tok <= 0) {
> > > > +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> > > > XML_TOK_INVALID) {
> > > > +@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser
> > > > parser,
> > > > const char *s, const char *end,
> > > > +         break;
> > > > +       }
> > > > +       /* found end of entity value - can store it now */
> > > > +-      return storeEntityValue(parser, parser->m_encoding, s,
> > > > end);
> > > > ++      return storeEntityValue(parser, parser->m_encoding, s,
> > > > end,
> > > > ++                              XML_ACCOUNT_DIRECT);
> > > > +     } else if (tok == XML_TOK_XML_DECL) {
> > > > +       enum XML_Error result;
> > > > +       result = processXmlDecl(parser, 0, start, next);
> > > > +@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser
> > > > parser,
> > > > const char *s, const char *end,
> > > > +     */
> > > > +     else if (tok == XML_TOK_BOM && next == end
> > > > +              && ! parser->m_parsingStatus.finalBuffer) {
> > > > ++#  ifdef XML_DTD
> > > > ++      if (! accountingDiffTolerated(parser, tok, s, next,
> > > > __LINE__,
> > > > ++                                    XML_ACCOUNT_DIRECT)) {
> > > > ++        accountingOnAbort(parser);
> > > > ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > > ++      }
> > > > ++#  endif
> > > > ++
> > > > +       *nextPtr = next;
> > > > +       return XML_ERROR_NONE;
> > > > +     }
> > > > +@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser
> > > > parser,
> > > > const char *s, const char *end,
> > > > +   }
> > > > +   /* This would cause the next stage, i.e. doProlog to be
> > > > passed
> > > > XML_TOK_BOM.
> > > > +      However, when parsing an external subset, doProlog will
> > > > not
> > > > accept a BOM
> > > > +-     as valid, and report a syntax error, so we have to skip
> > > > the
> > > > BOM
> > > > ++     as valid, and report a syntax error, so we have to skip
> > > > the
> > > > BOM,
> > > > and
> > > > ++     account for the BOM bytes.
> > > > +   */
> > > > +   else if (tok == XML_TOK_BOM) {
> > > > ++    if (! accountingDiffTolerated(parser, tok, s, next,
> > > > __LINE__,
> > > > ++                                  XML_ACCOUNT_DIRECT)) {
> > > > ++      accountingOnAbort(parser);
> > > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > > ++    }
> > > > ++
> > > > +     s = next;
> > > > +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > > +   }
> > > > +
> > > > +   parser->m_processor = prologProcessor;
> > > > +   return doProlog(parser, parser->m_encoding, s, end, tok,
> > > > next,
> > > > nextPtr,
> > > > +-                  (XML_Bool)! parser-
> > > > >m_parsingStatus.finalBuffer,
> > > > XML_TRUE);
> > > > ++                  (XML_Bool)! parser-
> > > > >m_parsingStatus.finalBuffer,
> > > > XML_TRUE,
> > > > ++                  XML_ACCOUNT_DIRECT);
> > > > + }
> > > > +
> > > > + static enum XML_Error PTRCALL
> > > > +@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser,
> > > > const
> > > > char *s, const char *end,
> > > > +
> > > > +   for (;;) {
> > > > +     tok = XmlPrologTok(enc, start, end, &next);
> > > > ++    /* Note: These bytes are accounted later in:
> > > > ++             - storeEntityValue
> > > > ++    */
> > > > +     if (tok <= 0) {
> > > > +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> > > > XML_TOK_INVALID) {
> > > > +         *nextPtr = s;
> > > > +@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser,
> > > > const
> > > > char *s, const char *end,
> > > > +         break;
> > > > +       }
> > > > +       /* found end of entity value - can store it now */
> > > > +-      return storeEntityValue(parser, enc, s, end);
> > > > ++      return storeEntityValue(parser, enc, s, end,
> > > > XML_ACCOUNT_DIRECT);
> > > > +     }
> > > > +     start = next;
> > > > +   }
> > > > +@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const
> > > > char
> > > > *s, const char *end,
> > > > +   const char *next = s;
> > > > +   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > > +   return doProlog(parser, parser->m_encoding, s, end, tok,
> > > > next,
> > > > nextPtr,
> > > > +-                  (XML_Bool)! parser-
> > > > >m_parsingStatus.finalBuffer,
> > > > XML_TRUE);
> > > > ++                  (XML_Bool)! parser-
> > > > >m_parsingStatus.finalBuffer,
> > > > XML_TRUE,
> > > > ++                  XML_ACCOUNT_DIRECT);
> > > > + }
> > > > +
> > > > + static enum XML_Error
> > > > + doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
> > > > const
> > > > char *end,
> > > > +          int tok, const char *next, const char **nextPtr,
> > > > XML_Bool
> > > > haveMore,
> > > > +-         XML_Bool allowClosingDoctype) {
> > > > ++         XML_Bool allowClosingDoctype, enum XML_Account
> > > > account) {
> > > > + #ifdef XML_DTD
> > > > +   static const XML_Char externalSubsetName[] = {ASCII_HASH,
> > > > '\0'};
> > > > + #endif /* XML_DTD */
> > > > +@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const
> > > > ENCODING
> > > > *enc, const char *s, const char *end,
> > > > +   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
> > > > +   static const XML_Char enumValueStart[] = {ASCII_LPAREN,
> > > > '\0'};
> > > > +
> > > > ++#ifndef XML_DTD
> > > > ++  UNUSED_P(account);
> > > > ++#endif
> > > > ++
> > > > +   /* save one level of indirection */
> > > > +   DTD *const dtd = parser->m_dtd;
> > > > +
> > > > +@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const
> > > > ENCODING
> > > > *enc, const char *s, const char *end,
> > > > +       }
> > > > +     }
> > > > +     role = XmlTokenRole(&parser->m_prologState, tok, s, next,
> > > > enc);
> > > > ++#ifdef XML_DTD
> > > > ++    switch (role) {
> > > > ++    case XML_ROLE_INSTANCE_START: // bytes accounted in
> > > > contentProcessor
> > > > ++    case XML_ROLE_XML_DECL:       // bytes accounted in
> > > > processXmlDecl
> > > > ++    case XML_ROLE_TEXT_DECL:      // bytes accounted in
> > > > processXmlDecl
> > > > ++      break;
> > > > ++    default:
> > > > ++      if (! accountingDiffTolerated(parser, tok, s, next,
> > > > __LINE__,
> > > > account)) {
> > > > ++        accountingOnAbort(parser);
> > > > ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > > ++      }
> > > > ++    }
> > > > ++#endif
> > > > +     switch (role) {
> > > > +     case XML_ROLE_XML_DECL: {
> > > > +       enum XML_Error result = processXmlDecl(parser, 0, s,
> > > > next);
> > > > +@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING
> > > > *enc,
> > > > const char *s, const char *end,
> > > > +         const XML_Char *attVal;
> > > > +         enum XML_Error result = storeAttributeValue(
> > > > +             parser, enc, parser->m_declAttributeIsCdata,
> > > > +-            s + enc->minBytesPerChar, next - enc-
> > > > >minBytesPerChar,
> > > > &dtd->pool);
> > > > ++            s + enc->minBytesPerChar, next - enc-
> > > > >minBytesPerChar,
> > > > &dtd->pool,
> > > > ++            XML_ACCOUNT_NONE);
> > > > +         if (result)
> > > > +           return result;
> > > > +         attVal = poolStart(&dtd->pool);
> > > > +@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING
> > > > *enc,
> > > > const char *s, const char *end,
> > > > +       break;
> > > > +     case XML_ROLE_ENTITY_VALUE:
> > > > +       if (dtd->keepProcessing) {
> > > > +-        enum XML_Error result = storeEntityValue(
> > > > +-            parser, enc, s + enc->minBytesPerChar, next - enc-
> > > > > minBytesPerChar);
> > > > ++        enum XML_Error result
> > > > ++            = storeEntityValue(parser, enc, s + enc-
> > > > > minBytesPerChar,
> > > > ++                               next - enc->minBytesPerChar,
> > > > XML_ACCOUNT_NONE);
> > > > +         if (parser->m_declEntity) {
> > > > +           parser->m_declEntity->textPtr = poolStart(&dtd-
> > > > > entityValuePool);
> > > > +           parser->m_declEntity->textLen
> > > > +@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const
> > > > ENCODING
> > > > *enc, const char *s, const char *end,
> > > > +         if (parser->m_externalEntityRefHandler) {
> > > > +           dtd->paramEntityRead = XML_FALSE;
> > > > +           entity->open = XML_TRUE;
> > > > ++          entityTrackingOnOpen(parser, entity, __LINE__);
> > > > +           if (! parser->m_externalEntityRefHandler(
> > > > +                   parser->m_externalEntityRefHandlerArg, 0,
> > > > entity-
> > > > > base,
> > > > +                   entity->systemId, entity->publicId)) {
> > > > ++            entityTrackingOnClose(parser, entity, __LINE__);
> > > > +             entity->open = XML_FALSE;
> > > > +             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> > > > +           }
> > > > ++          entityTrackingOnClose(parser, entity, __LINE__);
> > > > +           entity->open = XML_FALSE;
> > > > +           handleDefault = XML_FALSE;
> > > > +           if (! dtd->paramEntityRead) {
> > > > +@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const
> > > > char
> > > > *s, const char *end,
> > > > +   for (;;) {
> > > > +     const char *next = NULL;
> > > > +     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > > ++#ifdef XML_DTD
> > > > ++    if (! accountingDiffTolerated(parser, tok, s, next,
> > > > __LINE__,
> > > > ++                                  XML_ACCOUNT_DIRECT)) {
> > > > ++      accountingOnAbort(parser);
> > > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > > ++    }
> > > > ++#endif
> > > > +     parser->m_eventEndPtr = next;
> > > > +     switch (tok) {
> > > > +     /* report partial linebreak - it might be the last token */
> > > > +@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser,
> > > > ENTITY
> > > > *entity, XML_Bool betweenDecl) {
> > > > +       return XML_ERROR_NO_MEMORY;
> > > > +   }
> > > > +   entity->open = XML_TRUE;
> > > > ++#ifdef XML_DTD
> > > > ++  entityTrackingOnOpen(parser, entity, __LINE__);
> > > > ++#endif
> > > > +   entity->processed = 0;
> > > > +   openEntity->next = parser->m_openInternalEntities;
> > > > +   parser->m_openInternalEntities = openEntity;
> > > > +@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser,
> > > > ENTITY *entity, XML_Bool betweenDecl) {
> > > > +     int tok
> > > > +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> > > > textEnd, &next);
> > > > +     result = doProlog(parser, parser->m_internalEncoding,
> > > > textStart,
> > > > textEnd,
> > > > +-                      tok, next, &next, XML_FALSE, XML_FALSE);
> > > > ++                      tok, next, &next, XML_FALSE, XML_FALSE,
> > > > ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> > > > +   } else
> > > > + #endif /* XML_DTD */
> > > > +     result = doContent(parser, parser->m_tagLevel, parser-
> > > > > m_internalEncoding,
> > > > +-                       textStart, textEnd, &next, XML_FALSE);
> > > > ++                       textStart, textEnd, &next, XML_FALSE,
> > > > ++                       XML_ACCOUNT_ENTITY_EXPANSION);
> > > > +
> > > > +   if (result == XML_ERROR_NONE) {
> > > > +     if (textEnd != next && parser->m_parsingStatus.parsing ==
> > > > XML_SUSPENDED) {
> > > > +       entity->processed = (int)(next - textStart);
> > > > +       parser->m_processor = internalEntityProcessor;
> > > > +     } else {
> > > > ++#ifdef XML_DTD
> > > > ++      entityTrackingOnClose(parser, entity, __LINE__);
> > > > ++#endif /* XML_DTD */
> > > > +       entity->open = XML_FALSE;
> > > > +       parser->m_openInternalEntities = openEntity->next;
> > > > +       /* put openEntity back in list of free instances */
> > > > +@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser
> > > > parser,
> > > > const char *s, const char *end,
> > > > +     int tok
> > > > +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> > > > textEnd, &next);
> > > > +     result = doProlog(parser, parser->m_internalEncoding,
> > > > textStart,
> > > > textEnd,
> > > > +-                      tok, next, &next, XML_FALSE, XML_TRUE);
> > > > ++                      tok, next, &next, XML_FALSE, XML_TRUE,
> > > > ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> > > > +   } else
> > > > + #endif /* XML_DTD */
> > > > +     result = doContent(parser, openEntity->startTagLevel,
> > > > +                        parser->m_internalEncoding, textStart,
> > > > textEnd, &next,
> > > > +-                       XML_FALSE);
> > > > ++                       XML_FALSE,
> > > > XML_ACCOUNT_ENTITY_EXPANSION);
> > > > +
> > > > +   if (result != XML_ERROR_NONE)
> > > > +     return result;
> > > > +@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser,
> > > > const
> > > > char *s, const char *end,
> > > > +     entity->processed = (int)(next - (char *)entity->textPtr);
> > > > +     return result;
> > > > +   } else {
> > > > ++#ifdef XML_DTD
> > > > ++    entityTrackingOnClose(parser, entity, __LINE__);
> > > > ++#endif
> > > > +     entity->open = XML_FALSE;
> > > > +     parser->m_openInternalEntities = openEntity->next;
> > > > +     /* put openEntity back in list of free instances */
> > > > +@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser,
> > > > const
> > > > char *s, const char *end,
> > > > +     parser->m_processor = prologProcessor;
> > > > +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> > > > +     return doProlog(parser, parser->m_encoding, s, end, tok,
> > > > next,
> > > > nextPtr,
> > > > +-                    (XML_Bool)! parser-
> > > > > m_parsingStatus.finalBuffer,
> > > > XML_TRUE);
> > > > ++                    (XML_Bool)! parser-
> > > > > m_parsingStatus.finalBuffer,
> > > > XML_TRUE,
> > > > ++                    XML_ACCOUNT_DIRECT);
> > > > +   } else
> > > > + #endif /* XML_DTD */
> > > > +   {
> > > > +@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser,
> > > > const
> > > > char *s, const char *end,
> > > > +     /* see externalEntityContentProcessor vs contentProcessor
> > > > */
> > > > +     return doContent(parser, parser->m_parentParser ? 1 : 0,
> > > > parser-
> > > > > m_encoding,
> > > > +                      s, end, nextPtr,
> > > > +-                     (XML_Bool)! parser-
> > > > > m_parsingStatus.finalBuffer);
> > > > ++                     (XML_Bool)! parser-
> > > > > m_parsingStatus.finalBuffer,
> > > > ++                     XML_ACCOUNT_DIRECT);
> > > > +   }
> > > > + }
> > > > +
> > > > +@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const
> > > > char
> > > > *s, const char *end,
> > > > +
> > > > + static enum XML_Error
> > > > + storeAttributeValue(XML_Parser parser, const ENCODING *enc,
> > > > XML_Bool
> > > > isCdata,
> > > > +-                    const char *ptr, const char *end,
> > > > STRING_POOL
> > > > *pool) {
> > > > ++                    const char *ptr, const char *end,
> > > > STRING_POOL
> > > > *pool,
> > > > ++                    enum XML_Account account) {
> > > > +   enum XML_Error result
> > > > +-      = appendAttributeValue(parser, enc, isCdata, ptr, end,
> > > > pool);
> > > > ++      = appendAttributeValue(parser, enc, isCdata, ptr, end,
> > > > pool,
> > > > account);
> > > > +   if (result)
> > > > +     return result;
> > > > +   if (! isCdata && poolLength(pool) && poolLastChar(pool) ==
> > > > 0x20)
> > > > +@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser,
> > > > const
> > > > ENCODING *enc, XML_Bool isCdata,
> > > > +
> > > > + static enum XML_Error
> > > > + appendAttributeValue(XML_Parser parser, const ENCODING *enc,
> > > > XML_Bool
> > > > isCdata,
> > > > +-                     const char *ptr, const char *end,
> > > > STRING_POOL
> > > > *pool) {
> > > > ++                     const char *ptr, const char *end,
> > > > STRING_POOL
> > > > *pool,
> > > > ++                     enum XML_Account account) {
> > > > +   DTD *const dtd = parser->m_dtd; /* save one level of
> > > > indirection
> > > > */
> > > > ++#ifndef XML_DTD
> > > > ++  UNUSED_P(account);
> > > > ++#endif
> > > > ++
> > > > +   for (;;) {
> > > > +     const char *next;
> > > > +     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
> > > > ++#ifdef XML_DTD
> > > > ++    if (! accountingDiffTolerated(parser, tok, ptr, next,
> > > > __LINE__,
> > > > account)) {
> > > > ++      accountingOnAbort(parser);
> > > > ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > > ++    }
> > > > ++#endif
> > > > +     switch (tok) {
> > > > +     case XML_TOK_NONE:
> > > > +       return XML_ERROR_NONE;
> > > > +@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser,
> > > > const
> > > > ENCODING *enc, XML_Bool isCdata,
> > > > +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> > > > +           enc, ptr + enc->minBytesPerChar, next - enc-
> > > > > minBytesPerChar);
> > > > +       if (ch) {
> > > > ++#ifdef XML_DTD
> > > > ++        /* NOTE: We are replacing 4-6 characters original input
> > > > for
> > > > 1
> > > > character
> > > > ++         *       so there is no amplification and hence
> > > > recording
> > > > without
> > > > ++         *       protection. */
> > > > ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> > > > ++                                ((char *)&ch) +
> > > > sizeof(XML_Char),
> > > > __LINE__,
> > > > ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> > > > ++#endif /* XML_DTD */
> > > > +         if (! poolAppendChar(pool, ch))
> > > > +           return XML_ERROR_NO_MEMORY;
> > > > +         break;
> > > > +@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser,
> > > > const
> > > > ENCODING *enc, XML_Bool isCdata,
> > > > +         enum XML_Error result;
> > > > +         const XML_Char *textEnd = entity->textPtr + entity-
> > > > > textLen;
> > > > +         entity->open = XML_TRUE;
> > > > ++#ifdef XML_DTD
> > > > ++        entityTrackingOnOpen(parser, entity, __LINE__);
> > > > ++#endif
> > > > +         result = appendAttributeValue(parser, parser-
> > > > > m_internalEncoding,
> > > > +-                                      isCdata, (char *)entity-
> > > > > textPtr,
> > > > +-                                      (char *)textEnd, pool);
> > > > ++                                      isCdata, (const char
> > > > *)entity-
> > > > > textPtr,
> > > > ++                                      (const char *)textEnd,
> > > > pool,
> > > > ++
> > > > XML_ACCOUNT_ENTITY_EXPANSION);
> > > > ++#ifdef XML_DTD
> > > > ++        entityTrackingOnClose(parser, entity, __LINE__);
> > > > ++#endif
> > > > +         entity->open = XML_FALSE;
> > > > +         if (result)
> > > > +           return result;
> > > > +@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser,
> > > > const
> > > > ENCODING *enc, XML_Bool isCdata,
> > > > +
> > > > + static enum XML_Error
> > > > + storeEntityValue(XML_Parser parser, const ENCODING *enc,
> > > > +-                 const char *entityTextPtr, const char
> > > > *entityTextEnd) {
> > > > ++                 const char *entityTextPtr, const char
> > > > *entityTextEnd,
> > > > ++                 enum XML_Account account) {
> > > > +   DTD *const dtd = parser->m_dtd; /* save one level of
> > > > indirection
> > > > */
> > > > +   STRING_POOL *pool = &(dtd->entityValuePool);
> > > > +   enum XML_Error result = XML_ERROR_NONE;
> > > > + #ifdef XML_DTD
> > > > +   int oldInEntityValue = parser->m_prologState.inEntityValue;
> > > > +   parser->m_prologState.inEntityValue = 1;
> > > > ++#else
> > > > ++  UNUSED_P(account);
> > > > + #endif /* XML_DTD */
> > > > +   /* never return Null for the value argument in
> > > > EntityDeclHandler,
> > > > +      since this would indicate an external entity; therefore we
> > > > +@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const
> > > > ENCODING *enc,
> > > > +   for (;;) {
> > > > +     const char *next;
> > > > +     int tok = XmlEntityValueTok(enc, entityTextPtr,
> > > > entityTextEnd,
> > > > &next);
> > > > ++
> > > > ++#ifdef XML_DTD
> > > > ++    if (! accountingDiffTolerated(parser, tok, entityTextPtr,
> > > > next,
> > > > __LINE__,
> > > > ++                                  account)) {
> > > > ++      accountingOnAbort(parser);
> > > > ++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> > > > ++      goto endEntityValue;
> > > > ++    }
> > > > ++#endif
> > > > ++
> > > > +     switch (tok) {
> > > > +     case XML_TOK_PARAM_ENTITY_REF:
> > > > + #ifdef XML_DTD
> > > > +@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser,
> > > > const
> > > > ENCODING *enc,
> > > > +           if (parser->m_externalEntityRefHandler) {
> > > > +             dtd->paramEntityRead = XML_FALSE;
> > > > +             entity->open = XML_TRUE;
> > > > ++            entityTrackingOnOpen(parser, entity, __LINE__);
> > > > +             if (! parser->m_externalEntityRefHandler(
> > > > +                     parser->m_externalEntityRefHandlerArg, 0,
> > > > entity-
> > > > > base,
> > > > +                     entity->systemId, entity->publicId)) {
> > > > ++              entityTrackingOnClose(parser, entity, __LINE__);
> > > > +               entity->open = XML_FALSE;
> > > > +               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> > > > +               goto endEntityValue;
> > > > +             }
> > > > ++            entityTrackingOnClose(parser, entity, __LINE__);
> > > > +             entity->open = XML_FALSE;
> > > > +             if (! dtd->paramEntityRead)
> > > > +               dtd->keepProcessing = dtd->standalone;
> > > > +@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const
> > > > ENCODING *enc,
> > > > +             dtd->keepProcessing = dtd->standalone;
> > > > +         } else {
> > > > +           entity->open = XML_TRUE;
> > > > ++          entityTrackingOnOpen(parser, entity, __LINE__);
> > > > +           result = storeEntityValue(
> > > > +-              parser, parser->m_internalEncoding, (char
> > > > *)entity-
> > > > > textPtr,
> > > > +-              (char *)(entity->textPtr + entity->textLen));
> > > > ++              parser, parser->m_internalEncoding, (const char
> > > > *)entity->textPtr,
> > > > ++              (const char *)(entity->textPtr + entity-
> > > > >textLen),
> > > > ++              XML_ACCOUNT_ENTITY_EXPANSION);
> > > > ++          entityTrackingOnClose(parser, entity, __LINE__);
> > > > +           entity->open = XML_FALSE;
> > > > +           if (result)
> > > > +             goto endEntityValue;
> > > > +@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const
> > > > XML_Memory_Handling_Suite *memsuite) {
> > > > +   memcpy(result, s, charsRequired * sizeof(XML_Char));
> > > > +   return result;
> > > > + }
> > > > ++
> > > > ++#ifdef XML_DTD
> > > > ++
> > > > ++static float
> > > > ++accountingGetCurrentAmplification(XML_Parser rootParser) {
> > > > ++  const XmlBigCount countBytesOutput
> > > > ++      = rootParser->m_accounting.countBytesDirect
> > > > ++        + rootParser->m_accounting.countBytesIndirect;
> > > > ++  const float amplificationFactor
> > > > ++      = rootParser->m_accounting.countBytesDirect
> > > > ++            ? (countBytesOutput
> > > > ++               / (float)(rootParser-
> > > > > m_accounting.countBytesDirect))
> > > > ++            : 1.0f;
> > > > ++  assert(! rootParser->m_parentParser);
> > > > ++  return amplificationFactor;
> > > > ++}
> > > > ++
> > > > ++static void
> > > > ++accountingReportStats(XML_Parser originParser, const char
> > > > *epilog)
> > > > {
> > > > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > > > NULL);
> > > > ++  assert(! rootParser->m_parentParser);
> > > > ++
> > > > ++  if (rootParser->m_accounting.debugLevel < 1) {
> > > > ++    return;
> > > > ++  }
> > > > ++
> > > > ++  const float amplificationFactor
> > > > ++      = accountingGetCurrentAmplification(rootParser);
> > > > ++  fprintf(stderr,
> > > > ++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
> > > > ++              "10") ", indirect " EXPAT_FMT_ULL("10") ",
> > > > amplification %8.2f%s",
> > > > ++          (void *)rootParser, rootParser-
> > > > > m_accounting.countBytesDirect,
> > > > ++          rootParser->m_accounting.countBytesIndirect,
> > > > ++          (double)amplificationFactor, epilog);
> > > > ++}
> > > > ++
> > > > ++static void
> > > > ++accountingOnAbort(XML_Parser originParser) {
> > > > ++  accountingReportStats(originParser, " ABORTING\n");
> > > > ++}
> > > > ++
> > > > ++static void
> > > > ++accountingReportDiff(XML_Parser rootParser,
> > > > ++                     unsigned int levelsAwayFromRootParser,
> > > > const
> > > > char *before,
> > > > ++                     const char *after, ptrdiff_t bytesMore,
> > > > int
> > > > source_line,
> > > > ++                     enum XML_Account account) {
> > > > ++  assert(! rootParser->m_parentParser);
> > > > ++
> > > > ++  fprintf(stderr,
> > > > ++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d,
> > > > xmlparse.c:%d) %*s\"",
> > > > ++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" :
> > > > "EXP",
> > > > ++          levelsAwayFromRootParser, source_line, 10, "");
> > > > ++
> > > > ++  const char ellipis[] = "[..]";
> > > > ++  const size_t ellipsisLength = sizeof(ellipis) /* because
> > > > compile-
> > > > time */ - 1;
> > > > ++  const unsigned int contextLength = 10;
> > > > ++
> > > > ++  /* Note: Performance is of no concern here */
> > > > ++  const char *walker = before;
> > > > ++  if ((rootParser->m_accounting.debugLevel >= 3)
> > > > ++      || (after - before)
> > > > ++             <= (ptrdiff_t)(contextLength + ellipsisLength +
> > > > contextLength)) {
> > > > ++    for (; walker < after; walker++) {
> > > > ++      fprintf(stderr, "%s",
> > > > unsignedCharToPrintable(walker[0]));
> > > > ++    }
> > > > ++  } else {
> > > > ++    for (; walker < before + contextLength; walker++) {
> > > > ++      fprintf(stderr, "%s",
> > > > unsignedCharToPrintable(walker[0]));
> > > > ++    }
> > > > ++    fprintf(stderr, ellipis);
> > > > ++    walker = after - contextLength;
> > > > ++    for (; walker < after; walker++) {
> > > > ++      fprintf(stderr, "%s",
> > > > unsignedCharToPrintable(walker[0]));
> > > > ++    }
> > > > ++  }
> > > > ++  fprintf(stderr, "\"\n");
> > > > ++}
> > > > ++
> > > > ++static XML_Bool
> > > > ++accountingDiffTolerated(XML_Parser originParser, int tok, const
> > > > char
> > > > *before,
> > > > ++                        const char *after, int source_line,
> > > > ++                        enum XML_Account account) {
> > > > ++  /* Note: We need to check the token type *first* to be sure
> > > > that
> > > > ++   *       we can even access variable <after>, safely.
> > > > ++   *       E.g. for XML_TOK_NONE <after> may hold an invalid
> > > > pointer.
> > > > */
> > > > ++  switch (tok) {
> > > > ++  case XML_TOK_INVALID:
> > > > ++  case XML_TOK_PARTIAL:
> > > > ++  case XML_TOK_PARTIAL_CHAR:
> > > > ++  case XML_TOK_NONE:
> > > > ++    return XML_TRUE;
> > > > ++  }
> > > > ++
> > > > ++  if (account == XML_ACCOUNT_NONE)
> > > > ++    return XML_TRUE; /* because these bytes have been accounted
> > > > for,
> > > > already */
> > > > ++
> > > > ++  unsigned int levelsAwayFromRootParser;
> > > > ++  const XML_Parser rootParser
> > > > ++      = getRootParserOf(originParser,
> > > > &levelsAwayFromRootParser);
> > > > ++  assert(! rootParser->m_parentParser);
> > > > ++
> > > > ++  const int isDirect
> > > > ++      = (account == XML_ACCOUNT_DIRECT) && (originParser ==
> > > > rootParser);
> > > > ++  const ptrdiff_t bytesMore = after - before;
> > > > ++
> > > > ++  XmlBigCount *const additionTarget
> > > > ++      = isDirect ? &rootParser->m_accounting.countBytesDirect
> > > > ++                 : &rootParser-
> > > > >m_accounting.countBytesIndirect;
> > > > ++
> > > > ++  /* Detect and avoid integer overflow */
> > > > ++  if (*additionTarget > (XmlBigCount)(-1) -
> > > > (XmlBigCount)bytesMore)
> > > > ++    return XML_FALSE;
> > > > ++  *additionTarget += bytesMore;
> > > > ++
> > > > ++  const XmlBigCount countBytesOutput
> > > > ++      = rootParser->m_accounting.countBytesDirect
> > > > ++        + rootParser->m_accounting.countBytesIndirect;
> > > > ++  const float amplificationFactor
> > > > ++      = accountingGetCurrentAmplification(rootParser);
> > > > ++  const XML_Bool tolerated
> > > > ++      = (countBytesOutput < rootParser-
> > > > > m_accounting.activationThresholdBytes)
> > > > ++        || (amplificationFactor
> > > > ++            <= rootParser-
> > > > > m_accounting.maximumAmplificationFactor);
> > > > ++
> > > > ++  if (rootParser->m_accounting.debugLevel >= 2) {
> > > > ++    accountingReportStats(rootParser, "");
> > > > ++    accountingReportDiff(rootParser, levelsAwayFromRootParser,
> > > > before, after,
> > > > ++                         bytesMore, source_line, account);
> > > > ++  }
> > > > ++
> > > > ++  return tolerated;
> > > > ++}
> > > > ++
> > > > ++static void
> > > > ++entityTrackingReportStats(XML_Parser rootParser, ENTITY
> > > > *entity,
> > > > ++                          const char *action, int sourceLine) {
> > > > ++  assert(! rootParser->m_parentParser);
> > > > ++  if (rootParser->m_entity_stats.debugLevel < 1)
> > > > ++    return;
> > > > ++
> > > > ++#  if defined(XML_UNICODE)
> > > > ++  const char *const entityName = "[..]";
> > > > ++#  else
> > > > ++  const char *const entityName = entity->name;
> > > > ++#  endif
> > > > ++
> > > > ++  fprintf(
> > > > ++      stderr,
> > > > ++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s;
> > > > %s
> > > > length %d (xmlparse.c:%d)\n",
> > > > ++      (void *)rootParser, rootParser-
> > > > > m_entity_stats.countEverOpened,
> > > > ++      rootParser->m_entity_stats.currentDepth,
> > > > ++      rootParser->m_entity_stats.maximumDepthSeen,
> > > > ++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
> > > > ++      entity->is_param ? "%" : "&", entityName, action, entity-
> > > > > textLen,
> > > > ++      sourceLine);
> > > > ++}
> > > > ++
> > > > ++static void
> > > > ++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity,
> > > > int
> > > > sourceLine) {
> > > > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > > > NULL);
> > > > ++  assert(! rootParser->m_parentParser);
> > > > ++
> > > > ++  rootParser->m_entity_stats.countEverOpened++;
> > > > ++  rootParser->m_entity_stats.currentDepth++;
> > > > ++  if (rootParser->m_entity_stats.currentDepth
> > > > ++      > rootParser->m_entity_stats.maximumDepthSeen) {
> > > > ++    rootParser->m_entity_stats.maximumDepthSeen++;
> > > > ++  }
> > > > ++
> > > > ++  entityTrackingReportStats(rootParser, entity, "OPEN ",
> > > > sourceLine);
> > > > ++}
> > > > ++
> > > > ++static void
> > > > ++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity,
> > > > int
> > > > sourceLine) {
> > > > ++  const XML_Parser rootParser = getRootParserOf(originParser,
> > > > NULL);
> > > > ++  assert(! rootParser->m_parentParser);
> > > > ++
> > > > ++  entityTrackingReportStats(rootParser, entity, "CLOSE",
> > > > sourceLine);
> > > > ++  rootParser->m_entity_stats.currentDepth--;
> > > > ++}
> > > > ++
> > > > ++static XML_Parser
> > > > ++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff)
> > > > {
> > > > ++  XML_Parser rootParser = parser;
> > > > ++  unsigned int stepsTakenUpwards = 0;
> > > > ++  while (rootParser->m_parentParser) {
> > > > ++    rootParser = rootParser->m_parentParser;
> > > > ++    stepsTakenUpwards++;
> > > > ++  }
> > > > ++  assert(! rootParser->m_parentParser);
> > > > ++  if (outLevelDiff != NULL) {
> > > > ++    *outLevelDiff = stepsTakenUpwards;
> > > > ++  }
> > > > ++  return rootParser;
> > > > ++}
> > > > ++
> > > > ++static const char *
> > > > ++unsignedCharToPrintable(unsigned char c) {
> > > > ++  switch (c) {
> > > > ++  case 0:
> > > > ++    return "\\0";
> > > > ++  case 1:
> > > > ++    return "\\x1";
> > > > ++  case 2:
> > > > ++    return "\\x2";
> > > > ++  case 3:
> > > > ++    return "\\x3";
> > > > ++  case 4:
> > > > ++    return "\\x4";
> > > > ++  case 5:
> > > > ++    return "\\x5";
> > > > ++  case 6:
> > > > ++    return "\\x6";
> > > > ++  case 7:
> > > > ++    return "\\x7";
> > > > ++  case 8:
> > > > ++    return "\\x8";
> > > > ++  case 9:
> > > > ++    return "\\t";
> > > > ++  case 10:
> > > > ++    return "\\n";
> > > > ++  case 11:
> > > > ++    return "\\xB";
> > > > ++  case 12:
> > > > ++    return "\\xC";
> > > > ++  case 13:
> > > > ++    return "\\r";
> > > > ++  case 14:
> > > > ++    return "\\xE";
> > > > ++  case 15:
> > > > ++    return "\\xF";
> > > > ++  case 16:
> > > > ++    return "\\x10";
> > > > ++  case 17:
> > > > ++    return "\\x11";
> > > > ++  case 18:
> > > > ++    return "\\x12";
> > > > ++  case 19:
> > > > ++    return "\\x13";
> > > > ++  case 20:
> > > > ++    return "\\x14";
> > > > ++  case 21:
> > > > ++    return "\\x15";
> > > > ++  case 22:
> > > > ++    return "\\x16";
> > > > ++  case 23:
> > > > ++    return "\\x17";
> > > > ++  case 24:
> > > > ++    return "\\x18";
> > > > ++  case 25:
> > > > ++    return "\\x19";
> > > > ++  case 26:
> > > > ++    return "\\x1A";
> > > > ++  case 27:
> > > > ++    return "\\x1B";
> > > > ++  case 28:
> > > > ++    return "\\x1C";
> > > > ++  case 29:
> > > > ++    return "\\x1D";
> > > > ++  case 30:
> > > > ++    return "\\x1E";
> > > > ++  case 31:
> > > > ++    return "\\x1F";
> > > > ++  case 32:
> > > > ++    return " ";
> > > > ++  case 33:
> > > > ++    return "!";
> > > > ++  case 34:
> > > > ++    return "\\\"";
> > > > ++  case 35:
> > > > ++    return "#";
> > > > ++  case 36:
> > > > ++    return "$";
> > > > ++  case 37:
> > > > ++    return "%";
> > > > ++  case 38:
> > > > ++    return "&";
> > > > ++  case 39:
> > > > ++    return "'";
> > > > ++  case 40:
> > > > ++    return "(";
> > > > ++  case 41:
> > > > ++    return ")";
> > > > ++  case 42:
> > > > ++    return "*";
> > > > ++  case 43:
> > > > ++    return "+";
> > > > ++  case 44:
> > > > ++    return ",";
> > > > ++  case 45:
> > > > ++    return "-";
> > > > ++  case 46:
> > > > ++    return ".";
> > > > ++  case 47:
> > > > ++    return "/";
> > > > ++  case 48:
> > > > ++    return "0";
> > > > ++  case 49:
> > > > ++    return "1";
> > > > ++  case 50:
> > > > ++    return "2";
> > > > ++  case 51:
> > > > ++    return "3";
> > > > ++  case 52:
> > > > ++    return "4";
> > > > ++  case 53:
> > > > ++    return "5";
> > > > ++  case 54:
> > > > ++    return "6";
> > > > ++  case 55:
> > > > ++    return "7";
> > > > ++  case 56:
> > > > ++    return "8";
> > > > ++  case 57:
> > > > ++    return "9";
> > > > ++  case 58:
> > > > ++    return ":";
> > > > ++  case 59:
> > > > ++    return ";";
> > > > ++  case 60:
> > > > ++    return "<";
> > > > ++  case 61:
> > > > ++    return "=";
> > > > ++  case 62:
> > > > ++    return ">";
> > > > ++  case 63:
> > > > ++    return "?";
> > > > ++  case 64:
> > > > ++    return "@";
> > > > ++  case 65:
> > > > ++    return "A";
> > > > ++  case 66:
> > > > ++    return "B";
> > > > ++  case 67:
> > > > ++    return "C";
> > > > ++  case 68:
> > > > ++    return "D";
> > > > ++  case 69:
> > > > ++    return "E";
> > > > ++  case 70:
> > > > ++    return "F";
> > > > ++  case 71:
> > > > ++    return "G";
> > > > ++  case 72:
> > > > ++    return "H";
> > > > ++  case 73:
> > > > ++    return "I";
> > > > ++  case 74:
> > > > ++    return "J";
> > > > ++  case 75:
> > > > ++    return "K";
> > > > ++  case 76:
> > > > ++    return "L";
> > > > ++  case 77:
> > > > ++    return "M";
> > > > ++  case 78:
> > > > ++    return "N";
> > > > ++  case 79:
> > > > ++    return "O";
> > > > ++  case 80:
> > > > ++    return "P";
> > > > ++  case 81:
> > > > ++    return "Q";
> > > > ++  case 82:
> > > > ++    return "R";
> > > > ++  case 83:
> > > > ++    return "S";
> > > > ++  case 84:
> > > > ++    return "T";
> > > > ++  case 85:
> > > > ++    return "U";
> > > > ++  case 86:
> > > > ++    return "V";
> > > > ++  case 87:
> > > > ++    return "W";
> > > > ++  case 88:
> > > > ++    return "X";
> > > > ++  case 89:
> > > > ++    return "Y";
> > > > ++  case 90:
> > > > ++    return "Z";
> > > > ++  case 91:
> > > > ++    return "[";
> > > > ++  case 92:
> > > > ++    return "\\\\";
> > > > ++  case 93:
> > > > ++    return "]";
> > > > ++  case 94:
> > > > ++    return "^";
> > > > ++  case 95:
> > > > ++    return "_";
> > > > ++  case 96:
> > > > ++    return "`";
> > > > ++  case 97:
> > > > ++    return "a";
> > > > ++  case 98:
> > > > ++    return "b";
> > > > ++  case 99:
> > > > ++    return "c";
> > > > ++  case 100:
> > > > ++    return "d";
> > > > ++  case 101:
> > > > ++    return "e";
> > > > ++  case 102:
> > > > ++    return "f";
> > > > ++  case 103:
> > > > ++    return "g";
> > > > ++  case 104:
> > > > ++    return "h";
> > > > ++  case 105:
> > > > ++    return "i";
> > > > ++  case 106:
> > > > ++    return "j";
> > > > ++  case 107:
> > > > ++    return "k";
> > > > ++  case 108:
> > > > ++    return "l";
> > > > ++  case 109:
> > > > ++    return "m";
> > > > ++  case 110:
> > > > ++    return "n";
> > > > ++  case 111:
> > > > ++    return "o";
> > > > ++  case 112:
> > > > ++    return "p";
> > > > ++  case 113:
> > > > ++    return "q";
> > > > ++  case 114:
> > > > ++    return "r";
> > > > ++  case 115:
> > > > ++    return "s";
> > > > ++  case 116:
> > > > ++    return "t";
> > > > ++  case 117:
> > > > ++    return "u";
> > > > ++  case 118:
> > > > ++    return "v";
> > > > ++  case 119:
> > > > ++    return "w";
> > > > ++  case 120:
> > > > ++    return "x";
> > > > ++  case 121:
> > > > ++    return "y";
> > > > ++  case 122:
> > > > ++    return "z";
> > > > ++  case 123:
> > > > ++    return "{";
> > > > ++  case 124:
> > > > ++    return "|";
> > > > ++  case 125:
> > > > ++    return "}";
> > > > ++  case 126:
> > > > ++    return "~";
> > > > ++  case 127:
> > > > ++    return "\\x7F";
> > > > ++  case 128:
> > > > ++    return "\\x80";
> > > > ++  case 129:
> > > > ++    return "\\x81";
> > > > ++  case 130:
> > > > ++    return "\\x82";
> > > > ++  case 131:
> > > > ++    return "\\x83";
> > > > ++  case 132:
> > > > ++    return "\\x84";
> > > > ++  case 133:
> > > > ++    return "\\x85";
> > > > ++  case 134:
> > > > ++    return "\\x86";
> > > > ++  case 135:
> > > > ++    return "\\x87";
> > > > ++  case 136:
> > > > ++    return "\\x88";
> > > > ++  case 137:
> > > > ++    return "\\x89";
> > > > ++  case 138:
> > > > ++    return "\\x8A";
> > > > ++  case 139:
> > > > ++    return "\\x8B";
> > > > ++  case 140:
> > > > ++    return "\\x8C";
> > > > ++  case 141:
> > > > ++    return "\\x8D";
> > > > ++  case 142:
> > > > ++    return "\\x8E";
> > > > ++  case 143:
> > > > ++    return "\\x8F";
> > > > ++  case 144:
> > > > ++    return "\\x90";
> > > > ++  case 145:
> > > > ++    return "\\x91";
> > > > ++  case 146:
> > > > ++    return "\\x92";
> > > > ++  case 147:
> > > > ++    return "\\x93";
> > > > ++  case 148:
> > > > ++    return "\\x94";
> > > > ++  case 149:
> > > > ++    return "\\x95";
> > > > ++  case 150:
> > > > ++    return "\\x96";
> > > > ++  case 151:
> > > > ++    return "\\x97";
> > > > ++  case 152:
> > > > ++    return "\\x98";
> > > > ++  case 153:
> > > > ++    return "\\x99";
> > > > ++  case 154:
> > > > ++    return "\\x9A";
> > > > ++  case 155:
> > > > ++    return "\\x9B";
> > > > ++  case 156:
> > > > ++    return "\\x9C";
> > > > ++  case 157:
> > > > ++    return "\\x9D";
> > > > ++  case 158:
> > > > ++    return "\\x9E";
> > > > ++  case 159:
> > > > ++    return "\\x9F";
> > > > ++  case 160:
> > > > ++    return "\\xA0";
> > > > ++  case 161:
> > > > ++    return "\\xA1";
> > > > ++  case 162:
> > > > ++    return "\\xA2";
> > > > ++  case 163:
> > > > ++    return "\\xA3";
> > > > ++  case 164:
> > > > ++    return "\\xA4";
> > > > ++  case 165:
> > > > ++    return "\\xA5";
> > > > ++  case 166:
> > > > ++    return "\\xA6";
> > > > ++  case 167:
> > > > ++    return "\\xA7";
> > > > ++  case 168:
> > > > ++    return "\\xA8";
> > > > ++  case 169:
> > > > ++    return "\\xA9";
> > > > ++  case 170:
> > > > ++    return "\\xAA";
> > > > ++  case 171:
> > > > ++    return "\\xAB";
> > > > ++  case 172:
> > > > ++    return "\\xAC";
> > > > ++  case 173:
> > > > ++    return "\\xAD";
> > > > ++  case 174:
> > > > ++    return "\\xAE";
> > > > ++  case 175:
> > > > ++    return "\\xAF";
> > > > ++  case 176:
> > > > ++    return "\\xB0";
> > > > ++  case 177:
> > > > ++    return "\\xB1";
> > > > ++  case 178:
> > > > ++    return "\\xB2";
> > > > ++  case 179:
> > > > ++    return "\\xB3";
> > > > ++  case 180:
> > > > ++    return "\\xB4";
> > > > ++  case 181:
> > > > ++    return "\\xB5";
> > > > ++  case 182:
> > > > ++    return "\\xB6";
> > > > ++  case 183:
> > > > ++    return "\\xB7";
> > > > ++  case 184:
> > > > ++    return "\\xB8";
> > > > ++  case 185:
> > > > ++    return "\\xB9";
> > > > ++  case 186:
> > > > ++    return "\\xBA";
> > > > ++  case 187:
> > > > ++    return "\\xBB";
> > > > ++  case 188:
> > > > ++    return "\\xBC";
> > > > ++  case 189:
> > > > ++    return "\\xBD";
> > > > ++  case 190:
> > > > ++    return "\\xBE";
> > > > ++  case 191:
> > > > ++    return "\\xBF";
> > > > ++  case 192:
> > > > ++    return "\\xC0";
> > > > ++  case 193:
> > > > ++    return "\\xC1";
> > > > ++  case 194:
> > > > ++    return "\\xC2";
> > > > ++  case 195:
> > > > ++    return "\\xC3";
> > > > ++  case 196:
> > > > ++    return "\\xC4";
> > > > ++  case 197:
> > > > ++    return "\\xC5";
> > > > ++  case 198:
> > > > ++    return "\\xC6";
> > > > ++  case 199:
> > > > ++    return "\\xC7";
> > > > ++  case 200:
> > > > ++    return "\\xC8";
> > > > ++  case 201:
> > > > ++    return "\\xC9";
> > > > ++  case 202:
> > > > ++    return "\\xCA";
> > > > ++  case 203:
> > > > ++    return "\\xCB";
> > > > ++  case 204:
> > > > ++    return "\\xCC";
> > > > ++  case 205:
> > > > ++    return "\\xCD";
> > > > ++  case 206:
> > > > ++    return "\\xCE";
> > > > ++  case 207:
> > > > ++    return "\\xCF";
> > > > ++  case 208:
> > > > ++    return "\\xD0";
> > > > ++  case 209:
> > > > ++    return "\\xD1";
> > > > ++  case 210:
> > > > ++    return "\\xD2";
> > > > ++  case 211:
> > > > ++    return "\\xD3";
> > > > ++  case 212:
> > > > ++    return "\\xD4";
> > > > ++  case 213:
> > > > ++    return "\\xD5";
> > > > ++  case 214:
> > > > ++    return "\\xD6";
> > > > ++  case 215:
> > > > ++    return "\\xD7";
> > > > ++  case 216:
> > > > ++    return "\\xD8";
> > > > ++  case 217:
> > > > ++    return "\\xD9";
> > > > ++  case 218:
> > > > ++    return "\\xDA";
> > > > ++  case 219:
> > > > ++    return "\\xDB";
> > > > ++  case 220:
> > > > ++    return "\\xDC";
> > > > ++  case 221:
> > > > ++    return "\\xDD";
> > > > ++  case 222:
> > > > ++    return "\\xDE";
> > > > ++  case 223:
> > > > ++    return "\\xDF";
> > > > ++  case 224:
> > > > ++    return "\\xE0";
> > > > ++  case 225:
> > > > ++    return "\\xE1";
> > > > ++  case 226:
> > > > ++    return "\\xE2";
> > > > ++  case 227:
> > > > ++    return "\\xE3";
> > > > ++  case 228:
> > > > ++    return "\\xE4";
> > > > ++  case 229:
> > > > ++    return "\\xE5";
> > > > ++  case 230:
> > > > ++    return "\\xE6";
> > > > ++  case 231:
> > > > ++    return "\\xE7";
> > > > ++  case 232:
> > > > ++    return "\\xE8";
> > > > ++  case 233:
> > > > ++    return "\\xE9";
> > > > ++  case 234:
> > > > ++    return "\\xEA";
> > > > ++  case 235:
> > > > ++    return "\\xEB";
> > > > ++  case 236:
> > > > ++    return "\\xEC";
> > > > ++  case 237:
> > > > ++    return "\\xED";
> > > > ++  case 238:
> > > > ++    return "\\xEE";
> > > > ++  case 239:
> > > > ++    return "\\xEF";
> > > > ++  case 240:
> > > > ++    return "\\xF0";
> > > > ++  case 241:
> > > > ++    return "\\xF1";
> > > > ++  case 242:
> > > > ++    return "\\xF2";
> > > > ++  case 243:
> > > > ++    return "\\xF3";
> > > > ++  case 244:
> > > > ++    return "\\xF4";
> > > > ++  case 245:
> > > > ++    return "\\xF5";
> > > > ++  case 246:
> > > > ++    return "\\xF6";
> > > > ++  case 247:
> > > > ++    return "\\xF7";
> > > > ++  case 248:
> > > > ++    return "\\xF8";
> > > > ++  case 249:
> > > > ++    return "\\xF9";
> > > > ++  case 250:
> > > > ++    return "\\xFA";
> > > > ++  case 251:
> > > > ++    return "\\xFB";
> > > > ++  case 252:
> > > > ++    return "\\xFC";
> > > > ++  case 253:
> > > > ++    return "\\xFD";
> > > > ++  case 254:
> > > > ++    return "\\xFE";
> > > > ++  case 255:
> > > > ++    return "\\xFF";
> > > > ++  default:
> > > > ++    assert(0); /* never gets here */
> > > > ++    return "dead code";
> > > > ++  }
> > > > ++  assert(0); /* never gets here */
> > > > ++}
> > > > ++
> > > > ++#endif /* XML_DTD */
> > > > ++
> > > > ++static unsigned long
> > > > ++getDebugLevel(const char *variableName, unsigned long
> > > > defaultDebugLevel) {
> > > > ++  const char *const valueOrNull = getenv(variableName);
> > > > ++  if (valueOrNull == NULL) {
> > > > ++    return defaultDebugLevel;
> > > > ++  }
> > > > ++  const char *const value = valueOrNull;
> > > > ++
> > > > ++  errno = 0;
> > > > ++  char *afterValue = (char *)value;
> > > > ++  unsigned long debugLevel = strtoul(value, &afterValue, 10);
> > > > ++  if ((errno != 0) || (afterValue[0] != '\0')) {
> > > > ++    errno = 0;
> > > > ++    return defaultDebugLevel;
> > > > ++  }
> > > > ++
> > > > ++  return debugLevel;
> > > > ++}
> > > > +--
> > > > +2.32.0
> > > > +
> > > > diff --git a/meta/recipes-core/expat/expat_2.2.9.bb
> > > > b/meta/recipes-
> > > > core/expat/expat_2.2.9.bb
> > > > index 8f3db41352..3af457b2af 100644
> > > > --- a/meta/recipes-core/expat/expat_2.2.9.bb
> > > > +++ b/meta/recipes-core/expat/expat_2.2.9.bb
> > > > @@ -6,8 +6,9 @@ LICENSE = "MIT"
> > > >
> > > >  LIC_FILES_CHKSUM =
> > > > "file://COPYING;md5=5b8620d98e49772d95fc1d291c26aa79"
> > > >
> > > > -SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}.tar.bz2 \
> > > > +SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}-RENAMED-
> > > > VULNERABLE-
> > > > PLEASE-USE-2.4.1-INSTEAD.tar.bz2 \
> > > >             file://libtool-tag.patch \
> > > > +
> > > > file://0001-expat-Backport-fix-for-CVE-2013-0340.patch \
> > > >           "
> > > >
> > > >  SRC_URI[md5sum] = "875a2c2ff3e8eb9e5a5cd62db2033ab5"
> > > >
> > > >
> > > >
> > > -----BEGIN PGP SIGNATURE-----
> > >
> > > iQEzBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKDygACgkQYgqew07V
> > > MNVpHAgAjxDiHJ+0Zl+xxBRKkD3E3bGlKlwsn4MOlP1HWN5zjComuAdnyQwvTmAj
> > > 2HRDxGUQ/ZnXUlSDbNzHSgrG2IDa1dlBWGRASRX3YxIXTJ1UL5LWHuprDL2P3xNp
> > > XMaAeX2a86gJKDBA7/XXkrbVuCafjGZ6r0+urvcqpJFO1FR1Qb0aklAe/pEVtEYS
> > > XcN2tWfqeOy9HBOvLIBfFwkRE07oBfr0eWxKzECOq1MPOUYr9k/E4LwqGEWcrOrq
> > > rJM2U07Esu0NkQQSPZXP+NTYO9v5ztZjCLzOb0eI7tGbduW3ay7fOlawfP8fgiON
> > > YVMOzcvA9DFOK7Z3ur3nCL7MWnN3OA==
> > > =JFZY
> > > -----END PGP SIGNATURE-----
> > >
> > >
> > >
> -----BEGIN PGP SIGNATURE-----
>
> iQEzBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKFcIACgkQYgqew07V
> MNU6Rgf/dePOk4Svf4RuduZErXPaVZS+RmQ7eeiirdeuBA5HwEorNRYc//gIAc2N
> Cz5vtjm2DIKDcQ3kBJPaF37kdACvHOLaC4rVgoGpLlCn6hs6RNFhMOPo6ZFbbbng
> wLN23bFSAaBfLjoM/0QgvIDnxqSQP/98xpRxIhEHq1buOZ1SKvaRdRHgn3Tpcu0H
> KQcgaM9ao13u57kFVxLHNzPJ10b0SYIFavRUtIsw7/Miz9xBeHHnKz1Ldm3eG2e4
> Ut+JlzBABOT3deviTeNSON42iwe+9L4k8sFcUK4FBoeecFfdb+znUcsT3/XkC5t3
> QrZGsUKhZcTmG1vkhU/8Xqu6B6SHdw==
> =P/nu
> -----END PGP SIGNATURE-----
>
> 
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
       [not found] <168917379DAE252D.8130@lists.openembedded.org>
  2021-06-16 14:48 ` [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340 Jasper Orschulko
@ 2021-06-16 18:19 ` Jasper Orschulko
       [not found] ` <168922F3778E5D40.4659@lists.openembedded.org>
  2 siblings, 0 replies; 11+ messages in thread
From: Jasper Orschulko @ 2021-06-16 18:19 UTC (permalink / raw)
  To: openembedded-core

expat < 4.0 is vulnerable to billion laughs attacks (see
[https://github.com/libexpat/libexpat/issues/34]). This patch backports
the commits b1d039607d3d8a042bf0466bfcc1c0f104e353c8
and 60959f2b491876199879d97c8ed956eabb0c2e73 from upstream.

Additionally, the SRC_URI had to be adjusted due to renaming of the
source archive

Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
---
 .../expat/expat/CVE-2013-0340.patch           | 1758 +++++++++++++++++
 .../expat/expat/libtool-tag.patch             |   41 +-
 meta/recipes-core/expat/expat_2.2.9.bb        |   10 +-
 3 files changed, 1783 insertions(+), 26 deletions(-)
 create mode 100644 meta/recipes-core/expat/expat/CVE-2013-0340.patch

diff --git a/meta/recipes-core/expat/expat/CVE-2013-0340.patch
b/meta/recipes-core/expat/expat/CVE-2013-0340.patch
new file mode 100644
index 0000000000..5ef749719d
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2013-0340.patch
@@ -0,0 +1,1758 @@
+From a644ccf25392523b1329872310e24d0fc5f40629 Mon Sep 17 00:00:00 2001
+From: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon, 19 Apr 2021 21:42:51 +0200
+Subject: [PATCH] expat: Backport fix for CVE-2013-0340
+
+Issue: https://github.com/libexpat/libexpat/issues/34
+
+This patch cherry-picks the following commits from upstream release
+2.4.0 onto 2.2.9:
+
+- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
+- 60959f2b491876199879d97c8ed956eabb0c2e73
+
+Upstream-Status: Backport
+CVE: CVE-2013-0340
+Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
+---
+ lib/expat.h       |   21 +-
+ lib/internal.h    |   30 +
+ lib/libexpat.def  |    3 +
+ lib/libexpatw.def |    3 +
+ lib/xmlparse.c    | 1147 +++++++++++++++++++++++++++++++++++++--
+ 5 files changed, 1143 insertions(+), 61 deletions(-)
+
+diff --git a/lib/expat.h b/lib/expat.h
+index 48a6e2a3..0fb70d9d 100644
+--- a/lib/expat.h
++++ b/lib/expat.h
+@@ -115,7 +115,9 @@ enum XML_Error {
+   XML_ERROR_RESERVED_PREFIX_XMLNS,
+   XML_ERROR_RESERVED_NAMESPACE_URI,
+   /* Added in 2.2.1. */
+-  XML_ERROR_INVALID_ARGUMENT
++  XML_ERROR_INVALID_ARGUMENT,
++  /* Added in 2.4.0. */
++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
+ };
+ 
+ enum XML_Content_Type {
+@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
+   XML_FEATURE_SIZEOF_XML_LCHAR,
+   XML_FEATURE_NS,
+   XML_FEATURE_LARGE_SIZE,
+-  XML_FEATURE_ATTR_INFO
++  XML_FEATURE_ATTR_INFO,
++  /* Added in Expat 2.4.0. */
++ 
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFA
ULT,
++ 
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAU
LT
+   /* Additional features must be added to the end of this enum. */
+ };
+ 
+@@ -1010,6 +1015,18 @@ typedef struct {
+ XMLPARSEAPI(const XML_Feature *)
+ XML_GetFeatureList(void);
+ 
++#ifdef XML_DTD
++/* Added in Expat 2.4.0. */
++XMLPARSEAPI(XML_Bool)
++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++    XML_Parser parser, float maximumAmplificationFactor);
++
++/* Added in Expat 2.4.0. */
++XMLPARSEAPI(XML_Bool)
++XML_SetBillionLaughsAttackProtectionActivationThreshold(
++    XML_Parser parser, unsigned long long activationThresholdBytes);
++#endif
++
+ /* Expat follows the semantic versioning convention.
+    See http://semver.org.
+ */
+diff --git a/lib/internal.h b/lib/internal.h
+index 60913dab..d8b31fa2 100644
+--- a/lib/internal.h
++++ b/lib/internal.h
+@@ -101,10 +101,40 @@
+ #  endif
+ #endif
+ 
++#include <limits.h> // ULONG_MAX
++
++#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
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
++#  else
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
++#  endif
++#else
++#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
++#  if ! defined(ULONG_MAX)
++#    error Compiler did not define ULONG_MAX for us
++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
++#  else
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
++#  endif
++#endif
++
+ #ifndef UNUSED_P
+ #  define UNUSED_P(p) (void)p
+ #endif
+ 
++/* NOTE BEGIN If you ever patch these defaults to greater values
++              for non-attack XML payload in your environment,
++              please file a bug report with libexpat.  Thank you!
++*/
++#define
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT  
\
++  100.0f
++#define
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT   
\
++  8388608 // 8 MiB, 2^23
++/* NOTE END */
++
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+diff --git a/lib/libexpat.def b/lib/libexpat.def
+index 16faf595..5aefa6df 100644
+--- a/lib/libexpat.def
++++ b/lib/libexpat.def
+@@ -76,3 +76,6 @@ EXPORTS
+   XML_SetHashSalt @67
+ ; added with version 2.2.5
+   _INTERNAL_trim_to_complete_utf8_characters @68
++; added with version 2.4.0
++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
+diff --git a/lib/libexpatw.def b/lib/libexpatw.def
+index 16faf595..5aefa6df 100644
+--- a/lib/libexpatw.def
++++ b/lib/libexpatw.def
+@@ -76,3 +76,6 @@ EXPORTS
+   XML_SetHashSalt @67
+ ; added with version 2.2.5
+   _INTERNAL_trim_to_complete_utf8_characters @68
++; added with version 2.4.0
++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
+diff --git a/lib/xmlparse.c b/lib/xmlparse.c
+index 3aaf35b9..6790bc28 100644
+--- a/lib/xmlparse.c
++++ b/lib/xmlparse.c
+@@ -47,6 +47,8 @@
+ #include <limits.h> /* UINT_MAX */
+ #include <stdio.h>  /* fprintf */
+ #include <stdlib.h> /* getenv, rand_s */
++#include <stdint.h> /* uintptr_t */
++#include <math.h>   /* isnan */
+ 
+ #ifdef _WIN32
+ #  define getpid GetCurrentProcessId
+@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
+   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+ } OPEN_INTERNAL_ENTITY;
+ 
++enum XML_Account {
++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the Expat
parser */
++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during
entity
++                                   expansion */
++  XML_ACCOUNT_NONE              /* i.e. do not account, was accounted
already */
++};
++
++#ifdef XML_DTD
++typedef unsigned long long XmlBigCount;
++typedef struct accounting {
++  XmlBigCount countBytesDirect;
++  XmlBigCount countBytesIndirect;
++  int debugLevel;
++  float maximumAmplificationFactor; // >=1.0
++  unsigned long long activationThresholdBytes;
++} ACCOUNTING;
++
++typedef struct entity_stats {
++  unsigned int countEverOpened;
++  unsigned int currentDepth;
++  unsigned int maximumDepthSeen;
++  int debugLevel;
++} ENTITY_STATS;
++#endif /* XML_DTD */
++
+ typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const
char *start,
+                                          const char *end, const char
**endPtr);
+ 
+@@ -403,16 +430,18 @@ static enum XML_Error
initializeEncoding(XML_Parser parser);
+ static enum XML_Error doProlog(XML_Parser parser, const ENCODING
*enc,
+                                const char *s, const char *end, int
tok,
+                                const char *next, const char
**nextPtr,
+-                               XML_Bool haveMore, XML_Bool
allowClosingDoctype);
++                               XML_Bool haveMore, XML_Bool
allowClosingDoctype,
++                               enum XML_Account account);
+ static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY
*entity,
+                                             XML_Bool betweenDecl);
+ static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
+                                 const ENCODING *enc, const char
*start,
+                                 const char *end, const char **endPtr,
+-                                XML_Bool haveMore);
++                                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,
+@@ -422,7 +451,8 @@ static enum XML_Error doIgnoreSection(XML_Parser
parser, const ENCODING *,
+ static void freeBindings(XML_Parser parser, BINDING *bindings);
+ static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
+                                 const char *s, TAG_NAME *tagNamePtr,
+-                                BINDING **bindingsPtr);
++                                BINDING **bindingsPtr,
++                                enum XML_Account account);
+ static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
+                                  const ATTRIBUTE_ID *attId, const
XML_Char *uri,
+                                  BINDING **bindingsPtr);
+@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE *type,
ATTRIBUTE_ID *, XML_Bool isCdata,
+                            XML_Parser parser);
+ static enum XML_Error storeAttributeValue(XML_Parser parser, const
ENCODING *,
+                                           XML_Bool isCdata, const
char *,
+-                                          const char *, STRING_POOL
*);
++                                          const char *, STRING_POOL
*,
++                                          enum XML_Account account);
+ static enum XML_Error appendAttributeValue(XML_Parser parser, const
ENCODING *,
+                                            XML_Bool isCdata, const
char *,
+-                                           const char *, STRING_POOL
*);
++                                           const char *, STRING_POOL
*,
++                                           enum XML_Account account);
+ static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING
*enc,
+                                     const char *start, const char
*end);
+ static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+ static enum XML_Error storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+-                                       const char *start, const char
*end);
++                                       const char *start, const char
*end,
++                                       enum XML_Account account);
+ static int reportProcessingInstruction(XML_Parser parser, const
ENCODING *enc,
+                                        const char *start, const char
*end);
+ static int reportComment(XML_Parser parser, const ENCODING *enc,
+@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const XML_Char
*encodingName,
+ 
+ static void parserInit(XML_Parser parser, const XML_Char
*encodingName);
+ 
++#ifdef XML_DTD
++static float accountingGetCurrentAmplification(XML_Parser
rootParser);
++static void accountingReportStats(XML_Parser originParser, const char
*epilog);
++static void accountingOnAbort(XML_Parser originParser);
++static void accountingReportDiff(XML_Parser rootParser,
++                                 unsigned int
levelsAwayFromRootParser,
++                                 const char *before, const char
*after,
++                                 ptrdiff_t bytesMore, int
source_line,
++                                 enum XML_Account account);
++static XML_Bool accountingDiffTolerated(XML_Parser originParser, int
tok,
++                                        const char *before, const
char *after,
++                                        int source_line,
++                                        enum XML_Account account);
++
++static void entityTrackingReportStats(XML_Parser parser, ENTITY
*entity,
++                                      const char *action, int
sourceLine);
++static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
++                                 int sourceLine);
++static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
++                                  int sourceLine);
++
++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,
++                                   unsigned long defaultDebugLevel);
++
+ #define poolStart(pool) ((pool)->start)
+ #define poolEnd(pool) ((pool)->ptr)
+ #define poolLength(pool) ((pool)->ptr - (pool)->start)
+@@ -616,6 +678,10 @@ struct XML_ParserStruct {
+   enum XML_ParamEntityParsing m_paramEntityParsing;
+ #endif
+   unsigned long m_hash_secret_salt;
++#ifdef XML_DTD
++  ACCOUNTING m_accounting;
++  ENTITY_STATS m_entity_stats;
++#endif
+ };
+ 
+ #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
+@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const XML_Char
*encodingName) {
+   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ #endif
+   parser->m_hash_secret_salt = 0;
++
++#ifdef XML_DTD
++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
++  parser->m_accounting.debugLevel =
getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
++  parser->m_accounting.maximumAmplificationFactor
++      =
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
++  parser->m_accounting.activationThresholdBytes
++      =
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
++
++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
++  parser->m_entity_stats.debugLevel =
getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
++#endif
+ }
+ 
+ /* moves list of bindings to m_freeBindingList */
+@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
+   /* Added in 2.2.5. */
+   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1,
already */
+     return XML_L("invalid argument");
++  /* Added in 2.4.0. */
++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
++    return XML_L(
++        "limit on input amplification factor (from DTD and entities)
breached");
+   }
+   return NULL;
+ }
+@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
+ 
+ const XML_Feature *XMLCALL
+ XML_GetFeatureList(void) {
+-  static const XML_Feature features[]
+-      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+-          sizeof(XML_Char)},
+-         {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+-          sizeof(XML_LChar)},
++  static const XML_Feature features[] = {
++      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
++       sizeof(XML_Char)},
++      {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
++       sizeof(XML_LChar)},
+ #ifdef XML_UNICODE
+-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+ #endif
+ #ifdef XML_UNICODE_WCHAR_T
+-         {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"),
0},
++      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+ #endif
+ #ifdef XML_DTD
+-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+ #endif
+ #ifdef XML_CONTEXT_BYTES
+-         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+-          XML_CONTEXT_BYTES},
++      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
++       XML_CONTEXT_BYTES},
+ #endif
+ #ifdef XML_MIN_SIZE
+-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+ #endif
+ #ifdef XML_NS
+-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+ #endif
+ #ifdef XML_LARGE_SIZE
+-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
++      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
+ #endif
+ #ifdef XML_ATTR_INFO
+-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
+ #endif
+-         {XML_FEATURE_END, NULL, 0}};
++#ifdef XML_DTD
++      /* Added in Expat 2.4.0. */
++     
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEF
AULT,
++       XML_L("XML_BLAP_MAX_AMP"),
++       (long int)
++          
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT},
++     
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFA
ULT,
++       XML_L("XML_BLAP_ACT_THRES"),
++      
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
++#endif
++      {XML_FEATURE_END, NULL, 0}};
+ 
+   return features;
+ }
+ 
++#ifdef XML_DTD
++XML_Bool XMLCALL
++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++    XML_Parser parser, float maximumAmplificationFactor) {
++  if ((parser == NULL) || (parser->m_parentParser != NULL)
++      || isnan(maximumAmplificationFactor)
++      || (maximumAmplificationFactor < 1.0f)) {
++    return XML_FALSE;
++  }
++  parser->m_accounting.maximumAmplificationFactor =
maximumAmplificationFactor;
++  return XML_TRUE;
++}
++
++XML_Bool XMLCALL
++XML_SetBillionLaughsAttackProtectionActivationThreshold(
++    XML_Parser parser, unsigned long long activationThresholdBytes) {
++  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
++    return XML_FALSE;
++  }
++  parser->m_accounting.activationThresholdBytes =
activationThresholdBytes;
++  return XML_TRUE;
++}
++#endif /* XML_DTD */
++
+ /* Initially tag->rawName always points into the parse buffer;
+    for those TAG instances opened while the current parse buffer was
+    processed, and not yet closed, we need to store tag->rawName in a
more
+@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
+ static enum XML_Error PTRCALL
+ contentProcessor(XML_Parser parser, const char *start, const char
*end,
+                  const char **endPtr) {
+-  enum XML_Error result
+-      = doContent(parser, 0, parser->m_encoding, start, end, endPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++  enum XML_Error result = doContent(
++      parser, 0, parser->m_encoding, start, end, endPtr,
++      (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_ACCOUNT_DIRECT);
+   if (result == XML_ERROR_NONE) {
+     if (! storeRawNames(parser))
+       return XML_ERROR_NO_MEMORY;
+@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser parser,
const char *start,
+   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
+   switch (tok) {
+   case XML_TOK_BOM:
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif /* XML_DTD */
++
+     /* If we are at the end of the buffer, this would cause the next
stage,
+        i.e. externalEntityInitProcessor3, to pass control directly to
+        doContent (by detecting XML_TOK_NONE) without processing any
xml text
+@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser parser,
const char *start,
+   const char *next = start; /* XmlContentTok doesn't always set the
last arg */
+   parser->m_eventPtr = start;
+   tok = XmlContentTok(parser->m_encoding, start, end, &next);
++  /* Note: These bytes are accounted later in:
++           - processXmlDecl
++           - externalEntityContentProcessor
++  */
+   parser->m_eventEndPtr = next;
+ 
+   switch (tok) {
+@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser
parser, const char *start,
+                                const char *end, const char **endPtr)
{
+   enum XML_Error result
+       = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
++                  XML_ACCOUNT_ENTITY_EXPANSION);
+   if (result == XML_ERROR_NONE) {
+     if (! storeRawNames(parser))
+       return XML_ERROR_NO_MEMORY;
+@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser
parser, const char *start,
+ static enum XML_Error
+ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+           const char *s, const char *end, const char **nextPtr,
+-          XML_Bool haveMore) {
++          XML_Bool haveMore, enum XML_Account account) {
+   /* save one level of indirection */
+   DTD *const dtd = parser->m_dtd;
+ 
+@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+   for (;;) {
+     const char *next = s; /* XmlContentTok doesn't always set the
last arg */
+     int tok = XmlContentTok(enc, s, end, &next);
++#ifdef XML_DTD
++    const char *accountAfter
++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok ==
XML_TOK_TRAILING_CR))
++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
++              : next;
++    if (! accountingDiffTolerated(parser, tok, s, accountAfter,
__LINE__,
++                                  account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     *eventEndPP = next;
+     switch (tok) {
+     case XML_TOK_TRAILING_CR:
+@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+           enc, s + enc->minBytesPerChar, next - enc-
>minBytesPerChar);
+       if (ch) {
++#ifdef XML_DTD
++        /* NOTE: We are replacing 4-6 characters original input for 1
character
++         *       so there is no amplification and hence recording
without
++         *       protection. */
++        accountingDiffTolerated(parser, tok, (char *)&ch,
++                                ((char *)&ch) + sizeof(XML_Char),
__LINE__,
++                                XML_ACCOUNT_ENTITY_EXPANSION);
++#endif /* XML_DTD */
+         if (parser->m_characterDataHandler)
+           parser->m_characterDataHandler(parser->m_handlerArg, &ch,
1);
+         else if (parser->m_defaultHandler)
+@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+       }
+       tag->name.str = (XML_Char *)tag->buf;
+       *toPtr = XML_T('\0');
+-      result = storeAtts(parser, enc, s, &(tag->name), &(tag-
>bindings));
++      result
++          = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings),
account);
+       if (result)
+         return result;
+       if (parser->m_startElementHandler)
+@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+       if (! name.str)
+         return XML_ERROR_NO_MEMORY;
+       poolFinish(&parser->m_tempPool);
+-      result = storeAtts(parser, enc, s, &name, &bindings);
++      result = storeAtts(parser, enc, s, &name, &bindings,
++                         XML_ACCOUNT_NONE /* token spans whole start
tag */);
+       if (result != XML_ERROR_NONE) {
+         freeBindings(parser, bindings);
+         return result;
+@@ -2907,7 +3057,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) {
+@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING
*bindings) {
+ */
+ static enum XML_Error
+ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
+-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
++          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
++          enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   ELEMENT_TYPE *elementType;
+   int nDefaultAtts;
+@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const ENCODING
*enc, const char *attStr,
+       /* normalize the attribute value */
+       result = storeAttributeValue(
+           parser, enc, isCdata, parser->m_atts[i].valuePtr,
+-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
++          parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
+       if (result)
+         return result;
+       appAtts[attIndex] = poolStart(&parser->m_tempPool);
+@@ -3535,9 +3687,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) {
+@@ -3557,7 +3709,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;
+@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const
ENCODING *enc, const char **startPtr,
+   for (;;) {
+     const char *next;
+     int tok = XmlCdataSectionTok(enc, s, end, &next);
++#ifdef XML_DTD
++    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) {
+     case XML_TOK_CDATA_SECT_CLOSE:
+@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const
ENCODING *enc, const char **startPtr,
+   *eventPP = s;
+   *startPtr = NULL;
+   tok = XmlIgnoreSectionTok(enc, s, end, &next);
++#  ifdef XML_DTD
++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                XML_ACCOUNT_DIRECT)) {
++    accountingOnAbort(parser);
++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++  }
++#  endif
+   *eventEndPP = next;
+   switch (tok) {
+   case XML_TOK_IGNORE_SECT:
+@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int
isGeneralTextEntity, const char *s,
+   const char *versionend;
+   const XML_Char *storedversion = NULL;
+   int standalone = -1;
++
++#ifdef XML_DTD
++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next,
__LINE__,
++                                XML_ACCOUNT_DIRECT)) {
++    accountingOnAbort(parser);
++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++  }
++#endif
++
+   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
+           isGeneralTextEntity, parser->m_encoding, s, next, &parser-
>m_eventPtr,
+           &version, &versionend, &encodingName, &newEncoding,
&standalone)) {
+@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser parser,
const char *s, const char *end,
+ 
+   for (;;) {
+     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
++    /* Note: Except for XML_TOK_BOM below, these bytes are accounted
later in:
++             - storeEntityValue
++             - processXmlDecl
++    */
+     parser->m_eventEndPtr = next;
+     if (tok <= 0) {
+       if (! parser->m_parsingStatus.finalBuffer && tok !=
XML_TOK_INVALID) {
+@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser parser,
const char *s, const char *end,
+         break;
+       }
+       /* found end of entity value - can store it now */
+-      return storeEntityValue(parser, parser->m_encoding, s, end);
++      return storeEntityValue(parser, parser->m_encoding, s, end,
++                              XML_ACCOUNT_DIRECT);
+     } else if (tok == XML_TOK_XML_DECL) {
+       enum XML_Error result;
+       result = processXmlDecl(parser, 0, start, next);
+@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser parser,
const char *s, const char *end,
+     */
+     else if (tok == XML_TOK_BOM && next == end
+              && ! parser->m_parsingStatus.finalBuffer) {
++#  ifdef XML_DTD
++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                    XML_ACCOUNT_DIRECT)) {
++        accountingOnAbort(parser);
++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      }
++#  endif
++
+       *nextPtr = next;
+       return XML_ERROR_NONE;
+     }
+@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser parser,
const char *s, const char *end,
+   }
+   /* This would cause the next stage, i.e. doProlog to be passed
XML_TOK_BOM.
+      However, when parsing an external subset, doProlog will not
accept a BOM
+-     as valid, and report a syntax error, so we have to skip the BOM
++     as valid, and report a syntax error, so we have to skip the BOM,
and
++     account for the BOM bytes.
+   */
+   else if (tok == XML_TOK_BOM) {
++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++
+     s = next;
+     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+   }
+ 
+   parser->m_processor = prologProcessor;
+   return doProlog(parser, parser->m_encoding, s, end, tok, next,
nextPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE,
++                  XML_ACCOUNT_DIRECT);
+ }
+ 
+ static enum XML_Error PTRCALL
+@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser, const
char *s, const char *end,
+ 
+   for (;;) {
+     tok = XmlPrologTok(enc, start, end, &next);
++    /* Note: These bytes are accounted later in:
++             - storeEntityValue
++    */
+     if (tok <= 0) {
+       if (! parser->m_parsingStatus.finalBuffer && tok !=
XML_TOK_INVALID) {
+         *nextPtr = s;
+@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser, const
char *s, const char *end,
+         break;
+       }
+       /* found end of entity value - can store it now */
+-      return storeEntityValue(parser, enc, s, end);
++      return storeEntityValue(parser, enc, s, end,
XML_ACCOUNT_DIRECT);
+     }
+     start = next;
+   }
+@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const char
*s, const char *end,
+   const char *next = s;
+   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+   return doProlog(parser, parser->m_encoding, s, end, tok, next,
nextPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE,
++                  XML_ACCOUNT_DIRECT);
+ }
+ 
+ static enum XML_Error
+ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const
char *end,
+          int tok, const char *next, const char **nextPtr, XML_Bool
haveMore,
+-         XML_Bool allowClosingDoctype) {
++         XML_Bool allowClosingDoctype, enum XML_Account account) {
+ #ifdef XML_DTD
+   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
+ #endif /* XML_DTD */
+@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const ENCODING
*enc, const char *s, const char *end,
+   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
+   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
+ 
++#ifndef XML_DTD
++  UNUSED_P(account);
++#endif
++
+   /* save one level of indirection */
+   DTD *const dtd = parser->m_dtd;
+ 
+@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const ENCODING
*enc, const char *s, const char *end,
+       }
+     }
+     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
++#ifdef XML_DTD
++    switch (role) {
++    case XML_ROLE_INSTANCE_START: // bytes accounted in
contentProcessor
++    case XML_ROLE_XML_DECL:       // bytes accounted in
processXmlDecl
++    case XML_ROLE_TEXT_DECL:      // bytes accounted in
processXmlDecl
++      break;
++    default:
++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
account)) {
++        accountingOnAbort(parser);
++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      }
++    }
++#endif
+     switch (role) {
+     case XML_ROLE_XML_DECL: {
+       enum XML_Error result = processXmlDecl(parser, 0, s, next);
+@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING *enc,
const char *s, const char *end,
+         const XML_Char *attVal;
+         enum XML_Error result = storeAttributeValue(
+             parser, enc, parser->m_declAttributeIsCdata,
+-            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
&dtd->pool);
++            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
&dtd->pool,
++            XML_ACCOUNT_NONE);
+         if (result)
+           return result;
+         attVal = poolStart(&dtd->pool);
+@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING *enc,
const char *s, const char *end,
+       break;
+     case XML_ROLE_ENTITY_VALUE:
+       if (dtd->keepProcessing) {
+-        enum XML_Error result = storeEntityValue(
+-            parser, enc, s + enc->minBytesPerChar, next - enc-
>minBytesPerChar);
++        enum XML_Error result
++            = storeEntityValue(parser, enc, s + enc->minBytesPerChar,
++                               next - enc->minBytesPerChar,
XML_ACCOUNT_NONE);
+         if (parser->m_declEntity) {
+           parser->m_declEntity->textPtr = poolStart(&dtd-
>entityValuePool);
+           parser->m_declEntity->textLen
+@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const ENCODING
*enc, const char *s, const char *end,
+         if (parser->m_externalEntityRefHandler) {
+           dtd->paramEntityRead = XML_FALSE;
+           entity->open = XML_TRUE;
++          entityTrackingOnOpen(parser, entity, __LINE__);
+           if (! parser->m_externalEntityRefHandler(
+                   parser->m_externalEntityRefHandlerArg, 0, entity-
>base,
+                   entity->systemId, entity->publicId)) {
++            entityTrackingOnClose(parser, entity, __LINE__);
+             entity->open = XML_FALSE;
+             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+           }
++          entityTrackingOnClose(parser, entity, __LINE__);
+           entity->open = XML_FALSE;
+           handleDefault = XML_FALSE;
+           if (! dtd->paramEntityRead) {
+@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const char
*s, const char *end,
+   for (;;) {
+     const char *next = NULL;
+     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     parser->m_eventEndPtr = next;
+     switch (tok) {
+     /* report partial linebreak - it might be the last token */
+@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser, ENTITY
*entity, XML_Bool betweenDecl) {
+       return XML_ERROR_NO_MEMORY;
+   }
+   entity->open = XML_TRUE;
++#ifdef XML_DTD
++  entityTrackingOnOpen(parser, entity, __LINE__);
++#endif
+   entity->processed = 0;
+   openEntity->next = parser->m_openInternalEntities;
+   parser->m_openInternalEntities = openEntity;
+@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser,
ENTITY *entity, XML_Bool betweenDecl) {
+     int tok
+         = XmlPrologTok(parser->m_internalEncoding, textStart,
textEnd, &next);
+     result = doProlog(parser, parser->m_internalEncoding, textStart,
textEnd,
+-                      tok, next, &next, XML_FALSE, XML_FALSE);
++                      tok, next, &next, XML_FALSE, XML_FALSE,
++                      XML_ACCOUNT_ENTITY_EXPANSION);
+   } else
+ #endif /* XML_DTD */
+     result = doContent(parser, parser->m_tagLevel, parser-
>m_internalEncoding,
+-                       textStart, textEnd, &next, XML_FALSE);
++                       textStart, textEnd, &next, XML_FALSE,
++                       XML_ACCOUNT_ENTITY_EXPANSION);
+ 
+   if (result == XML_ERROR_NONE) {
+     if (textEnd != next && parser->m_parsingStatus.parsing ==
XML_SUSPENDED) {
+       entity->processed = (int)(next - textStart);
+       parser->m_processor = internalEntityProcessor;
+     } else {
++#ifdef XML_DTD
++      entityTrackingOnClose(parser, entity, __LINE__);
++#endif /* XML_DTD */
+       entity->open = XML_FALSE;
+       parser->m_openInternalEntities = openEntity->next;
+       /* put openEntity back in list of free instances */
+@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser parser,
const char *s, const char *end,
+     int tok
+         = XmlPrologTok(parser->m_internalEncoding, textStart,
textEnd, &next);
+     result = doProlog(parser, parser->m_internalEncoding, textStart,
textEnd,
+-                      tok, next, &next, XML_FALSE, XML_TRUE);
++                      tok, next, &next, XML_FALSE, XML_TRUE,
++                      XML_ACCOUNT_ENTITY_EXPANSION);
+   } else
+ #endif /* XML_DTD */
+     result = doContent(parser, openEntity->startTagLevel,
+                        parser->m_internalEncoding, textStart,
textEnd, &next,
+-                       XML_FALSE);
++                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
+ 
+   if (result != XML_ERROR_NONE)
+     return result;
+@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser, const
char *s, const char *end,
+     entity->processed = (int)(next - (char *)entity->textPtr);
+     return result;
+   } else {
++#ifdef XML_DTD
++    entityTrackingOnClose(parser, entity, __LINE__);
++#endif
+     entity->open = XML_FALSE;
+     parser->m_openInternalEntities = openEntity->next;
+     /* put openEntity back in list of free instances */
+@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser, const
char *s, const char *end,
+     parser->m_processor = prologProcessor;
+     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+     return doProlog(parser, parser->m_encoding, s, end, tok, next,
nextPtr,
+-                    (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE);
++                    (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE,
++                    XML_ACCOUNT_DIRECT);
+   } else
+ #endif /* XML_DTD */
+   {
+@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser, const
char *s, const char *end,
+     /* see externalEntityContentProcessor vs contentProcessor */
+     return doContent(parser, parser->m_parentParser ? 1 : 0, parser-
>m_encoding,
+                      s, end, nextPtr,
+-                     (XML_Bool)! parser-
>m_parsingStatus.finalBuffer);
++                     (XML_Bool)! parser->m_parsingStatus.finalBuffer,
++                     XML_ACCOUNT_DIRECT);
+   }
+ }
+ 
+@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const char
*s, const char *end,
+ 
+ static enum XML_Error
+ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool
isCdata,
+-                    const char *ptr, const char *end, STRING_POOL
*pool) {
++                    const char *ptr, const char *end, STRING_POOL
*pool,
++                    enum XML_Account account) {
+   enum XML_Error result
+-      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
++      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool,
account);
+   if (result)
+     return result;
+   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+ 
+ static enum XML_Error
+ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool
isCdata,
+-                     const char *ptr, const char *end, STRING_POOL
*pool) {
++                     const char *ptr, const char *end, STRING_POOL
*pool,
++                     enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
++#ifndef XML_DTD
++  UNUSED_P(account);
++#endif
++
+   for (;;) {
+     const char *next;
+     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__,
account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     switch (tok) {
+     case XML_TOK_NONE:
+       return XML_ERROR_NONE;
+@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+           enc, ptr + enc->minBytesPerChar, next - enc-
>minBytesPerChar);
+       if (ch) {
++#ifdef XML_DTD
++        /* NOTE: We are replacing 4-6 characters original input for 1
character
++         *       so there is no amplification and hence recording
without
++         *       protection. */
++        accountingDiffTolerated(parser, tok, (char *)&ch,
++                                ((char *)&ch) + sizeof(XML_Char),
__LINE__,
++                                XML_ACCOUNT_ENTITY_EXPANSION);
++#endif /* XML_DTD */
+         if (! poolAppendChar(pool, ch))
+           return XML_ERROR_NO_MEMORY;
+         break;
+@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+         enum XML_Error result;
+         const XML_Char *textEnd = entity->textPtr + entity->textLen;
+         entity->open = XML_TRUE;
++#ifdef XML_DTD
++        entityTrackingOnOpen(parser, entity, __LINE__);
++#endif
+         result = appendAttributeValue(parser, parser-
>m_internalEncoding,
+-                                      isCdata, (char *)entity-
>textPtr,
+-                                      (char *)textEnd, pool);
++                                      isCdata, (const char *)entity-
>textPtr,
++                                      (const char *)textEnd, pool,
++                                      XML_ACCOUNT_ENTITY_EXPANSION);
++#ifdef XML_DTD
++        entityTrackingOnClose(parser, entity, __LINE__);
++#endif
+         entity->open = XML_FALSE;
+         if (result)
+           return result;
+@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+ 
+ static enum XML_Error
+ storeEntityValue(XML_Parser parser, const ENCODING *enc,
+-                 const char *entityTextPtr, const char
*entityTextEnd) {
++                 const char *entityTextPtr, const char
*entityTextEnd,
++                 enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   STRING_POOL *pool = &(dtd->entityValuePool);
+   enum XML_Error result = XML_ERROR_NONE;
+ #ifdef XML_DTD
+   int oldInEntityValue = parser->m_prologState.inEntityValue;
+   parser->m_prologState.inEntityValue = 1;
++#else
++  UNUSED_P(account);
+ #endif /* XML_DTD */
+   /* never return Null for the value argument in EntityDeclHandler,
+      since this would indicate an external entity; therefore we
+@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+   for (;;) {
+     const char *next;
+     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd,
&next);
++
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, entityTextPtr, next,
__LINE__,
++                                  account)) {
++      accountingOnAbort(parser);
++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      goto endEntityValue;
++    }
++#endif
++
+     switch (tok) {
+     case XML_TOK_PARAM_ENTITY_REF:
+ #ifdef XML_DTD
+@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+           if (parser->m_externalEntityRefHandler) {
+             dtd->paramEntityRead = XML_FALSE;
+             entity->open = XML_TRUE;
++            entityTrackingOnOpen(parser, entity, __LINE__);
+             if (! parser->m_externalEntityRefHandler(
+                     parser->m_externalEntityRefHandlerArg, 0, entity-
>base,
+                     entity->systemId, entity->publicId)) {
++              entityTrackingOnClose(parser, entity, __LINE__);
+               entity->open = XML_FALSE;
+               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+               goto endEntityValue;
+             }
++            entityTrackingOnClose(parser, entity, __LINE__);
+             entity->open = XML_FALSE;
+             if (! dtd->paramEntityRead)
+               dtd->keepProcessing = dtd->standalone;
+@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+             dtd->keepProcessing = dtd->standalone;
+         } else {
+           entity->open = XML_TRUE;
++          entityTrackingOnOpen(parser, entity, __LINE__);
+           result = storeEntityValue(
+-              parser, parser->m_internalEncoding, (char *)entity-
>textPtr,
+-              (char *)(entity->textPtr + entity->textLen));
++              parser, parser->m_internalEncoding, (const char
*)entity->textPtr,
++              (const char *)(entity->textPtr + entity->textLen),
++              XML_ACCOUNT_ENTITY_EXPANSION);
++          entityTrackingOnClose(parser, entity, __LINE__);
+           entity->open = XML_FALSE;
+           if (result)
+             goto endEntityValue;
+@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const
XML_Memory_Handling_Suite *memsuite) {
+   memcpy(result, s, charsRequired * sizeof(XML_Char));
+   return result;
+ }
++
++#ifdef XML_DTD
++
++static float
++accountingGetCurrentAmplification(XML_Parser rootParser) {
++  const XmlBigCount countBytesOutput
++      = rootParser->m_accounting.countBytesDirect
++        + rootParser->m_accounting.countBytesIndirect;
++  const float amplificationFactor
++      = rootParser->m_accounting.countBytesDirect
++            ? (countBytesOutput
++               / (float)(rootParser->m_accounting.countBytesDirect))
++            : 1.0f;
++  assert(! rootParser->m_parentParser);
++  return amplificationFactor;
++}
++
++static void
++accountingReportStats(XML_Parser originParser, const char *epilog) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  if (rootParser->m_accounting.debugLevel < 1) {
++    return;
++  }
++
++  const float amplificationFactor
++      = accountingGetCurrentAmplification(rootParser);
++  fprintf(stderr,
++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
++              "10") ", indirect " EXPAT_FMT_ULL("10") ",
amplification %8.2f%s",
++          (void *)rootParser, rootParser-
>m_accounting.countBytesDirect,
++          rootParser->m_accounting.countBytesIndirect,
++          (double)amplificationFactor, epilog);
++}
++
++static void
++accountingOnAbort(XML_Parser originParser) {
++  accountingReportStats(originParser, " ABORTING\n");
++}
++
++static void
++accountingReportDiff(XML_Parser rootParser,
++                     unsigned int levelsAwayFromRootParser, const
char *before,
++                     const char *after, ptrdiff_t bytesMore, int
source_line,
++                     enum XML_Account account) {
++  assert(! rootParser->m_parentParser);
++
++  fprintf(stderr,
++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d,
xmlparse.c:%d) %*s\"",
++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
++          levelsAwayFromRootParser, source_line, 10, "");
++
++  const char ellipis[] = "[..]";
++  const size_t ellipsisLength = sizeof(ellipis) /* because compile-
time */ - 1;
++  const unsigned int contextLength = 10;
++
++  /* Note: Performance is of no concern here */
++  const char *walker = before;
++  if ((rootParser->m_accounting.debugLevel >= 3)
++      || (after - before)
++             <= (ptrdiff_t)(contextLength + ellipsisLength +
contextLength)) {
++    for (; walker < after; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++  } else {
++    for (; walker < before + contextLength; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++    fprintf(stderr, ellipis);
++    walker = after - contextLength;
++    for (; walker < after; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++  }
++  fprintf(stderr, "\"\n");
++}
++
++static XML_Bool
++accountingDiffTolerated(XML_Parser originParser, int tok, const char
*before,
++                        const char *after, int source_line,
++                        enum XML_Account account) {
++  /* Note: We need to check the token type *first* to be sure that
++   *       we can even access variable <after>, safely.
++   *       E.g. for XML_TOK_NONE <after> may hold an invalid pointer.
*/
++  switch (tok) {
++  case XML_TOK_INVALID:
++  case XML_TOK_PARTIAL:
++  case XML_TOK_PARTIAL_CHAR:
++  case XML_TOK_NONE:
++    return XML_TRUE;
++  }
++
++  if (account == XML_ACCOUNT_NONE)
++    return XML_TRUE; /* because these bytes have been accounted for,
already */
++
++  unsigned int levelsAwayFromRootParser;
++  const XML_Parser rootParser
++      = getRootParserOf(originParser, &levelsAwayFromRootParser);
++  assert(! rootParser->m_parentParser);
++
++  const int isDirect
++      = (account == XML_ACCOUNT_DIRECT) && (originParser ==
rootParser);
++  const ptrdiff_t bytesMore = after - before;
++
++  XmlBigCount *const additionTarget
++      = isDirect ? &rootParser->m_accounting.countBytesDirect
++                 : &rootParser->m_accounting.countBytesIndirect;
++
++  /* Detect and avoid integer overflow */
++  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
++    return XML_FALSE;
++  *additionTarget += bytesMore;
++
++  const XmlBigCount countBytesOutput
++      = rootParser->m_accounting.countBytesDirect
++        + rootParser->m_accounting.countBytesIndirect;
++  const float amplificationFactor
++      = accountingGetCurrentAmplification(rootParser);
++  const XML_Bool tolerated
++      = (countBytesOutput < rootParser-
>m_accounting.activationThresholdBytes)
++        || (amplificationFactor
++            <= rootParser->m_accounting.maximumAmplificationFactor);
++
++  if (rootParser->m_accounting.debugLevel >= 2) {
++    accountingReportStats(rootParser, "");
++    accountingReportDiff(rootParser, levelsAwayFromRootParser,
before, after,
++                         bytesMore, source_line, account);
++  }
++
++  return tolerated;
++}
++
++static void
++entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
++                          const char *action, int sourceLine) {
++  assert(! rootParser->m_parentParser);
++  if (rootParser->m_entity_stats.debugLevel < 1)
++    return;
++
++#  if defined(XML_UNICODE)
++  const char *const entityName = "[..]";
++#  else
++  const char *const entityName = entity->name;
++#  endif
++
++  fprintf(
++      stderr,
++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s
length %d (xmlparse.c:%d)\n",
++      (void *)rootParser, rootParser->m_entity_stats.countEverOpened,
++      rootParser->m_entity_stats.currentDepth,
++      rootParser->m_entity_stats.maximumDepthSeen,
++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
++      entity->is_param ? "%" : "&", entityName, action, entity-
>textLen,
++      sourceLine);
++}
++
++static void
++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int
sourceLine) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  rootParser->m_entity_stats.countEverOpened++;
++  rootParser->m_entity_stats.currentDepth++;
++  if (rootParser->m_entity_stats.currentDepth
++      > rootParser->m_entity_stats.maximumDepthSeen) {
++    rootParser->m_entity_stats.maximumDepthSeen++;
++  }
++
++  entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine);
++}
++
++static void
++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int
sourceLine) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine);
++  rootParser->m_entity_stats.currentDepth--;
++}
++
++static XML_Parser
++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
++  XML_Parser rootParser = parser;
++  unsigned int stepsTakenUpwards = 0;
++  while (rootParser->m_parentParser) {
++    rootParser = rootParser->m_parentParser;
++    stepsTakenUpwards++;
++  }
++  assert(! rootParser->m_parentParser);
++  if (outLevelDiff != NULL) {
++    *outLevelDiff = stepsTakenUpwards;
++  }
++  return rootParser;
++}
++
++static const char *
++unsignedCharToPrintable(unsigned char c) {
++  switch (c) {
++  case 0:
++    return "\\0";
++  case 1:
++    return "\\x1";
++  case 2:
++    return "\\x2";
++  case 3:
++    return "\\x3";
++  case 4:
++    return "\\x4";
++  case 5:
++    return "\\x5";
++  case 6:
++    return "\\x6";
++  case 7:
++    return "\\x7";
++  case 8:
++    return "\\x8";
++  case 9:
++    return "\\t";
++  case 10:
++    return "\\n";
++  case 11:
++    return "\\xB";
++  case 12:
++    return "\\xC";
++  case 13:
++    return "\\r";
++  case 14:
++    return "\\xE";
++  case 15:
++    return "\\xF";
++  case 16:
++    return "\\x10";
++  case 17:
++    return "\\x11";
++  case 18:
++    return "\\x12";
++  case 19:
++    return "\\x13";
++  case 20:
++    return "\\x14";
++  case 21:
++    return "\\x15";
++  case 22:
++    return "\\x16";
++  case 23:
++    return "\\x17";
++  case 24:
++    return "\\x18";
++  case 25:
++    return "\\x19";
++  case 26:
++    return "\\x1A";
++  case 27:
++    return "\\x1B";
++  case 28:
++    return "\\x1C";
++  case 29:
++    return "\\x1D";
++  case 30:
++    return "\\x1E";
++  case 31:
++    return "\\x1F";
++  case 32:
++    return " ";
++  case 33:
++    return "!";
++  case 34:
++    return "\\\"";
++  case 35:
++    return "#";
++  case 36:
++    return "$";
++  case 37:
++    return "%";
++  case 38:
++    return "&";
++  case 39:
++    return "'";
++  case 40:
++    return "(";
++  case 41:
++    return ")";
++  case 42:
++    return "*";
++  case 43:
++    return "+";
++  case 44:
++    return ",";
++  case 45:
++    return "-";
++  case 46:
++    return ".";
++  case 47:
++    return "/";
++  case 48:
++    return "0";
++  case 49:
++    return "1";
++  case 50:
++    return "2";
++  case 51:
++    return "3";
++  case 52:
++    return "4";
++  case 53:
++    return "5";
++  case 54:
++    return "6";
++  case 55:
++    return "7";
++  case 56:
++    return "8";
++  case 57:
++    return "9";
++  case 58:
++    return ":";
++  case 59:
++    return ";";
++  case 60:
++    return "<";
++  case 61:
++    return "=";
++  case 62:
++    return ">";
++  case 63:
++    return "?";
++  case 64:
++    return "@";
++  case 65:
++    return "A";
++  case 66:
++    return "B";
++  case 67:
++    return "C";
++  case 68:
++    return "D";
++  case 69:
++    return "E";
++  case 70:
++    return "F";
++  case 71:
++    return "G";
++  case 72:
++    return "H";
++  case 73:
++    return "I";
++  case 74:
++    return "J";
++  case 75:
++    return "K";
++  case 76:
++    return "L";
++  case 77:
++    return "M";
++  case 78:
++    return "N";
++  case 79:
++    return "O";
++  case 80:
++    return "P";
++  case 81:
++    return "Q";
++  case 82:
++    return "R";
++  case 83:
++    return "S";
++  case 84:
++    return "T";
++  case 85:
++    return "U";
++  case 86:
++    return "V";
++  case 87:
++    return "W";
++  case 88:
++    return "X";
++  case 89:
++    return "Y";
++  case 90:
++    return "Z";
++  case 91:
++    return "[";
++  case 92:
++    return "\\\\";
++  case 93:
++    return "]";
++  case 94:
++    return "^";
++  case 95:
++    return "_";
++  case 96:
++    return "`";
++  case 97:
++    return "a";
++  case 98:
++    return "b";
++  case 99:
++    return "c";
++  case 100:
++    return "d";
++  case 101:
++    return "e";
++  case 102:
++    return "f";
++  case 103:
++    return "g";
++  case 104:
++    return "h";
++  case 105:
++    return "i";
++  case 106:
++    return "j";
++  case 107:
++    return "k";
++  case 108:
++    return "l";
++  case 109:
++    return "m";
++  case 110:
++    return "n";
++  case 111:
++    return "o";
++  case 112:
++    return "p";
++  case 113:
++    return "q";
++  case 114:
++    return "r";
++  case 115:
++    return "s";
++  case 116:
++    return "t";
++  case 117:
++    return "u";
++  case 118:
++    return "v";
++  case 119:
++    return "w";
++  case 120:
++    return "x";
++  case 121:
++    return "y";
++  case 122:
++    return "z";
++  case 123:
++    return "{";
++  case 124:
++    return "|";
++  case 125:
++    return "}";
++  case 126:
++    return "~";
++  case 127:
++    return "\\x7F";
++  case 128:
++    return "\\x80";
++  case 129:
++    return "\\x81";
++  case 130:
++    return "\\x82";
++  case 131:
++    return "\\x83";
++  case 132:
++    return "\\x84";
++  case 133:
++    return "\\x85";
++  case 134:
++    return "\\x86";
++  case 135:
++    return "\\x87";
++  case 136:
++    return "\\x88";
++  case 137:
++    return "\\x89";
++  case 138:
++    return "\\x8A";
++  case 139:
++    return "\\x8B";
++  case 140:
++    return "\\x8C";
++  case 141:
++    return "\\x8D";
++  case 142:
++    return "\\x8E";
++  case 143:
++    return "\\x8F";
++  case 144:
++    return "\\x90";
++  case 145:
++    return "\\x91";
++  case 146:
++    return "\\x92";
++  case 147:
++    return "\\x93";
++  case 148:
++    return "\\x94";
++  case 149:
++    return "\\x95";
++  case 150:
++    return "\\x96";
++  case 151:
++    return "\\x97";
++  case 152:
++    return "\\x98";
++  case 153:
++    return "\\x99";
++  case 154:
++    return "\\x9A";
++  case 155:
++    return "\\x9B";
++  case 156:
++    return "\\x9C";
++  case 157:
++    return "\\x9D";
++  case 158:
++    return "\\x9E";
++  case 159:
++    return "\\x9F";
++  case 160:
++    return "\\xA0";
++  case 161:
++    return "\\xA1";
++  case 162:
++    return "\\xA2";
++  case 163:
++    return "\\xA3";
++  case 164:
++    return "\\xA4";
++  case 165:
++    return "\\xA5";
++  case 166:
++    return "\\xA6";
++  case 167:
++    return "\\xA7";
++  case 168:
++    return "\\xA8";
++  case 169:
++    return "\\xA9";
++  case 170:
++    return "\\xAA";
++  case 171:
++    return "\\xAB";
++  case 172:
++    return "\\xAC";
++  case 173:
++    return "\\xAD";
++  case 174:
++    return "\\xAE";
++  case 175:
++    return "\\xAF";
++  case 176:
++    return "\\xB0";
++  case 177:
++    return "\\xB1";
++  case 178:
++    return "\\xB2";
++  case 179:
++    return "\\xB3";
++  case 180:
++    return "\\xB4";
++  case 181:
++    return "\\xB5";
++  case 182:
++    return "\\xB6";
++  case 183:
++    return "\\xB7";
++  case 184:
++    return "\\xB8";
++  case 185:
++    return "\\xB9";
++  case 186:
++    return "\\xBA";
++  case 187:
++    return "\\xBB";
++  case 188:
++    return "\\xBC";
++  case 189:
++    return "\\xBD";
++  case 190:
++    return "\\xBE";
++  case 191:
++    return "\\xBF";
++  case 192:
++    return "\\xC0";
++  case 193:
++    return "\\xC1";
++  case 194:
++    return "\\xC2";
++  case 195:
++    return "\\xC3";
++  case 196:
++    return "\\xC4";
++  case 197:
++    return "\\xC5";
++  case 198:
++    return "\\xC6";
++  case 199:
++    return "\\xC7";
++  case 200:
++    return "\\xC8";
++  case 201:
++    return "\\xC9";
++  case 202:
++    return "\\xCA";
++  case 203:
++    return "\\xCB";
++  case 204:
++    return "\\xCC";
++  case 205:
++    return "\\xCD";
++  case 206:
++    return "\\xCE";
++  case 207:
++    return "\\xCF";
++  case 208:
++    return "\\xD0";
++  case 209:
++    return "\\xD1";
++  case 210:
++    return "\\xD2";
++  case 211:
++    return "\\xD3";
++  case 212:
++    return "\\xD4";
++  case 213:
++    return "\\xD5";
++  case 214:
++    return "\\xD6";
++  case 215:
++    return "\\xD7";
++  case 216:
++    return "\\xD8";
++  case 217:
++    return "\\xD9";
++  case 218:
++    return "\\xDA";
++  case 219:
++    return "\\xDB";
++  case 220:
++    return "\\xDC";
++  case 221:
++    return "\\xDD";
++  case 222:
++    return "\\xDE";
++  case 223:
++    return "\\xDF";
++  case 224:
++    return "\\xE0";
++  case 225:
++    return "\\xE1";
++  case 226:
++    return "\\xE2";
++  case 227:
++    return "\\xE3";
++  case 228:
++    return "\\xE4";
++  case 229:
++    return "\\xE5";
++  case 230:
++    return "\\xE6";
++  case 231:
++    return "\\xE7";
++  case 232:
++    return "\\xE8";
++  case 233:
++    return "\\xE9";
++  case 234:
++    return "\\xEA";
++  case 235:
++    return "\\xEB";
++  case 236:
++    return "\\xEC";
++  case 237:
++    return "\\xED";
++  case 238:
++    return "\\xEE";
++  case 239:
++    return "\\xEF";
++  case 240:
++    return "\\xF0";
++  case 241:
++    return "\\xF1";
++  case 242:
++    return "\\xF2";
++  case 243:
++    return "\\xF3";
++  case 244:
++    return "\\xF4";
++  case 245:
++    return "\\xF5";
++  case 246:
++    return "\\xF6";
++  case 247:
++    return "\\xF7";
++  case 248:
++    return "\\xF8";
++  case 249:
++    return "\\xF9";
++  case 250:
++    return "\\xFA";
++  case 251:
++    return "\\xFB";
++  case 252:
++    return "\\xFC";
++  case 253:
++    return "\\xFD";
++  case 254:
++    return "\\xFE";
++  case 255:
++    return "\\xFF";
++  default:
++    assert(0); /* never gets here */
++    return "dead code";
++  }
++  assert(0); /* never gets here */
++}
++
++#endif /* XML_DTD */
++
++static unsigned long
++getDebugLevel(const char *variableName, unsigned long
defaultDebugLevel) {
++  const char *const valueOrNull = getenv(variableName);
++  if (valueOrNull == NULL) {
++    return defaultDebugLevel;
++  }
++  const char *const value = valueOrNull;
++
++  errno = 0;
++  char *afterValue = (char *)value;
++  unsigned long debugLevel = strtoul(value, &afterValue, 10);
++  if ((errno != 0) || (afterValue[0] != '\0')) {
++    errno = 0;
++    return defaultDebugLevel;
++  }
++
++  return debugLevel;
++}
+-- 
+2.32.0
+
diff --git a/meta/recipes-core/expat/expat/libtool-tag.patch
b/meta/recipes-core/expat/expat/libtool-tag.patch
index 0a0aed23e5..203415a725 100644
--- a/meta/recipes-core/expat/expat/libtool-tag.patch
+++ b/meta/recipes-core/expat/expat/libtool-tag.patch
@@ -1,30 +1,27 @@
-From 10342e6b600858b091bc7771e454d9e06af06410 Mon Sep 17 00:00:00 2001
-From: Khem Raj <raj.khem@gmail.com>
-Date: Thu, 2 Nov 2017 18:20:57 +0800
+From da433dbe79f2d4d5d7d79869c669594c99c5de9c Mon Sep 17 00:00:00 2001
+From: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
+Date: Wed, 16 Jun 2021 19:00:30 +0200
 Subject: [PATCH] Add CC tag to build
 
-Add CC tag to build
-
 Upstream-Status: Pending
-Signed-off-by: Khem Raj <raj.khem@gmail.com>
-Signed-off-by: Dengke Du <dengke.du@windriver.com>
+Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
 ---
- Makefile.in | 2 +-
+ Makefile.am | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
-diff --git a/Makefile.in b/Makefile.in
-index 9560a95..d444bd6 100644
---- a/Makefile.in
-+++ b/Makefile.in
-@@ -319,7 +319,7 @@ LIBCURRENT = @LIBCURRENT@
- LIBOBJS = @LIBOBJS@
- LIBREVISION = @LIBREVISION@
- LIBS = @LIBS@
--LIBTOOL = @LIBTOOL@
-+LIBTOOL = @LIBTOOL@ --tag CC
- LIPO = @LIPO@
- LN_S = @LN_S@
- LTLIBOBJS = @LTLIBOBJS@
+diff --git a/Makefile.am b/Makefile.am
+index 5e1d37dd..f7a6dece 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -36,7 +36,7 @@ AUTOMAKE_OPTIONS = \
+     subdir-objects
+ 
+ ACLOCAL_AMFLAGS = -I m4
+-LIBTOOLFLAGS = --verbose
++LIBTOOLFLAGS = --verbose --tag=CC
+ 
+ SUBDIRS = lib # lib goes first to build first
+ if WITH_EXAMPLES
 -- 
-2.7.4
+2.32.0
 
diff --git a/meta/recipes-core/expat/expat_2.2.9.bb b/meta/recipes-
core/expat/expat_2.2.9.bb
index 8f3db41352..c4b51265ac 100644
--- a/meta/recipes-core/expat/expat_2.2.9.bb
+++ b/meta/recipes-core/expat/expat_2.2.9.bb
@@ -6,17 +6,19 @@ LICENSE = "MIT"
 
 LIC_FILES_CHKSUM =
"file://COPYING;md5=5b8620d98e49772d95fc1d291c26aa79"
 
-SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}.tar.bz2 \
+SRC_URI = "git://github.com/libexpat/libexpat.git;protocol=https \
+           file://CVE-2013-0340.patch \
            file://libtool-tag.patch \
 	  "
 
-SRC_URI[md5sum] = "875a2c2ff3e8eb9e5a5cd62db2033ab5"
-SRC_URI[sha256sum] =
"f1063084dc4302a427dabcca499c8312b3a32a29b7d2506653ecc8f950a9a237"
+SRCREV = "a7bc26b69768f7fb24f0c7976fae24b157b85b13"
+
+S = "${WORKDIR}/git/expat"
 
 inherit autotools lib_package
 
 do_configure_prepend () {
-	rm -f ${S}/conftools/libtool.m4
+	rm -f ${S}/expat/conftools/libtool.m4
 }
 
 BBCLASSEXTEND = "native nativesdk"
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
       [not found] ` <168922F3778E5D40.4659@lists.openembedded.org>
@ 2021-06-16 18:21   ` Jasper Orschulko
  2021-06-16 21:14     ` Jasper Orschulko
  0 siblings, 1 reply; 11+ messages in thread
From: Jasper Orschulko @ 2021-06-16 18:21 UTC (permalink / raw)
  To: openembedded-core, steve

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Revision of the the patch file. Please verify. :)

- -- 
With best regards

Jasper Orschulko
DevOps Engineer

Tel. +49 30 58 58 14 265
Fax +49 30 58 58 14 999
Jasper.Orschulko@iris-sensing.com

• • • • • • • • • • • • • • • • • • • • • • • • • •

iris-GmbH
infrared & intelligent sensors
Ostendstraße 1-14 | 12459 Berlin

https://iris-sensing.com/




On Wed, 2021-06-16 at 18:19 +0000, Jasper Orschulko wrote:
> expat < 4.0 is vulnerable to billion laughs attacks (see
> [https://github.com/libexpat/libexpat/issues/34]). This patch
> backports
> the commits b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> and 60959f2b491876199879d97c8ed956eabb0c2e73 from upstream.
> 
> Additionally, the SRC_URI had to be adjusted due to renaming of the
> source archive
> 
> Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
> ---
>  .../expat/expat/CVE-2013-0340.patch           | 1758
> +++++++++++++++++
>  .../expat/expat/libtool-tag.patch             |   41 +-
>  meta/recipes-core/expat/expat_2.2.9.bb        |   10 +-
>  3 files changed, 1783 insertions(+), 26 deletions(-)
>  create mode 100644 meta/recipes-core/expat/expat/CVE-2013-0340.patch
> 
> diff --git a/meta/recipes-core/expat/expat/CVE-2013-0340.patch
> b/meta/recipes-core/expat/expat/CVE-2013-0340.patch
> new file mode 100644
> index 0000000000..5ef749719d
> --- /dev/null
> +++ b/meta/recipes-core/expat/expat/CVE-2013-0340.patch
> @@ -0,0 +1,1758 @@
> +From a644ccf25392523b1329872310e24d0fc5f40629 Mon Sep 17 00:00:00
> 2001
> +From: Sebastian Pipping <sebastian@pipping.org>
> +Date: Mon, 19 Apr 2021 21:42:51 +0200
> +Subject: [PATCH] expat: Backport fix for CVE-2013-0340
> +
> +Issue: https://github.com/libexpat/libexpat/issues/34
> +
> +This patch cherry-picks the following commits from upstream release
> +2.4.0 onto 2.2.9:
> +
> +- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
> +- 60959f2b491876199879d97c8ed956eabb0c2e73
> +
> +Upstream-Status: Backport
> +CVE: CVE-2013-0340
> +Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
> +---
> + lib/expat.h       |   21 +-
> + lib/internal.h    |   30 +
> + lib/libexpat.def  |    3 +
> + lib/libexpatw.def |    3 +
> + lib/xmlparse.c    | 1147 +++++++++++++++++++++++++++++++++++++--
> + 5 files changed, 1143 insertions(+), 61 deletions(-)
> +
> +diff --git a/lib/expat.h b/lib/expat.h
> +index 48a6e2a3..0fb70d9d 100644
> +--- a/lib/expat.h
> ++++ b/lib/expat.h
> +@@ -115,7 +115,9 @@ enum XML_Error {
> +   XML_ERROR_RESERVED_PREFIX_XMLNS,
> +   XML_ERROR_RESERVED_NAMESPACE_URI,
> +   /* Added in 2.2.1. */
> +-  XML_ERROR_INVALID_ARGUMENT
> ++  XML_ERROR_INVALID_ARGUMENT,
> ++  /* Added in 2.4.0. */
> ++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
> + };
> + 
> + enum XML_Content_Type {
> +@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
> +   XML_FEATURE_SIZEOF_XML_LCHAR,
> +   XML_FEATURE_NS,
> +   XML_FEATURE_LARGE_SIZE,
> +-  XML_FEATURE_ATTR_INFO
> ++  XML_FEATURE_ATTR_INFO,
> ++  /* Added in Expat 2.4.0. */
> ++ 
> XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DE
> FA
> ULT,
> ++ 
> XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEF
> AU
> LT
> +   /* Additional features must be added to the end of this enum. */
> + };
> + 
> +@@ -1010,6 +1015,18 @@ typedef struct {
> + XMLPARSEAPI(const XML_Feature *)
> + XML_GetFeatureList(void);
> + 
> ++#ifdef XML_DTD
> ++/* Added in Expat 2.4.0. */
> ++XMLPARSEAPI(XML_Bool)
> ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> ++    XML_Parser parser, float maximumAmplificationFactor);
> ++
> ++/* Added in Expat 2.4.0. */
> ++XMLPARSEAPI(XML_Bool)
> ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> ++    XML_Parser parser, unsigned long long
> activationThresholdBytes);
> ++#endif
> ++
> + /* Expat follows the semantic versioning convention.
> +    See http://semver.org.
> + */
> +diff --git a/lib/internal.h b/lib/internal.h
> +index 60913dab..d8b31fa2 100644
> +--- a/lib/internal.h
> ++++ b/lib/internal.h
> +@@ -101,10 +101,40 @@
> + #  endif
> + #endif
> + 
> ++#include <limits.h> // ULONG_MAX
> ++
> ++#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
> ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
> ++#  else
> ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> ++#  endif
> ++#else
> ++#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
> ++#  if ! defined(ULONG_MAX)
> ++#    error Compiler did not define ULONG_MAX for us
> ++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
> ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
> ++#  else
> ++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
> ++#  endif
> ++#endif
> ++
> + #ifndef UNUSED_P
> + #  define UNUSED_P(p) (void)p
> + #endif
> + 
> ++/* NOTE BEGIN If you ever patch these defaults to greater values
> ++              for non-attack XML payload in your environment,
> ++              please file a bug report with libexpat.  Thank you!
> ++*/
> ++#define
> \
> ++  100.0f
> ++#define
> \
> ++  8388608 // 8 MiB, 2^23
> ++/* NOTE END */
> ++
> + #ifdef __cplusplus
> + extern "C" {
> + #endif
> +diff --git a/lib/libexpat.def b/lib/libexpat.def
> +index 16faf595..5aefa6df 100644
> +--- a/lib/libexpat.def
> ++++ b/lib/libexpat.def
> +@@ -76,3 +76,6 @@ EXPORTS
> +   XML_SetHashSalt @67
> + ; added with version 2.2.5
> +   _INTERNAL_trim_to_complete_utf8_characters @68
> ++; added with version 2.4.0
> ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
> +diff --git a/lib/libexpatw.def b/lib/libexpatw.def
> +index 16faf595..5aefa6df 100644
> +--- a/lib/libexpatw.def
> ++++ b/lib/libexpatw.def
> +@@ -76,3 +76,6 @@ EXPORTS
> +   XML_SetHashSalt @67
> + ; added with version 2.2.5
> +   _INTERNAL_trim_to_complete_utf8_characters @68
> ++; added with version 2.4.0
> ++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
> ++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
> +diff --git a/lib/xmlparse.c b/lib/xmlparse.c
> +index 3aaf35b9..6790bc28 100644
> +--- a/lib/xmlparse.c
> ++++ b/lib/xmlparse.c
> +@@ -47,6 +47,8 @@
> + #include <limits.h> /* UINT_MAX */
> + #include <stdio.h>  /* fprintf */
> + #include <stdlib.h> /* getenv, rand_s */
> ++#include <stdint.h> /* uintptr_t */
> ++#include <math.h>   /* isnan */
> + 
> + #ifdef _WIN32
> + #  define getpid GetCurrentProcessId
> +@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
> +   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
> + } OPEN_INTERNAL_ENTITY;
> + 
> ++enum XML_Account {
> ++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the
> Expat
> parser */
> ++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced
> during
> entity
> ++                                   expansion */
> ++  XML_ACCOUNT_NONE              /* i.e. do not account, was
> accounted
> already */
> ++};
> ++
> ++#ifdef XML_DTD
> ++typedef unsigned long long XmlBigCount;
> ++typedef struct accounting {
> ++  XmlBigCount countBytesDirect;
> ++  XmlBigCount countBytesIndirect;
> ++  int debugLevel;
> ++  float maximumAmplificationFactor; // >=1.0
> ++  unsigned long long activationThresholdBytes;
> ++} ACCOUNTING;
> ++
> ++typedef struct entity_stats {
> ++  unsigned int countEverOpened;
> ++  unsigned int currentDepth;
> ++  unsigned int maximumDepthSeen;
> ++  int debugLevel;
> ++} ENTITY_STATS;
> ++#endif /* XML_DTD */
> ++
> + typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const
> char *start,
> +                                          const char *end, const
> char
> **endPtr);
> + 
> +@@ -403,16 +430,18 @@ static enum XML_Error
> initializeEncoding(XML_Parser parser);
> + static enum XML_Error doProlog(XML_Parser parser, const ENCODING
> *enc,
> +                                const char *s, const char *end, int
> tok,
> +                                const char *next, const char
> **nextPtr,
> +-                               XML_Bool haveMore, XML_Bool
> allowClosingDoctype);
> ++                               XML_Bool haveMore, XML_Bool
> allowClosingDoctype,
> ++                               enum XML_Account account);
> + static enum XML_Error processInternalEntity(XML_Parser parser,
> ENTITY
> *entity,
> +                                             XML_Bool betweenDecl);
> + static enum XML_Error doContent(XML_Parser parser, int
> startTagLevel,
> +                                 const ENCODING *enc, const char
> *start,
> +                                 const char *end, const char
> **endPtr,
> +-                                XML_Bool haveMore);
> ++                                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,
> +@@ -422,7 +451,8 @@ static enum XML_Error doIgnoreSection(XML_Parser
> parser, const ENCODING *,
> + static void freeBindings(XML_Parser parser, BINDING *bindings);
> + static enum XML_Error storeAtts(XML_Parser parser, const ENCODING
> *,
> +                                 const char *s, TAG_NAME
> *tagNamePtr,
> +-                                BINDING **bindingsPtr);
> ++                                BINDING **bindingsPtr,
> ++                                enum XML_Account account);
> + static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
> +                                  const ATTRIBUTE_ID *attId, const
> XML_Char *uri,
> +                                  BINDING **bindingsPtr);
> +@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE *type,
> ATTRIBUTE_ID *, XML_Bool isCdata,
> +                            XML_Parser parser);
> + static enum XML_Error storeAttributeValue(XML_Parser parser, const
> ENCODING *,
> +                                           XML_Bool isCdata, const
> char *,
> +-                                          const char *, STRING_POOL
> *);
> ++                                          const char *, STRING_POOL
> *,
> ++                                          enum XML_Account
> account);
> + static enum XML_Error appendAttributeValue(XML_Parser parser, const
> ENCODING *,
> +                                            XML_Bool isCdata, const
> char *,
> +-                                           const char *,
> STRING_POOL
> *);
> ++                                           const char *,
> STRING_POOL
> *,
> ++                                           enum XML_Account
> account);
> + static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const
> ENCODING
> *enc,
> +                                     const char *start, const char
> *end);
> + static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
> + static enum XML_Error storeEntityValue(XML_Parser parser, const
> ENCODING *enc,
> +-                                       const char *start, const
> char
> *end);
> ++                                       const char *start, const
> char
> *end,
> ++                                       enum XML_Account account);
> + static int reportProcessingInstruction(XML_Parser parser, const
> ENCODING *enc,
> +                                        const char *start, const
> char
> *end);
> + static int reportComment(XML_Parser parser, const ENCODING *enc,
> +@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const XML_Char
> *encodingName,
> + 
> + static void parserInit(XML_Parser parser, const XML_Char
> *encodingName);
> + 
> ++#ifdef XML_DTD
> ++static float accountingGetCurrentAmplification(XML_Parser
> rootParser);
> ++static void accountingReportStats(XML_Parser originParser, const
> char
> *epilog);
> ++static void accountingOnAbort(XML_Parser originParser);
> ++static void accountingReportDiff(XML_Parser rootParser,
> ++                                 unsigned int
> levelsAwayFromRootParser,
> ++                                 const char *before, const char
> *after,
> ++                                 ptrdiff_t bytesMore, int
> source_line,
> ++                                 enum XML_Account account);
> ++static XML_Bool accountingDiffTolerated(XML_Parser originParser,
> int
> tok,
> ++                                        const char *before, const
> char *after,
> ++                                        int source_line,
> ++                                        enum XML_Account account);
> ++
> ++static void entityTrackingReportStats(XML_Parser parser, ENTITY
> *entity,
> ++                                      const char *action, int
> sourceLine);
> ++static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
> ++                                 int sourceLine);
> ++static void entityTrackingOnClose(XML_Parser parser, ENTITY
> *entity,
> ++                                  int sourceLine);
> ++
> ++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,
> ++                                   unsigned long
> defaultDebugLevel);
> ++
> + #define poolStart(pool) ((pool)->start)
> + #define poolEnd(pool) ((pool)->ptr)
> + #define poolLength(pool) ((pool)->ptr - (pool)->start)
> +@@ -616,6 +678,10 @@ struct XML_ParserStruct {
> +   enum XML_ParamEntityParsing m_paramEntityParsing;
> + #endif
> +   unsigned long m_hash_secret_salt;
> ++#ifdef XML_DTD
> ++  ACCOUNTING m_accounting;
> ++  ENTITY_STATS m_entity_stats;
> ++#endif
> + };
> + 
> + #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
> +@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const XML_Char
> *encodingName) {
> +   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
> + #endif
> +   parser->m_hash_secret_salt = 0;
> ++
> ++#ifdef XML_DTD
> ++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
> ++  parser->m_accounting.debugLevel =
> getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
> ++  parser->m_accounting.maximumAmplificationFactor
> ++      =
> EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
> ++  parser->m_accounting.activationThresholdBytes
> ++      =
> EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
> ++
> ++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
> ++  parser->m_entity_stats.debugLevel =
> getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
> ++#endif
> + }
> + 
> + /* moves list of bindings to m_freeBindingList */
> +@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
> +   /* Added in 2.2.5. */
> +   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1,
> already */
> +     return XML_L("invalid argument");
> ++  /* Added in 2.4.0. */
> ++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
> ++    return XML_L(
> ++        "limit on input amplification factor (from DTD and
> entities)
> breached");
> +   }
> +   return NULL;
> + }
> +@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
> + 
> + const XML_Feature *XMLCALL
> + XML_GetFeatureList(void) {
> +-  static const XML_Feature features[]
> +-      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
> +-          sizeof(XML_Char)},
> +-         {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
> +-          sizeof(XML_LChar)},
> ++  static const XML_Feature features[] = {
> ++      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
> ++       sizeof(XML_Char)},
> ++      {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
> ++       sizeof(XML_LChar)},
> + #ifdef XML_UNICODE
> +-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> ++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
> + #endif
> + #ifdef XML_UNICODE_WCHAR_T
> +-         {XML_FEATURE_UNICODE_WCHAR_T,
> XML_L("XML_UNICODE_WCHAR_T"),
> 0},
> ++      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"),
> 0},
> + #endif
> + #ifdef XML_DTD
> +-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> ++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
> + #endif
> + #ifdef XML_CONTEXT_BYTES
> +-         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
> +-          XML_CONTEXT_BYTES},
> ++      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
> ++       XML_CONTEXT_BYTES},
> + #endif
> + #ifdef XML_MIN_SIZE
> +-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> ++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
> + #endif
> + #ifdef XML_NS
> +-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> ++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
> + #endif
> + #ifdef XML_LARGE_SIZE
> +-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> ++      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
> + #endif
> + #ifdef XML_ATTR_INFO
> +-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> ++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
> + #endif
> +-         {XML_FEATURE_END, NULL, 0}};
> ++#ifdef XML_DTD
> ++      /* Added in Expat 2.4.0. */
> ++     
> {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_D
> EF
> AULT,
> ++       XML_L("XML_BLAP_MAX_AMP"),
> ++       (long int)
> ++          
> EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT}
> ,
> ++     
> {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DE
> FA
> ULT,
> ++       XML_L("XML_BLAP_ACT_THRES"),
> ++      
> EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
> ++#endif
> ++      {XML_FEATURE_END, NULL, 0}};
> + 
> +   return features;
> + }
> + 
> ++#ifdef XML_DTD
> ++XML_Bool XMLCALL
> ++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
> ++    XML_Parser parser, float maximumAmplificationFactor) {
> ++  if ((parser == NULL) || (parser->m_parentParser != NULL)
> ++      || isnan(maximumAmplificationFactor)
> ++      || (maximumAmplificationFactor < 1.0f)) {
> ++    return XML_FALSE;
> ++  }
> ++  parser->m_accounting.maximumAmplificationFactor =
> maximumAmplificationFactor;
> ++  return XML_TRUE;
> ++}
> ++
> ++XML_Bool XMLCALL
> ++XML_SetBillionLaughsAttackProtectionActivationThreshold(
> ++    XML_Parser parser, unsigned long long activationThresholdBytes)
> {
> ++  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
> ++    return XML_FALSE;
> ++  }
> ++  parser->m_accounting.activationThresholdBytes =
> activationThresholdBytes;
> ++  return XML_TRUE;
> ++}
> ++#endif /* XML_DTD */
> ++
> + /* Initially tag->rawName always points into the parse buffer;
> +    for those TAG instances opened while the current parse buffer
> was
> +    processed, and not yet closed, we need to store tag->rawName in
> a
> more
> +@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
> + static enum XML_Error PTRCALL
> + contentProcessor(XML_Parser parser, const char *start, const char
> *end,
> +                  const char **endPtr) {
> +-  enum XML_Error result
> +-      = doContent(parser, 0, parser->m_encoding, start, end,
> endPtr,
> +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
> ++  enum XML_Error result = doContent(
> ++      parser, 0, parser->m_encoding, start, end, endPtr,
> ++      (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> XML_ACCOUNT_DIRECT);
> +   if (result == XML_ERROR_NONE) {
> +     if (! storeRawNames(parser))
> +       return XML_ERROR_NO_MEMORY;
> +@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser
> parser,
> const char *start,
> +   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
> +   switch (tok) {
> +   case XML_TOK_BOM:
> ++#ifdef XML_DTD
> ++    if (! accountingDiffTolerated(parser, tok, start, next,
> __LINE__,
> ++                                  XML_ACCOUNT_DIRECT)) {
> ++      accountingOnAbort(parser);
> ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++    }
> ++#endif /* XML_DTD */
> ++
> +     /* If we are at the end of the buffer, this would cause the
> next
> stage,
> +        i.e. externalEntityInitProcessor3, to pass control directly
> to
> +        doContent (by detecting XML_TOK_NONE) without processing any
> xml text
> +@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser
> parser,
> const char *start,
> +   const char *next = start; /* XmlContentTok doesn't always set the
> last arg */
> +   parser->m_eventPtr = start;
> +   tok = XmlContentTok(parser->m_encoding, start, end, &next);
> ++  /* Note: These bytes are accounted later in:
> ++           - processXmlDecl
> ++           - externalEntityContentProcessor
> ++  */
> +   parser->m_eventEndPtr = next;
> + 
> +   switch (tok) {
> +@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser
> parser, const char *start,
> +                                const char *end, const char
> **endPtr)
> {
> +   enum XML_Error result
> +       = doContent(parser, 1, parser->m_encoding, start, end,
> endPtr,
> +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
> ++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> ++                  XML_ACCOUNT_ENTITY_EXPANSION);
> +   if (result == XML_ERROR_NONE) {
> +     if (! storeRawNames(parser))
> +       return XML_ERROR_NO_MEMORY;
> +@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser
> parser, const char *start,
> + static enum XML_Error
> + doContent(XML_Parser parser, int startTagLevel, const ENCODING
> *enc,
> +           const char *s, const char *end, const char **nextPtr,
> +-          XML_Bool haveMore) {
> ++          XML_Bool haveMore, enum XML_Account account) {
> +   /* save one level of indirection */
> +   DTD *const dtd = parser->m_dtd;
> + 
> +@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int
> startTagLevel,
> const ENCODING *enc,
> +   for (;;) {
> +     const char *next = s; /* XmlContentTok doesn't always set the
> last arg */
> +     int tok = XmlContentTok(enc, s, end, &next);
> ++#ifdef XML_DTD
> ++    const char *accountAfter
> ++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok ==
> XML_TOK_TRAILING_CR))
> ++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
> ++              : next;
> ++    if (! accountingDiffTolerated(parser, tok, s, accountAfter,
> __LINE__,
> ++                                  account)) {
> ++      accountingOnAbort(parser);
> ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++    }
> ++#endif
> +     *eventEndPP = next;
> +     switch (tok) {
> +     case XML_TOK_TRAILING_CR:
> +@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int
> startTagLevel,
> const ENCODING *enc,
> +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> +           enc, s + enc->minBytesPerChar, next - enc-
> > minBytesPerChar);
> +       if (ch) {
> ++#ifdef XML_DTD
> ++        /* NOTE: We are replacing 4-6 characters original input for
> 1
> character
> ++         *       so there is no amplification and hence recording
> without
> ++         *       protection. */
> ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> ++                                ((char *)&ch) + sizeof(XML_Char),
> __LINE__,
> ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> ++#endif /* XML_DTD */
> +         if (parser->m_characterDataHandler)
> +           parser->m_characterDataHandler(parser->m_handlerArg, &ch,
> 1);
> +         else if (parser->m_defaultHandler)
> +@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int
> startTagLevel,
> const ENCODING *enc,
> +       }
> +       tag->name.str = (XML_Char *)tag->buf;
> +       *toPtr = XML_T('\0');
> +-      result = storeAtts(parser, enc, s, &(tag->name), &(tag-
> > bindings));
> ++      result
> ++          = storeAtts(parser, enc, s, &(tag->name), &(tag-
> >bindings),
> account);
> +       if (result)
> +         return result;
> +       if (parser->m_startElementHandler)
> +@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int
> startTagLevel,
> const ENCODING *enc,
> +       if (! name.str)
> +         return XML_ERROR_NO_MEMORY;
> +       poolFinish(&parser->m_tempPool);
> +-      result = storeAtts(parser, enc, s, &name, &bindings);
> ++      result = storeAtts(parser, enc, s, &name, &bindings,
> ++                         XML_ACCOUNT_NONE /* token spans whole
> start
> tag */);
> +       if (result != XML_ERROR_NONE) {
> +         freeBindings(parser, bindings);
> +         return result;
> +@@ -2907,7 +3057,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) {
> +@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING
> *bindings) {
> + */
> + static enum XML_Error
> + storeAtts(XML_Parser parser, const ENCODING *enc, const char
> *attStr,
> +-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
> ++          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
> ++          enum XML_Account account) {
> +   DTD *const dtd = parser->m_dtd; /* save one level of indirection
> */
> +   ELEMENT_TYPE *elementType;
> +   int nDefaultAtts;
> +@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const ENCODING
> *enc, const char *attStr,
> +       /* normalize the attribute value */
> +       result = storeAttributeValue(
> +           parser, enc, isCdata, parser->m_atts[i].valuePtr,
> +-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
> ++          parser->m_atts[i].valueEnd, &parser->m_tempPool,
> account);
> +       if (result)
> +         return result;
> +       appAtts[attIndex] = poolStart(&parser->m_tempPool);
> +@@ -3535,9 +3687,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) {
> +@@ -3557,7 +3709,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;
> +@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const
> ENCODING *enc, const char **startPtr,
> +   for (;;) {
> +     const char *next;
> +     int tok = XmlCdataSectionTok(enc, s, end, &next);
> ++#ifdef XML_DTD
> ++    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) {
> +     case XML_TOK_CDATA_SECT_CLOSE:
> +@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const
> ENCODING *enc, const char **startPtr,
> +   *eventPP = s;
> +   *startPtr = NULL;
> +   tok = XmlIgnoreSectionTok(enc, s, end, &next);
> ++#  ifdef XML_DTD
> ++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> ++                                XML_ACCOUNT_DIRECT)) {
> ++    accountingOnAbort(parser);
> ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++  }
> ++#  endif
> +   *eventEndPP = next;
> +   switch (tok) {
> +   case XML_TOK_IGNORE_SECT:
> +@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int
> isGeneralTextEntity, const char *s,
> +   const char *versionend;
> +   const XML_Char *storedversion = NULL;
> +   int standalone = -1;
> ++
> ++#ifdef XML_DTD
> ++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next,
> __LINE__,
> ++                                XML_ACCOUNT_DIRECT)) {
> ++    accountingOnAbort(parser);
> ++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++  }
> ++#endif
> ++
> +   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
> +           isGeneralTextEntity, parser->m_encoding, s, next,
> &parser-
> > m_eventPtr,
> +           &version, &versionend, &encodingName, &newEncoding,
> &standalone)) {
> +@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser parser,
> const char *s, const char *end,
> + 
> +   for (;;) {
> +     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
> ++    /* Note: Except for XML_TOK_BOM below, these bytes are
> accounted
> later in:
> ++             - storeEntityValue
> ++             - processXmlDecl
> ++    */
> +     parser->m_eventEndPtr = next;
> +     if (tok <= 0) {
> +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> XML_TOK_INVALID) {
> +@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser parser,
> const char *s, const char *end,
> +         break;
> +       }
> +       /* found end of entity value - can store it now */
> +-      return storeEntityValue(parser, parser->m_encoding, s, end);
> ++      return storeEntityValue(parser, parser->m_encoding, s, end,
> ++                              XML_ACCOUNT_DIRECT);
> +     } else if (tok == XML_TOK_XML_DECL) {
> +       enum XML_Error result;
> +       result = processXmlDecl(parser, 0, start, next);
> +@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser parser,
> const char *s, const char *end,
> +     */
> +     else if (tok == XML_TOK_BOM && next == end
> +              && ! parser->m_parsingStatus.finalBuffer) {
> ++#  ifdef XML_DTD
> ++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> ++                                    XML_ACCOUNT_DIRECT)) {
> ++        accountingOnAbort(parser);
> ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++      }
> ++#  endif
> ++
> +       *nextPtr = next;
> +       return XML_ERROR_NONE;
> +     }
> +@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser parser,
> const char *s, const char *end,
> +   }
> +   /* This would cause the next stage, i.e. doProlog to be passed
> XML_TOK_BOM.
> +      However, when parsing an external subset, doProlog will not
> accept a BOM
> +-     as valid, and report a syntax error, so we have to skip the
> BOM
> ++     as valid, and report a syntax error, so we have to skip the
> BOM,
> and
> ++     account for the BOM bytes.
> +   */
> +   else if (tok == XML_TOK_BOM) {
> ++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> ++                                  XML_ACCOUNT_DIRECT)) {
> ++      accountingOnAbort(parser);
> ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++    }
> ++
> +     s = next;
> +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> +   }
> + 
> +   parser->m_processor = prologProcessor;
> +   return doProlog(parser, parser->m_encoding, s, end, tok, next,
> nextPtr,
> +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> XML_TRUE);
> ++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> XML_TRUE,
> ++                  XML_ACCOUNT_DIRECT);
> + }
> + 
> + static enum XML_Error PTRCALL
> +@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser, const
> char *s, const char *end,
> + 
> +   for (;;) {
> +     tok = XmlPrologTok(enc, start, end, &next);
> ++    /* Note: These bytes are accounted later in:
> ++             - storeEntityValue
> ++    */
> +     if (tok <= 0) {
> +       if (! parser->m_parsingStatus.finalBuffer && tok !=
> XML_TOK_INVALID) {
> +         *nextPtr = s;
> +@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser, const
> char *s, const char *end,
> +         break;
> +       }
> +       /* found end of entity value - can store it now */
> +-      return storeEntityValue(parser, enc, s, end);
> ++      return storeEntityValue(parser, enc, s, end,
> XML_ACCOUNT_DIRECT);
> +     }
> +     start = next;
> +   }
> +@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const
> char
> *s, const char *end,
> +   const char *next = s;
> +   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> +   return doProlog(parser, parser->m_encoding, s, end, tok, next,
> nextPtr,
> +-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> XML_TRUE);
> ++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
> XML_TRUE,
> ++                  XML_ACCOUNT_DIRECT);
> + }
> + 
> + static enum XML_Error
> + doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
> const
> char *end,
> +          int tok, const char *next, const char **nextPtr, XML_Bool
> haveMore,
> +-         XML_Bool allowClosingDoctype) {
> ++         XML_Bool allowClosingDoctype, enum XML_Account account) {
> + #ifdef XML_DTD
> +   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
> + #endif /* XML_DTD */
> +@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const ENCODING
> *enc, const char *s, const char *end,
> +   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
> +   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
> + 
> ++#ifndef XML_DTD
> ++  UNUSED_P(account);
> ++#endif
> ++
> +   /* save one level of indirection */
> +   DTD *const dtd = parser->m_dtd;
> + 
> +@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const ENCODING
> *enc, const char *s, const char *end,
> +       }
> +     }
> +     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
> ++#ifdef XML_DTD
> ++    switch (role) {
> ++    case XML_ROLE_INSTANCE_START: // bytes accounted in
> contentProcessor
> ++    case XML_ROLE_XML_DECL:       // bytes accounted in
> processXmlDecl
> ++    case XML_ROLE_TEXT_DECL:      // bytes accounted in
> processXmlDecl
> ++      break;
> ++    default:
> ++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> account)) {
> ++        accountingOnAbort(parser);
> ++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++      }
> ++    }
> ++#endif
> +     switch (role) {
> +     case XML_ROLE_XML_DECL: {
> +       enum XML_Error result = processXmlDecl(parser, 0, s, next);
> +@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING
> *enc,
> const char *s, const char *end,
> +         const XML_Char *attVal;
> +         enum XML_Error result = storeAttributeValue(
> +             parser, enc, parser->m_declAttributeIsCdata,
> +-            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
> &dtd->pool);
> ++            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
> &dtd->pool,
> ++            XML_ACCOUNT_NONE);
> +         if (result)
> +           return result;
> +         attVal = poolStart(&dtd->pool);
> +@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING
> *enc,
> const char *s, const char *end,
> +       break;
> +     case XML_ROLE_ENTITY_VALUE:
> +       if (dtd->keepProcessing) {
> +-        enum XML_Error result = storeEntityValue(
> +-            parser, enc, s + enc->minBytesPerChar, next - enc-
> > minBytesPerChar);
> ++        enum XML_Error result
> ++            = storeEntityValue(parser, enc, s + enc-
> >minBytesPerChar,
> ++                               next - enc->minBytesPerChar,
> XML_ACCOUNT_NONE);
> +         if (parser->m_declEntity) {
> +           parser->m_declEntity->textPtr = poolStart(&dtd-
> > entityValuePool);
> +           parser->m_declEntity->textLen
> +@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const ENCODING
> *enc, const char *s, const char *end,
> +         if (parser->m_externalEntityRefHandler) {
> +           dtd->paramEntityRead = XML_FALSE;
> +           entity->open = XML_TRUE;
> ++          entityTrackingOnOpen(parser, entity, __LINE__);
> +           if (! parser->m_externalEntityRefHandler(
> +                   parser->m_externalEntityRefHandlerArg, 0, entity-
> > base,
> +                   entity->systemId, entity->publicId)) {
> ++            entityTrackingOnClose(parser, entity, __LINE__);
> +             entity->open = XML_FALSE;
> +             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> +           }
> ++          entityTrackingOnClose(parser, entity, __LINE__);
> +           entity->open = XML_FALSE;
> +           handleDefault = XML_FALSE;
> +           if (! dtd->paramEntityRead) {
> +@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const char
> *s, const char *end,
> +   for (;;) {
> +     const char *next = NULL;
> +     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> ++#ifdef XML_DTD
> ++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
> ++                                  XML_ACCOUNT_DIRECT)) {
> ++      accountingOnAbort(parser);
> ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++    }
> ++#endif
> +     parser->m_eventEndPtr = next;
> +     switch (tok) {
> +     /* report partial linebreak - it might be the last token */
> +@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser,
> ENTITY
> *entity, XML_Bool betweenDecl) {
> +       return XML_ERROR_NO_MEMORY;
> +   }
> +   entity->open = XML_TRUE;
> ++#ifdef XML_DTD
> ++  entityTrackingOnOpen(parser, entity, __LINE__);
> ++#endif
> +   entity->processed = 0;
> +   openEntity->next = parser->m_openInternalEntities;
> +   parser->m_openInternalEntities = openEntity;
> +@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser,
> ENTITY *entity, XML_Bool betweenDecl) {
> +     int tok
> +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> textEnd, &next);
> +     result = doProlog(parser, parser->m_internalEncoding,
> textStart,
> textEnd,
> +-                      tok, next, &next, XML_FALSE, XML_FALSE);
> ++                      tok, next, &next, XML_FALSE, XML_FALSE,
> ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> +   } else
> + #endif /* XML_DTD */
> +     result = doContent(parser, parser->m_tagLevel, parser-
> > m_internalEncoding,
> +-                       textStart, textEnd, &next, XML_FALSE);
> ++                       textStart, textEnd, &next, XML_FALSE,
> ++                       XML_ACCOUNT_ENTITY_EXPANSION);
> + 
> +   if (result == XML_ERROR_NONE) {
> +     if (textEnd != next && parser->m_parsingStatus.parsing ==
> XML_SUSPENDED) {
> +       entity->processed = (int)(next - textStart);
> +       parser->m_processor = internalEntityProcessor;
> +     } else {
> ++#ifdef XML_DTD
> ++      entityTrackingOnClose(parser, entity, __LINE__);
> ++#endif /* XML_DTD */
> +       entity->open = XML_FALSE;
> +       parser->m_openInternalEntities = openEntity->next;
> +       /* put openEntity back in list of free instances */
> +@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser parser,
> const char *s, const char *end,
> +     int tok
> +         = XmlPrologTok(parser->m_internalEncoding, textStart,
> textEnd, &next);
> +     result = doProlog(parser, parser->m_internalEncoding,
> textStart,
> textEnd,
> +-                      tok, next, &next, XML_FALSE, XML_TRUE);
> ++                      tok, next, &next, XML_FALSE, XML_TRUE,
> ++                      XML_ACCOUNT_ENTITY_EXPANSION);
> +   } else
> + #endif /* XML_DTD */
> +     result = doContent(parser, openEntity->startTagLevel,
> +                        parser->m_internalEncoding, textStart,
> textEnd, &next,
> +-                       XML_FALSE);
> ++                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
> + 
> +   if (result != XML_ERROR_NONE)
> +     return result;
> +@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser,
> const
> char *s, const char *end,
> +     entity->processed = (int)(next - (char *)entity->textPtr);
> +     return result;
> +   } else {
> ++#ifdef XML_DTD
> ++    entityTrackingOnClose(parser, entity, __LINE__);
> ++#endif
> +     entity->open = XML_FALSE;
> +     parser->m_openInternalEntities = openEntity->next;
> +     /* put openEntity back in list of free instances */
> +@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser,
> const
> char *s, const char *end,
> +     parser->m_processor = prologProcessor;
> +     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
> +     return doProlog(parser, parser->m_encoding, s, end, tok, next,
> nextPtr,
> +-                    (XML_Bool)! parser-
> >m_parsingStatus.finalBuffer,
> XML_TRUE);
> ++                    (XML_Bool)! parser-
> >m_parsingStatus.finalBuffer,
> XML_TRUE,
> ++                    XML_ACCOUNT_DIRECT);
> +   } else
> + #endif /* XML_DTD */
> +   {
> +@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser,
> const
> char *s, const char *end,
> +     /* see externalEntityContentProcessor vs contentProcessor */
> +     return doContent(parser, parser->m_parentParser ? 1 : 0,
> parser-
> > m_encoding,
> +                      s, end, nextPtr,
> +-                     (XML_Bool)! parser-
> > m_parsingStatus.finalBuffer);
> ++                     (XML_Bool)! parser-
> >m_parsingStatus.finalBuffer,
> ++                     XML_ACCOUNT_DIRECT);
> +   }
> + }
> + 
> +@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const char
> *s, const char *end,
> + 
> + static enum XML_Error
> + storeAttributeValue(XML_Parser parser, const ENCODING *enc,
> XML_Bool
> isCdata,
> +-                    const char *ptr, const char *end, STRING_POOL
> *pool) {
> ++                    const char *ptr, const char *end, STRING_POOL
> *pool,
> ++                    enum XML_Account account) {
> +   enum XML_Error result
> +-      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
> ++      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool,
> account);
> +   if (result)
> +     return result;
> +   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
> +@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser, const
> ENCODING *enc, XML_Bool isCdata,
> + 
> + static enum XML_Error
> + appendAttributeValue(XML_Parser parser, const ENCODING *enc,
> XML_Bool
> isCdata,
> +-                     const char *ptr, const char *end, STRING_POOL
> *pool) {
> ++                     const char *ptr, const char *end, STRING_POOL
> *pool,
> ++                     enum XML_Account account) {
> +   DTD *const dtd = parser->m_dtd; /* save one level of indirection
> */
> ++#ifndef XML_DTD
> ++  UNUSED_P(account);
> ++#endif
> ++
> +   for (;;) {
> +     const char *next;
> +     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
> ++#ifdef XML_DTD
> ++    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__,
> account)) {
> ++      accountingOnAbort(parser);
> ++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++    }
> ++#endif
> +     switch (tok) {
> +     case XML_TOK_NONE:
> +       return XML_ERROR_NONE;
> +@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser, const
> ENCODING *enc, XML_Bool isCdata,
> +       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
> +           enc, ptr + enc->minBytesPerChar, next - enc-
> > minBytesPerChar);
> +       if (ch) {
> ++#ifdef XML_DTD
> ++        /* NOTE: We are replacing 4-6 characters original input for
> 1
> character
> ++         *       so there is no amplification and hence recording
> without
> ++         *       protection. */
> ++        accountingDiffTolerated(parser, tok, (char *)&ch,
> ++                                ((char *)&ch) + sizeof(XML_Char),
> __LINE__,
> ++                                XML_ACCOUNT_ENTITY_EXPANSION);
> ++#endif /* XML_DTD */
> +         if (! poolAppendChar(pool, ch))
> +           return XML_ERROR_NO_MEMORY;
> +         break;
> +@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser, const
> ENCODING *enc, XML_Bool isCdata,
> +         enum XML_Error result;
> +         const XML_Char *textEnd = entity->textPtr + entity-
> >textLen;
> +         entity->open = XML_TRUE;
> ++#ifdef XML_DTD
> ++        entityTrackingOnOpen(parser, entity, __LINE__);
> ++#endif
> +         result = appendAttributeValue(parser, parser-
> > m_internalEncoding,
> +-                                      isCdata, (char *)entity-
> > textPtr,
> +-                                      (char *)textEnd, pool);
> ++                                      isCdata, (const char
> *)entity-
> > textPtr,
> ++                                      (const char *)textEnd, pool,
> ++                                     
> XML_ACCOUNT_ENTITY_EXPANSION);
> ++#ifdef XML_DTD
> ++        entityTrackingOnClose(parser, entity, __LINE__);
> ++#endif
> +         entity->open = XML_FALSE;
> +         if (result)
> +           return result;
> +@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser,
> const
> ENCODING *enc, XML_Bool isCdata,
> + 
> + static enum XML_Error
> + storeEntityValue(XML_Parser parser, const ENCODING *enc,
> +-                 const char *entityTextPtr, const char
> *entityTextEnd) {
> ++                 const char *entityTextPtr, const char
> *entityTextEnd,
> ++                 enum XML_Account account) {
> +   DTD *const dtd = parser->m_dtd; /* save one level of indirection
> */
> +   STRING_POOL *pool = &(dtd->entityValuePool);
> +   enum XML_Error result = XML_ERROR_NONE;
> + #ifdef XML_DTD
> +   int oldInEntityValue = parser->m_prologState.inEntityValue;
> +   parser->m_prologState.inEntityValue = 1;
> ++#else
> ++  UNUSED_P(account);
> + #endif /* XML_DTD */
> +   /* never return Null for the value argument in EntityDeclHandler,
> +      since this would indicate an external entity; therefore we
> +@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const
> ENCODING *enc,
> +   for (;;) {
> +     const char *next;
> +     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd,
> &next);
> ++
> ++#ifdef XML_DTD
> ++    if (! accountingDiffTolerated(parser, tok, entityTextPtr, next,
> __LINE__,
> ++                                  account)) {
> ++      accountingOnAbort(parser);
> ++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
> ++      goto endEntityValue;
> ++    }
> ++#endif
> ++
> +     switch (tok) {
> +     case XML_TOK_PARAM_ENTITY_REF:
> + #ifdef XML_DTD
> +@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser, const
> ENCODING *enc,
> +           if (parser->m_externalEntityRefHandler) {
> +             dtd->paramEntityRead = XML_FALSE;
> +             entity->open = XML_TRUE;
> ++            entityTrackingOnOpen(parser, entity, __LINE__);
> +             if (! parser->m_externalEntityRefHandler(
> +                     parser->m_externalEntityRefHandlerArg, 0,
> entity-
> > base,
> +                     entity->systemId, entity->publicId)) {
> ++              entityTrackingOnClose(parser, entity, __LINE__);
> +               entity->open = XML_FALSE;
> +               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
> +               goto endEntityValue;
> +             }
> ++            entityTrackingOnClose(parser, entity, __LINE__);
> +             entity->open = XML_FALSE;
> +             if (! dtd->paramEntityRead)
> +               dtd->keepProcessing = dtd->standalone;
> +@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const
> ENCODING *enc,
> +             dtd->keepProcessing = dtd->standalone;
> +         } else {
> +           entity->open = XML_TRUE;
> ++          entityTrackingOnOpen(parser, entity, __LINE__);
> +           result = storeEntityValue(
> +-              parser, parser->m_internalEncoding, (char *)entity-
> > textPtr,
> +-              (char *)(entity->textPtr + entity->textLen));
> ++              parser, parser->m_internalEncoding, (const char
> *)entity->textPtr,
> ++              (const char *)(entity->textPtr + entity->textLen),
> ++              XML_ACCOUNT_ENTITY_EXPANSION);
> ++          entityTrackingOnClose(parser, entity, __LINE__);
> +           entity->open = XML_FALSE;
> +           if (result)
> +             goto endEntityValue;
> +@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const
> XML_Memory_Handling_Suite *memsuite) {
> +   memcpy(result, s, charsRequired * sizeof(XML_Char));
> +   return result;
> + }
> ++
> ++#ifdef XML_DTD
> ++
> ++static float
> ++accountingGetCurrentAmplification(XML_Parser rootParser) {
> ++  const XmlBigCount countBytesOutput
> ++      = rootParser->m_accounting.countBytesDirect
> ++        + rootParser->m_accounting.countBytesIndirect;
> ++  const float amplificationFactor
> ++      = rootParser->m_accounting.countBytesDirect
> ++            ? (countBytesOutput
> ++               / (float)(rootParser-
> >m_accounting.countBytesDirect))
> ++            : 1.0f;
> ++  assert(! rootParser->m_parentParser);
> ++  return amplificationFactor;
> ++}
> ++
> ++static void
> ++accountingReportStats(XML_Parser originParser, const char *epilog)
> {
> ++  const XML_Parser rootParser = getRootParserOf(originParser,
> NULL);
> ++  assert(! rootParser->m_parentParser);
> ++
> ++  if (rootParser->m_accounting.debugLevel < 1) {
> ++    return;
> ++  }
> ++
> ++  const float amplificationFactor
> ++      = accountingGetCurrentAmplification(rootParser);
> ++  fprintf(stderr,
> ++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
> ++              "10") ", indirect " EXPAT_FMT_ULL("10") ",
> amplification %8.2f%s",
> ++          (void *)rootParser, rootParser-
> > m_accounting.countBytesDirect,
> ++          rootParser->m_accounting.countBytesIndirect,
> ++          (double)amplificationFactor, epilog);
> ++}
> ++
> ++static void
> ++accountingOnAbort(XML_Parser originParser) {
> ++  accountingReportStats(originParser, " ABORTING\n");
> ++}
> ++
> ++static void
> ++accountingReportDiff(XML_Parser rootParser,
> ++                     unsigned int levelsAwayFromRootParser, const
> char *before,
> ++                     const char *after, ptrdiff_t bytesMore, int
> source_line,
> ++                     enum XML_Account account) {
> ++  assert(! rootParser->m_parentParser);
> ++
> ++  fprintf(stderr,
> ++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d,
> xmlparse.c:%d) %*s\"",
> ++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" :
> "EXP",
> ++          levelsAwayFromRootParser, source_line, 10, "");
> ++
> ++  const char ellipis[] = "[..]";
> ++  const size_t ellipsisLength = sizeof(ellipis) /* because compile-
> time */ - 1;
> ++  const unsigned int contextLength = 10;
> ++
> ++  /* Note: Performance is of no concern here */
> ++  const char *walker = before;
> ++  if ((rootParser->m_accounting.debugLevel >= 3)
> ++      || (after - before)
> ++             <= (ptrdiff_t)(contextLength + ellipsisLength +
> contextLength)) {
> ++    for (; walker < after; walker++) {
> ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> ++    }
> ++  } else {
> ++    for (; walker < before + contextLength; walker++) {
> ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> ++    }
> ++    fprintf(stderr, ellipis);
> ++    walker = after - contextLength;
> ++    for (; walker < after; walker++) {
> ++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
> ++    }
> ++  }
> ++  fprintf(stderr, "\"\n");
> ++}
> ++
> ++static XML_Bool
> ++accountingDiffTolerated(XML_Parser originParser, int tok, const
> char
> *before,
> ++                        const char *after, int source_line,
> ++                        enum XML_Account account) {
> ++  /* Note: We need to check the token type *first* to be sure that
> ++   *       we can even access variable <after>, safely.
> ++   *       E.g. for XML_TOK_NONE <after> may hold an invalid
> pointer.
> */
> ++  switch (tok) {
> ++  case XML_TOK_INVALID:
> ++  case XML_TOK_PARTIAL:
> ++  case XML_TOK_PARTIAL_CHAR:
> ++  case XML_TOK_NONE:
> ++    return XML_TRUE;
> ++  }
> ++
> ++  if (account == XML_ACCOUNT_NONE)
> ++    return XML_TRUE; /* because these bytes have been accounted
> for,
> already */
> ++
> ++  unsigned int levelsAwayFromRootParser;
> ++  const XML_Parser rootParser
> ++      = getRootParserOf(originParser, &levelsAwayFromRootParser);
> ++  assert(! rootParser->m_parentParser);
> ++
> ++  const int isDirect
> ++      = (account == XML_ACCOUNT_DIRECT) && (originParser ==
> rootParser);
> ++  const ptrdiff_t bytesMore = after - before;
> ++
> ++  XmlBigCount *const additionTarget
> ++      = isDirect ? &rootParser->m_accounting.countBytesDirect
> ++                 : &rootParser->m_accounting.countBytesIndirect;
> ++
> ++  /* Detect and avoid integer overflow */
> ++  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
> ++    return XML_FALSE;
> ++  *additionTarget += bytesMore;
> ++
> ++  const XmlBigCount countBytesOutput
> ++      = rootParser->m_accounting.countBytesDirect
> ++        + rootParser->m_accounting.countBytesIndirect;
> ++  const float amplificationFactor
> ++      = accountingGetCurrentAmplification(rootParser);
> ++  const XML_Bool tolerated
> ++      = (countBytesOutput < rootParser-
> > m_accounting.activationThresholdBytes)
> ++        || (amplificationFactor
> ++            <= rootParser-
> >m_accounting.maximumAmplificationFactor);
> ++
> ++  if (rootParser->m_accounting.debugLevel >= 2) {
> ++    accountingReportStats(rootParser, "");
> ++    accountingReportDiff(rootParser, levelsAwayFromRootParser,
> before, after,
> ++                         bytesMore, source_line, account);
> ++  }
> ++
> ++  return tolerated;
> ++}
> ++
> ++static void
> ++entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
> ++                          const char *action, int sourceLine) {
> ++  assert(! rootParser->m_parentParser);
> ++  if (rootParser->m_entity_stats.debugLevel < 1)
> ++    return;
> ++
> ++#  if defined(XML_UNICODE)
> ++  const char *const entityName = "[..]";
> ++#  else
> ++  const char *const entityName = entity->name;
> ++#  endif
> ++
> ++  fprintf(
> ++      stderr,
> ++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s
> length %d (xmlparse.c:%d)\n",
> ++      (void *)rootParser, rootParser-
> >m_entity_stats.countEverOpened,
> ++      rootParser->m_entity_stats.currentDepth,
> ++      rootParser->m_entity_stats.maximumDepthSeen,
> ++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
> ++      entity->is_param ? "%" : "&", entityName, action, entity-
> > textLen,
> ++      sourceLine);
> ++}
> ++
> ++static void
> ++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int
> sourceLine) {
> ++  const XML_Parser rootParser = getRootParserOf(originParser,
> NULL);
> ++  assert(! rootParser->m_parentParser);
> ++
> ++  rootParser->m_entity_stats.countEverOpened++;
> ++  rootParser->m_entity_stats.currentDepth++;
> ++  if (rootParser->m_entity_stats.currentDepth
> ++      > rootParser->m_entity_stats.maximumDepthSeen) {
> ++    rootParser->m_entity_stats.maximumDepthSeen++;
> ++  }
> ++
> ++  entityTrackingReportStats(rootParser, entity, "OPEN ",
> sourceLine);
> ++}
> ++
> ++static void
> ++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int
> sourceLine) {
> ++  const XML_Parser rootParser = getRootParserOf(originParser,
> NULL);
> ++  assert(! rootParser->m_parentParser);
> ++
> ++  entityTrackingReportStats(rootParser, entity, "CLOSE",
> sourceLine);
> ++  rootParser->m_entity_stats.currentDepth--;
> ++}
> ++
> ++static XML_Parser
> ++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
> ++  XML_Parser rootParser = parser;
> ++  unsigned int stepsTakenUpwards = 0;
> ++  while (rootParser->m_parentParser) {
> ++    rootParser = rootParser->m_parentParser;
> ++    stepsTakenUpwards++;
> ++  }
> ++  assert(! rootParser->m_parentParser);
> ++  if (outLevelDiff != NULL) {
> ++    *outLevelDiff = stepsTakenUpwards;
> ++  }
> ++  return rootParser;
> ++}
> ++
> ++static const char *
> ++unsignedCharToPrintable(unsigned char c) {
> ++  switch (c) {
> ++  case 0:
> ++    return "\\0";
> ++  case 1:
> ++    return "\\x1";
> ++  case 2:
> ++    return "\\x2";
> ++  case 3:
> ++    return "\\x3";
> ++  case 4:
> ++    return "\\x4";
> ++  case 5:
> ++    return "\\x5";
> ++  case 6:
> ++    return "\\x6";
> ++  case 7:
> ++    return "\\x7";
> ++  case 8:
> ++    return "\\x8";
> ++  case 9:
> ++    return "\\t";
> ++  case 10:
> ++    return "\\n";
> ++  case 11:
> ++    return "\\xB";
> ++  case 12:
> ++    return "\\xC";
> ++  case 13:
> ++    return "\\r";
> ++  case 14:
> ++    return "\\xE";
> ++  case 15:
> ++    return "\\xF";
> ++  case 16:
> ++    return "\\x10";
> ++  case 17:
> ++    return "\\x11";
> ++  case 18:
> ++    return "\\x12";
> ++  case 19:
> ++    return "\\x13";
> ++  case 20:
> ++    return "\\x14";
> ++  case 21:
> ++    return "\\x15";
> ++  case 22:
> ++    return "\\x16";
> ++  case 23:
> ++    return "\\x17";
> ++  case 24:
> ++    return "\\x18";
> ++  case 25:
> ++    return "\\x19";
> ++  case 26:
> ++    return "\\x1A";
> ++  case 27:
> ++    return "\\x1B";
> ++  case 28:
> ++    return "\\x1C";
> ++  case 29:
> ++    return "\\x1D";
> ++  case 30:
> ++    return "\\x1E";
> ++  case 31:
> ++    return "\\x1F";
> ++  case 32:
> ++    return " ";
> ++  case 33:
> ++    return "!";
> ++  case 34:
> ++    return "\\\"";
> ++  case 35:
> ++    return "#";
> ++  case 36:
> ++    return "$";
> ++  case 37:
> ++    return "%";
> ++  case 38:
> ++    return "&";
> ++  case 39:
> ++    return "'";
> ++  case 40:
> ++    return "(";
> ++  case 41:
> ++    return ")";
> ++  case 42:
> ++    return "*";
> ++  case 43:
> ++    return "+";
> ++  case 44:
> ++    return ",";
> ++  case 45:
> ++    return "-";
> ++  case 46:
> ++    return ".";
> ++  case 47:
> ++    return "/";
> ++  case 48:
> ++    return "0";
> ++  case 49:
> ++    return "1";
> ++  case 50:
> ++    return "2";
> ++  case 51:
> ++    return "3";
> ++  case 52:
> ++    return "4";
> ++  case 53:
> ++    return "5";
> ++  case 54:
> ++    return "6";
> ++  case 55:
> ++    return "7";
> ++  case 56:
> ++    return "8";
> ++  case 57:
> ++    return "9";
> ++  case 58:
> ++    return ":";
> ++  case 59:
> ++    return ";";
> ++  case 60:
> ++    return "<";
> ++  case 61:
> ++    return "=";
> ++  case 62:
> ++    return ">";
> ++  case 63:
> ++    return "?";
> ++  case 64:
> ++    return "@";
> ++  case 65:
> ++    return "A";
> ++  case 66:
> ++    return "B";
> ++  case 67:
> ++    return "C";
> ++  case 68:
> ++    return "D";
> ++  case 69:
> ++    return "E";
> ++  case 70:
> ++    return "F";
> ++  case 71:
> ++    return "G";
> ++  case 72:
> ++    return "H";
> ++  case 73:
> ++    return "I";
> ++  case 74:
> ++    return "J";
> ++  case 75:
> ++    return "K";
> ++  case 76:
> ++    return "L";
> ++  case 77:
> ++    return "M";
> ++  case 78:
> ++    return "N";
> ++  case 79:
> ++    return "O";
> ++  case 80:
> ++    return "P";
> ++  case 81:
> ++    return "Q";
> ++  case 82:
> ++    return "R";
> ++  case 83:
> ++    return "S";
> ++  case 84:
> ++    return "T";
> ++  case 85:
> ++    return "U";
> ++  case 86:
> ++    return "V";
> ++  case 87:
> ++    return "W";
> ++  case 88:
> ++    return "X";
> ++  case 89:
> ++    return "Y";
> ++  case 90:
> ++    return "Z";
> ++  case 91:
> ++    return "[";
> ++  case 92:
> ++    return "\\\\";
> ++  case 93:
> ++    return "]";
> ++  case 94:
> ++    return "^";
> ++  case 95:
> ++    return "_";
> ++  case 96:
> ++    return "`";
> ++  case 97:
> ++    return "a";
> ++  case 98:
> ++    return "b";
> ++  case 99:
> ++    return "c";
> ++  case 100:
> ++    return "d";
> ++  case 101:
> ++    return "e";
> ++  case 102:
> ++    return "f";
> ++  case 103:
> ++    return "g";
> ++  case 104:
> ++    return "h";
> ++  case 105:
> ++    return "i";
> ++  case 106:
> ++    return "j";
> ++  case 107:
> ++    return "k";
> ++  case 108:
> ++    return "l";
> ++  case 109:
> ++    return "m";
> ++  case 110:
> ++    return "n";
> ++  case 111:
> ++    return "o";
> ++  case 112:
> ++    return "p";
> ++  case 113:
> ++    return "q";
> ++  case 114:
> ++    return "r";
> ++  case 115:
> ++    return "s";
> ++  case 116:
> ++    return "t";
> ++  case 117:
> ++    return "u";
> ++  case 118:
> ++    return "v";
> ++  case 119:
> ++    return "w";
> ++  case 120:
> ++    return "x";
> ++  case 121:
> ++    return "y";
> ++  case 122:
> ++    return "z";
> ++  case 123:
> ++    return "{";
> ++  case 124:
> ++    return "|";
> ++  case 125:
> ++    return "}";
> ++  case 126:
> ++    return "~";
> ++  case 127:
> ++    return "\\x7F";
> ++  case 128:
> ++    return "\\x80";
> ++  case 129:
> ++    return "\\x81";
> ++  case 130:
> ++    return "\\x82";
> ++  case 131:
> ++    return "\\x83";
> ++  case 132:
> ++    return "\\x84";
> ++  case 133:
> ++    return "\\x85";
> ++  case 134:
> ++    return "\\x86";
> ++  case 135:
> ++    return "\\x87";
> ++  case 136:
> ++    return "\\x88";
> ++  case 137:
> ++    return "\\x89";
> ++  case 138:
> ++    return "\\x8A";
> ++  case 139:
> ++    return "\\x8B";
> ++  case 140:
> ++    return "\\x8C";
> ++  case 141:
> ++    return "\\x8D";
> ++  case 142:
> ++    return "\\x8E";
> ++  case 143:
> ++    return "\\x8F";
> ++  case 144:
> ++    return "\\x90";
> ++  case 145:
> ++    return "\\x91";
> ++  case 146:
> ++    return "\\x92";
> ++  case 147:
> ++    return "\\x93";
> ++  case 148:
> ++    return "\\x94";
> ++  case 149:
> ++    return "\\x95";
> ++  case 150:
> ++    return "\\x96";
> ++  case 151:
> ++    return "\\x97";
> ++  case 152:
> ++    return "\\x98";
> ++  case 153:
> ++    return "\\x99";
> ++  case 154:
> ++    return "\\x9A";
> ++  case 155:
> ++    return "\\x9B";
> ++  case 156:
> ++    return "\\x9C";
> ++  case 157:
> ++    return "\\x9D";
> ++  case 158:
> ++    return "\\x9E";
> ++  case 159:
> ++    return "\\x9F";
> ++  case 160:
> ++    return "\\xA0";
> ++  case 161:
> ++    return "\\xA1";
> ++  case 162:
> ++    return "\\xA2";
> ++  case 163:
> ++    return "\\xA3";
> ++  case 164:
> ++    return "\\xA4";
> ++  case 165:
> ++    return "\\xA5";
> ++  case 166:
> ++    return "\\xA6";
> ++  case 167:
> ++    return "\\xA7";
> ++  case 168:
> ++    return "\\xA8";
> ++  case 169:
> ++    return "\\xA9";
> ++  case 170:
> ++    return "\\xAA";
> ++  case 171:
> ++    return "\\xAB";
> ++  case 172:
> ++    return "\\xAC";
> ++  case 173:
> ++    return "\\xAD";
> ++  case 174:
> ++    return "\\xAE";
> ++  case 175:
> ++    return "\\xAF";
> ++  case 176:
> ++    return "\\xB0";
> ++  case 177:
> ++    return "\\xB1";
> ++  case 178:
> ++    return "\\xB2";
> ++  case 179:
> ++    return "\\xB3";
> ++  case 180:
> ++    return "\\xB4";
> ++  case 181:
> ++    return "\\xB5";
> ++  case 182:
> ++    return "\\xB6";
> ++  case 183:
> ++    return "\\xB7";
> ++  case 184:
> ++    return "\\xB8";
> ++  case 185:
> ++    return "\\xB9";
> ++  case 186:
> ++    return "\\xBA";
> ++  case 187:
> ++    return "\\xBB";
> ++  case 188:
> ++    return "\\xBC";
> ++  case 189:
> ++    return "\\xBD";
> ++  case 190:
> ++    return "\\xBE";
> ++  case 191:
> ++    return "\\xBF";
> ++  case 192:
> ++    return "\\xC0";
> ++  case 193:
> ++    return "\\xC1";
> ++  case 194:
> ++    return "\\xC2";
> ++  case 195:
> ++    return "\\xC3";
> ++  case 196:
> ++    return "\\xC4";
> ++  case 197:
> ++    return "\\xC5";
> ++  case 198:
> ++    return "\\xC6";
> ++  case 199:
> ++    return "\\xC7";
> ++  case 200:
> ++    return "\\xC8";
> ++  case 201:
> ++    return "\\xC9";
> ++  case 202:
> ++    return "\\xCA";
> ++  case 203:
> ++    return "\\xCB";
> ++  case 204:
> ++    return "\\xCC";
> ++  case 205:
> ++    return "\\xCD";
> ++  case 206:
> ++    return "\\xCE";
> ++  case 207:
> ++    return "\\xCF";
> ++  case 208:
> ++    return "\\xD0";
> ++  case 209:
> ++    return "\\xD1";
> ++  case 210:
> ++    return "\\xD2";
> ++  case 211:
> ++    return "\\xD3";
> ++  case 212:
> ++    return "\\xD4";
> ++  case 213:
> ++    return "\\xD5";
> ++  case 214:
> ++    return "\\xD6";
> ++  case 215:
> ++    return "\\xD7";
> ++  case 216:
> ++    return "\\xD8";
> ++  case 217:
> ++    return "\\xD9";
> ++  case 218:
> ++    return "\\xDA";
> ++  case 219:
> ++    return "\\xDB";
> ++  case 220:
> ++    return "\\xDC";
> ++  case 221:
> ++    return "\\xDD";
> ++  case 222:
> ++    return "\\xDE";
> ++  case 223:
> ++    return "\\xDF";
> ++  case 224:
> ++    return "\\xE0";
> ++  case 225:
> ++    return "\\xE1";
> ++  case 226:
> ++    return "\\xE2";
> ++  case 227:
> ++    return "\\xE3";
> ++  case 228:
> ++    return "\\xE4";
> ++  case 229:
> ++    return "\\xE5";
> ++  case 230:
> ++    return "\\xE6";
> ++  case 231:
> ++    return "\\xE7";
> ++  case 232:
> ++    return "\\xE8";
> ++  case 233:
> ++    return "\\xE9";
> ++  case 234:
> ++    return "\\xEA";
> ++  case 235:
> ++    return "\\xEB";
> ++  case 236:
> ++    return "\\xEC";
> ++  case 237:
> ++    return "\\xED";
> ++  case 238:
> ++    return "\\xEE";
> ++  case 239:
> ++    return "\\xEF";
> ++  case 240:
> ++    return "\\xF0";
> ++  case 241:
> ++    return "\\xF1";
> ++  case 242:
> ++    return "\\xF2";
> ++  case 243:
> ++    return "\\xF3";
> ++  case 244:
> ++    return "\\xF4";
> ++  case 245:
> ++    return "\\xF5";
> ++  case 246:
> ++    return "\\xF6";
> ++  case 247:
> ++    return "\\xF7";
> ++  case 248:
> ++    return "\\xF8";
> ++  case 249:
> ++    return "\\xF9";
> ++  case 250:
> ++    return "\\xFA";
> ++  case 251:
> ++    return "\\xFB";
> ++  case 252:
> ++    return "\\xFC";
> ++  case 253:
> ++    return "\\xFD";
> ++  case 254:
> ++    return "\\xFE";
> ++  case 255:
> ++    return "\\xFF";
> ++  default:
> ++    assert(0); /* never gets here */
> ++    return "dead code";
> ++  }
> ++  assert(0); /* never gets here */
> ++}
> ++
> ++#endif /* XML_DTD */
> ++
> ++static unsigned long
> ++getDebugLevel(const char *variableName, unsigned long
> defaultDebugLevel) {
> ++  const char *const valueOrNull = getenv(variableName);
> ++  if (valueOrNull == NULL) {
> ++    return defaultDebugLevel;
> ++  }
> ++  const char *const value = valueOrNull;
> ++
> ++  errno = 0;
> ++  char *afterValue = (char *)value;
> ++  unsigned long debugLevel = strtoul(value, &afterValue, 10);
> ++  if ((errno != 0) || (afterValue[0] != '\0')) {
> ++    errno = 0;
> ++    return defaultDebugLevel;
> ++  }
> ++
> ++  return debugLevel;
> ++}
> +-- 
> +2.32.0
> +
> diff --git a/meta/recipes-core/expat/expat/libtool-tag.patch
> b/meta/recipes-core/expat/expat/libtool-tag.patch
> index 0a0aed23e5..203415a725 100644
> --- a/meta/recipes-core/expat/expat/libtool-tag.patch
> +++ b/meta/recipes-core/expat/expat/libtool-tag.patch
> @@ -1,30 +1,27 @@
> -From 10342e6b600858b091bc7771e454d9e06af06410 Mon Sep 17 00:00:00
> 2001
> -From: Khem Raj <raj.khem@gmail.com>
> -Date: Thu, 2 Nov 2017 18:20:57 +0800
> +From da433dbe79f2d4d5d7d79869c669594c99c5de9c Mon Sep 17 00:00:00
> 2001
> +From: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
> +Date: Wed, 16 Jun 2021 19:00:30 +0200
>  Subject: [PATCH] Add CC tag to build
>  
> -Add CC tag to build
> -
>  Upstream-Status: Pending
> -Signed-off-by: Khem Raj <raj.khem@gmail.com>
> -Signed-off-by: Dengke Du <dengke.du@windriver.com>
> +Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
>  ---
> - Makefile.in | 2 +-
> + Makefile.am | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>  
> -diff --git a/Makefile.in b/Makefile.in
> -index 9560a95..d444bd6 100644
> ---- a/Makefile.in
> -+++ b/Makefile.in
> -@@ -319,7 +319,7 @@ LIBCURRENT = @LIBCURRENT@
> - LIBOBJS = @LIBOBJS@
> - LIBREVISION = @LIBREVISION@
> - LIBS = @LIBS@
> --LIBTOOL = @LIBTOOL@
> -+LIBTOOL = @LIBTOOL@ --tag CC
> - LIPO = @LIPO@
> - LN_S = @LN_S@
> - LTLIBOBJS = @LTLIBOBJS@
> +diff --git a/Makefile.am b/Makefile.am
> +index 5e1d37dd..f7a6dece 100644
> +--- a/Makefile.am
> ++++ b/Makefile.am
> +@@ -36,7 +36,7 @@ AUTOMAKE_OPTIONS = \
> +     subdir-objects
> + 
> + ACLOCAL_AMFLAGS = -I m4
> +-LIBTOOLFLAGS = --verbose
> ++LIBTOOLFLAGS = --verbose --tag=CC
> + 
> + SUBDIRS = lib # lib goes first to build first
> + if WITH_EXAMPLES
>  -- 
> -2.7.4
> +2.32.0
>  
> diff --git a/meta/recipes-core/expat/expat_2.2.9.bb b/meta/recipes-
> core/expat/expat_2.2.9.bb
> index 8f3db41352..c4b51265ac 100644
> --- a/meta/recipes-core/expat/expat_2.2.9.bb
> +++ b/meta/recipes-core/expat/expat_2.2.9.bb
> @@ -6,17 +6,19 @@ LICENSE = "MIT"
>  
>  LIC_FILES_CHKSUM =
> "file://COPYING;md5=5b8620d98e49772d95fc1d291c26aa79"
>  
> -SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}.tar.bz2 \
> +SRC_URI = "git://github.com/libexpat/libexpat.git;protocol=https \
> +           file://CVE-2013-0340.patch \
>             file://libtool-tag.patch \
>           "
>  
> -SRC_URI[md5sum] = "875a2c2ff3e8eb9e5a5cd62db2033ab5"
> -SRC_URI[sha256sum] =
> "f1063084dc4302a427dabcca499c8312b3a32a29b7d2506653ecc8f950a9a237"
> +SRCREV = "a7bc26b69768f7fb24f0c7976fae24b157b85b13"
> +
> +S = "${WORKDIR}/git/expat"
>  
>  inherit autotools lib_package
>  
>  do_configure_prepend () {
> -       rm -f ${S}/conftools/libtool.m4
> +       rm -f ${S}/expat/conftools/libtool.m4
>  }
>  
>  BBCLASSEXTEND = "native nativesdk"
> -- 
> 2.32.0
> 
> 
> 
> 
> 
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKQPMACgkQYgqew07V
MNVYcAf/X/VSwrve1JBme2t9zTAmHSRH68aWYd+tinuJwGZY17tGUr2JKDK3t4ys
bixcOI6K2eBZOzokSQ0IgtVNFEcyGMKHfCE0DKCWEwNN7HS1cfymMnrF3mUTwPBZ
EkqbJ72XEF4RDdHYLj5Q/iWSF86d9JCvS0TCMDSmlJA+rXbY+PK8gutT9IYZDZs7
pFAveQYY/QQDh9tXYHZzZ6/7Lws7Q6uw+VSEWoT4On5wXJeU1O2mgBB9YJ7kvaGd
bOpa2piSvClzV+Pm/b1w677X+jAH7v0ph6hbC5GqXn39L6maCfbkD7w3Wj1HZzTw
rdAZLF6yDbjiPrQ3ivtjqtCvpPW1Qg==
=lcly
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
  2021-06-16 18:21   ` Jasper Orschulko
@ 2021-06-16 21:14     ` Jasper Orschulko
  2021-06-17 10:06       ` Jasper Orschulko
  0 siblings, 1 reply; 11+ messages in thread
From: Jasper Orschulko @ 2021-06-16 21:14 UTC (permalink / raw)
  To: openembedded-core, steve

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

I just noticed (additionally to the fact that I messed up the path in
my patch), that the original do_configure_prepend task actually is not
necessary, as there is no ${S}/conftools/libtool.m4 in the 2.9.9
release (neither git, nor sourceforge). While removing a non-existing
file does no harm, I will provide a new patch tomorrow without this
task, for tidiness' sake. ;) 

- -- 
With best regards

Jasper Orschulko
DevOps Engineer

Tel. +49 30 58 58 14 265
Fax +49 30 58 58 14 999
Jasper.Orschulko@iris-sensing.com

• • • • • • • • • • • • • • • • • • • • • • • • • •

iris-GmbH
infrared & intelligent sensors
Ostendstraße 1-14 | 12459 Berlin

https://iris-sensing.com/




On Wed, 2021-06-16 at 20:20 +0200, Jasper Orschulko wrote:
> Revision of the the patch file. Please verify. :)
> 
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKaXMACgkQYgqew07V
MNXfFQf8C5Lh2OG7tDsP6uQcLEV/J+ieCWN2ylKH5lARVzEPQB5TpVGfgcbdrqPr
66Ia3NS/gKDHtpKDigBOpYau4jFC71252Hpfap13/OiH53/+1es3hwXm5k4xtYYL
WU8iAG7wlKwrj8zSljeElOvOw0EiDLaX/dnhtNKboquKxAgJrQkGG2a3G4KlFQ50
W4xR0Jrx67/UkWJLic1h51vc1RGw7zeDbOwJ+xl+2uXDGCjRtQHmXChpBSInAMjP
r0uza47Oi/+XQGuVYAdYR12lp89Vl7EGAvoy6seKablkVSu7zBMxBi70GyrQdKFw
eM7ixMdqSS1MZ6zdI/64Aaq9XB1wgg==
=EY5+
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
  2021-06-16 21:14     ` Jasper Orschulko
@ 2021-06-17 10:06       ` Jasper Orschulko
  0 siblings, 0 replies; 11+ messages in thread
From: Jasper Orschulko @ 2021-06-17 10:06 UTC (permalink / raw)
  To: openembedded-core, steve

expat < 4.0 is vulnerable to billion laughs attacks (see
[https://github.com/libexpat/libexpat/issues/34]). This patch backports
the commits b1d039607d3d8a042bf0466bfcc1c0f104e353c8
and 60959f2b491876199879d97c8ed956eabb0c2e73 from upstream.

Additionally, the SRC_URI had to be adjusted due to renaming of the
source archive

Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>

Upstream-Status: Submitted
[https://lists.openembedded.org/g/openembedded-core/message/153030?p=,,,20,0,0,0::Created,,Jasper,20,2,0,83581993
]
---
 .../expat/expat/CVE-2013-0340.patch           | 1758 +++++++++++++++++
 .../expat/expat/libtool-tag.patch             |   41 +-
 meta/recipes-core/expat/expat_2.2.9.bb        |   12 +-
 3 files changed, 1782 insertions(+), 29 deletions(-)
 create mode 100644 meta/recipes-core/expat/expat/CVE-2013-0340.patch

diff --git a/meta/recipes-core/expat/expat/CVE-2013-0340.patch
b/meta/recipes-core/expat/expat/CVE-2013-0340.patch
new file mode 100644
index 0000000000..5ef749719d
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2013-0340.patch
@@ -0,0 +1,1758 @@
+From a644ccf25392523b1329872310e24d0fc5f40629 Mon Sep 17 00:00:00 2001
+From: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon, 19 Apr 2021 21:42:51 +0200
+Subject: [PATCH] expat: Backport fix for CVE-2013-0340
+
+Issue: https://github.com/libexpat/libexpat/issues/34
+
+This patch cherry-picks the following commits from upstream release
+2.4.0 onto 2.2.9:
+
+- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
+- 60959f2b491876199879d97c8ed956eabb0c2e73
+
+Upstream-Status: Backport
+CVE: CVE-2013-0340
+Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
+---
+ lib/expat.h       |   21 +-
+ lib/internal.h    |   30 +
+ lib/libexpat.def  |    3 +
+ lib/libexpatw.def |    3 +
+ lib/xmlparse.c    | 1147 +++++++++++++++++++++++++++++++++++++--
+ 5 files changed, 1143 insertions(+), 61 deletions(-)
+
+diff --git a/lib/expat.h b/lib/expat.h
+index 48a6e2a3..0fb70d9d 100644
+--- a/lib/expat.h
++++ b/lib/expat.h
+@@ -115,7 +115,9 @@ enum XML_Error {
+   XML_ERROR_RESERVED_PREFIX_XMLNS,
+   XML_ERROR_RESERVED_NAMESPACE_URI,
+   /* Added in 2.2.1. */
+-  XML_ERROR_INVALID_ARGUMENT
++  XML_ERROR_INVALID_ARGUMENT,
++  /* Added in 2.4.0. */
++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
+ };
+ 
+ enum XML_Content_Type {
+@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
+   XML_FEATURE_SIZEOF_XML_LCHAR,
+   XML_FEATURE_NS,
+   XML_FEATURE_LARGE_SIZE,
+-  XML_FEATURE_ATTR_INFO
++  XML_FEATURE_ATTR_INFO,
++  /* Added in Expat 2.4.0. */
++ 
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFA
ULT,
++ 
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAU
LT
+   /* Additional features must be added to the end of this enum. */
+ };
+ 
+@@ -1010,6 +1015,18 @@ typedef struct {
+ XMLPARSEAPI(const XML_Feature *)
+ XML_GetFeatureList(void);
+ 
++#ifdef XML_DTD
++/* Added in Expat 2.4.0. */
++XMLPARSEAPI(XML_Bool)
++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++    XML_Parser parser, float maximumAmplificationFactor);
++
++/* Added in Expat 2.4.0. */
++XMLPARSEAPI(XML_Bool)
++XML_SetBillionLaughsAttackProtectionActivationThreshold(
++    XML_Parser parser, unsigned long long activationThresholdBytes);
++#endif
++
+ /* Expat follows the semantic versioning convention.
+    See http://semver.org.
+ */
+diff --git a/lib/internal.h b/lib/internal.h
+index 60913dab..d8b31fa2 100644
+--- a/lib/internal.h
++++ b/lib/internal.h
+@@ -101,10 +101,40 @@
+ #  endif
+ #endif
+ 
++#include <limits.h> // ULONG_MAX
++
++#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
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
++#  else
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
++#  endif
++#else
++#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
++#  if ! defined(ULONG_MAX)
++#    error Compiler did not define ULONG_MAX for us
++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
++#  else
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
++#  endif
++#endif
++
+ #ifndef UNUSED_P
+ #  define UNUSED_P(p) (void)p
+ #endif
+ 
++/* NOTE BEGIN If you ever patch these defaults to greater values
++              for non-attack XML payload in your environment,
++              please file a bug report with libexpat.  Thank you!
++*/
++#define
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT  
\
++  100.0f
++#define
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT   
\
++  8388608 // 8 MiB, 2^23
++/* NOTE END */
++
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+diff --git a/lib/libexpat.def b/lib/libexpat.def
+index 16faf595..5aefa6df 100644
+--- a/lib/libexpat.def
++++ b/lib/libexpat.def
+@@ -76,3 +76,6 @@ EXPORTS
+   XML_SetHashSalt @67
+ ; added with version 2.2.5
+   _INTERNAL_trim_to_complete_utf8_characters @68
++; added with version 2.4.0
++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
+diff --git a/lib/libexpatw.def b/lib/libexpatw.def
+index 16faf595..5aefa6df 100644
+--- a/lib/libexpatw.def
++++ b/lib/libexpatw.def
+@@ -76,3 +76,6 @@ EXPORTS
+   XML_SetHashSalt @67
+ ; added with version 2.2.5
+   _INTERNAL_trim_to_complete_utf8_characters @68
++; added with version 2.4.0
++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
+diff --git a/lib/xmlparse.c b/lib/xmlparse.c
+index 3aaf35b9..6790bc28 100644
+--- a/lib/xmlparse.c
++++ b/lib/xmlparse.c
+@@ -47,6 +47,8 @@
+ #include <limits.h> /* UINT_MAX */
+ #include <stdio.h>  /* fprintf */
+ #include <stdlib.h> /* getenv, rand_s */
++#include <stdint.h> /* uintptr_t */
++#include <math.h>   /* isnan */
+ 
+ #ifdef _WIN32
+ #  define getpid GetCurrentProcessId
+@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
+   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+ } OPEN_INTERNAL_ENTITY;
+ 
++enum XML_Account {
++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the Expat
parser */
++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during
entity
++                                   expansion */
++  XML_ACCOUNT_NONE              /* i.e. do not account, was accounted
already */
++};
++
++#ifdef XML_DTD
++typedef unsigned long long XmlBigCount;
++typedef struct accounting {
++  XmlBigCount countBytesDirect;
++  XmlBigCount countBytesIndirect;
++  int debugLevel;
++  float maximumAmplificationFactor; // >=1.0
++  unsigned long long activationThresholdBytes;
++} ACCOUNTING;
++
++typedef struct entity_stats {
++  unsigned int countEverOpened;
++  unsigned int currentDepth;
++  unsigned int maximumDepthSeen;
++  int debugLevel;
++} ENTITY_STATS;
++#endif /* XML_DTD */
++
+ typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const
char *start,
+                                          const char *end, const char
**endPtr);
+ 
+@@ -403,16 +430,18 @@ static enum XML_Error
initializeEncoding(XML_Parser parser);
+ static enum XML_Error doProlog(XML_Parser parser, const ENCODING
*enc,
+                                const char *s, const char *end, int
tok,
+                                const char *next, const char
**nextPtr,
+-                               XML_Bool haveMore, XML_Bool
allowClosingDoctype);
++                               XML_Bool haveMore, XML_Bool
allowClosingDoctype,
++                               enum XML_Account account);
+ static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY
*entity,
+                                             XML_Bool betweenDecl);
+ static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
+                                 const ENCODING *enc, const char
*start,
+                                 const char *end, const char **endPtr,
+-                                XML_Bool haveMore);
++                                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,
+@@ -422,7 +451,8 @@ static enum XML_Error doIgnoreSection(XML_Parser
parser, const ENCODING *,
+ static void freeBindings(XML_Parser parser, BINDING *bindings);
+ static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
+                                 const char *s, TAG_NAME *tagNamePtr,
+-                                BINDING **bindingsPtr);
++                                BINDING **bindingsPtr,
++                                enum XML_Account account);
+ static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
+                                  const ATTRIBUTE_ID *attId, const
XML_Char *uri,
+                                  BINDING **bindingsPtr);
+@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE *type,
ATTRIBUTE_ID *, XML_Bool isCdata,
+                            XML_Parser parser);
+ static enum XML_Error storeAttributeValue(XML_Parser parser, const
ENCODING *,
+                                           XML_Bool isCdata, const
char *,
+-                                          const char *, STRING_POOL
*);
++                                          const char *, STRING_POOL
*,
++                                          enum XML_Account account);
+ static enum XML_Error appendAttributeValue(XML_Parser parser, const
ENCODING *,
+                                            XML_Bool isCdata, const
char *,
+-                                           const char *, STRING_POOL
*);
++                                           const char *, STRING_POOL
*,
++                                           enum XML_Account account);
+ static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING
*enc,
+                                     const char *start, const char
*end);
+ static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+ static enum XML_Error storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+-                                       const char *start, const char
*end);
++                                       const char *start, const char
*end,
++                                       enum XML_Account account);
+ static int reportProcessingInstruction(XML_Parser parser, const
ENCODING *enc,
+                                        const char *start, const char
*end);
+ static int reportComment(XML_Parser parser, const ENCODING *enc,
+@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const XML_Char
*encodingName,
+ 
+ static void parserInit(XML_Parser parser, const XML_Char
*encodingName);
+ 
++#ifdef XML_DTD
++static float accountingGetCurrentAmplification(XML_Parser
rootParser);
++static void accountingReportStats(XML_Parser originParser, const char
*epilog);
++static void accountingOnAbort(XML_Parser originParser);
++static void accountingReportDiff(XML_Parser rootParser,
++                                 unsigned int
levelsAwayFromRootParser,
++                                 const char *before, const char
*after,
++                                 ptrdiff_t bytesMore, int
source_line,
++                                 enum XML_Account account);
++static XML_Bool accountingDiffTolerated(XML_Parser originParser, int
tok,
++                                        const char *before, const
char *after,
++                                        int source_line,
++                                        enum XML_Account account);
++
++static void entityTrackingReportStats(XML_Parser parser, ENTITY
*entity,
++                                      const char *action, int
sourceLine);
++static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
++                                 int sourceLine);
++static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
++                                  int sourceLine);
++
++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,
++                                   unsigned long defaultDebugLevel);
++
+ #define poolStart(pool) ((pool)->start)
+ #define poolEnd(pool) ((pool)->ptr)
+ #define poolLength(pool) ((pool)->ptr - (pool)->start)
+@@ -616,6 +678,10 @@ struct XML_ParserStruct {
+   enum XML_ParamEntityParsing m_paramEntityParsing;
+ #endif
+   unsigned long m_hash_secret_salt;
++#ifdef XML_DTD
++  ACCOUNTING m_accounting;
++  ENTITY_STATS m_entity_stats;
++#endif
+ };
+ 
+ #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
+@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const XML_Char
*encodingName) {
+   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ #endif
+   parser->m_hash_secret_salt = 0;
++
++#ifdef XML_DTD
++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
++  parser->m_accounting.debugLevel =
getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
++  parser->m_accounting.maximumAmplificationFactor
++      =
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
++  parser->m_accounting.activationThresholdBytes
++      =
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
++
++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
++  parser->m_entity_stats.debugLevel =
getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
++#endif
+ }
+ 
+ /* moves list of bindings to m_freeBindingList */
+@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
+   /* Added in 2.2.5. */
+   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1,
already */
+     return XML_L("invalid argument");
++  /* Added in 2.4.0. */
++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
++    return XML_L(
++        "limit on input amplification factor (from DTD and entities)
breached");
+   }
+   return NULL;
+ }
+@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
+ 
+ const XML_Feature *XMLCALL
+ XML_GetFeatureList(void) {
+-  static const XML_Feature features[]
+-      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+-          sizeof(XML_Char)},
+-         {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+-          sizeof(XML_LChar)},
++  static const XML_Feature features[] = {
++      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
++       sizeof(XML_Char)},
++      {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
++       sizeof(XML_LChar)},
+ #ifdef XML_UNICODE
+-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+ #endif
+ #ifdef XML_UNICODE_WCHAR_T
+-         {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"),
0},
++      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+ #endif
+ #ifdef XML_DTD
+-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+ #endif
+ #ifdef XML_CONTEXT_BYTES
+-         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+-          XML_CONTEXT_BYTES},
++      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
++       XML_CONTEXT_BYTES},
+ #endif
+ #ifdef XML_MIN_SIZE
+-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+ #endif
+ #ifdef XML_NS
+-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+ #endif
+ #ifdef XML_LARGE_SIZE
+-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
++      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
+ #endif
+ #ifdef XML_ATTR_INFO
+-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
+ #endif
+-         {XML_FEATURE_END, NULL, 0}};
++#ifdef XML_DTD
++      /* Added in Expat 2.4.0. */
++     
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEF
AULT,
++       XML_L("XML_BLAP_MAX_AMP"),
++       (long int)
++          
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT},
++     
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFA
ULT,
++       XML_L("XML_BLAP_ACT_THRES"),
++      
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
++#endif
++      {XML_FEATURE_END, NULL, 0}};
+ 
+   return features;
+ }
+ 
++#ifdef XML_DTD
++XML_Bool XMLCALL
++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++    XML_Parser parser, float maximumAmplificationFactor) {
++  if ((parser == NULL) || (parser->m_parentParser != NULL)
++      || isnan(maximumAmplificationFactor)
++      || (maximumAmplificationFactor < 1.0f)) {
++    return XML_FALSE;
++  }
++  parser->m_accounting.maximumAmplificationFactor =
maximumAmplificationFactor;
++  return XML_TRUE;
++}
++
++XML_Bool XMLCALL
++XML_SetBillionLaughsAttackProtectionActivationThreshold(
++    XML_Parser parser, unsigned long long activationThresholdBytes) {
++  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
++    return XML_FALSE;
++  }
++  parser->m_accounting.activationThresholdBytes =
activationThresholdBytes;
++  return XML_TRUE;
++}
++#endif /* XML_DTD */
++
+ /* Initially tag->rawName always points into the parse buffer;
+    for those TAG instances opened while the current parse buffer was
+    processed, and not yet closed, we need to store tag->rawName in a
more
+@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
+ static enum XML_Error PTRCALL
+ contentProcessor(XML_Parser parser, const char *start, const char
*end,
+                  const char **endPtr) {
+-  enum XML_Error result
+-      = doContent(parser, 0, parser->m_encoding, start, end, endPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++  enum XML_Error result = doContent(
++      parser, 0, parser->m_encoding, start, end, endPtr,
++      (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_ACCOUNT_DIRECT);
+   if (result == XML_ERROR_NONE) {
+     if (! storeRawNames(parser))
+       return XML_ERROR_NO_MEMORY;
+@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser parser,
const char *start,
+   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
+   switch (tok) {
+   case XML_TOK_BOM:
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif /* XML_DTD */
++
+     /* If we are at the end of the buffer, this would cause the next
stage,
+        i.e. externalEntityInitProcessor3, to pass control directly to
+        doContent (by detecting XML_TOK_NONE) without processing any
xml text
+@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser parser,
const char *start,
+   const char *next = start; /* XmlContentTok doesn't always set the
last arg */
+   parser->m_eventPtr = start;
+   tok = XmlContentTok(parser->m_encoding, start, end, &next);
++  /* Note: These bytes are accounted later in:
++           - processXmlDecl
++           - externalEntityContentProcessor
++  */
+   parser->m_eventEndPtr = next;
+ 
+   switch (tok) {
+@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser
parser, const char *start,
+                                const char *end, const char **endPtr)
{
+   enum XML_Error result
+       = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
++                  XML_ACCOUNT_ENTITY_EXPANSION);
+   if (result == XML_ERROR_NONE) {
+     if (! storeRawNames(parser))
+       return XML_ERROR_NO_MEMORY;
+@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser
parser, const char *start,
+ static enum XML_Error
+ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+           const char *s, const char *end, const char **nextPtr,
+-          XML_Bool haveMore) {
++          XML_Bool haveMore, enum XML_Account account) {
+   /* save one level of indirection */
+   DTD *const dtd = parser->m_dtd;
+ 
+@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+   for (;;) {
+     const char *next = s; /* XmlContentTok doesn't always set the
last arg */
+     int tok = XmlContentTok(enc, s, end, &next);
++#ifdef XML_DTD
++    const char *accountAfter
++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok ==
XML_TOK_TRAILING_CR))
++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
++              : next;
++    if (! accountingDiffTolerated(parser, tok, s, accountAfter,
__LINE__,
++                                  account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     *eventEndPP = next;
+     switch (tok) {
+     case XML_TOK_TRAILING_CR:
+@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+           enc, s + enc->minBytesPerChar, next - enc-
>minBytesPerChar);
+       if (ch) {
++#ifdef XML_DTD
++        /* NOTE: We are replacing 4-6 characters original input for 1
character
++         *       so there is no amplification and hence recording
without
++         *       protection. */
++        accountingDiffTolerated(parser, tok, (char *)&ch,
++                                ((char *)&ch) + sizeof(XML_Char),
__LINE__,
++                                XML_ACCOUNT_ENTITY_EXPANSION);
++#endif /* XML_DTD */
+         if (parser->m_characterDataHandler)
+           parser->m_characterDataHandler(parser->m_handlerArg, &ch,
1);
+         else if (parser->m_defaultHandler)
+@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+       }
+       tag->name.str = (XML_Char *)tag->buf;
+       *toPtr = XML_T('\0');
+-      result = storeAtts(parser, enc, s, &(tag->name), &(tag-
>bindings));
++      result
++          = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings),
account);
+       if (result)
+         return result;
+       if (parser->m_startElementHandler)
+@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+       if (! name.str)
+         return XML_ERROR_NO_MEMORY;
+       poolFinish(&parser->m_tempPool);
+-      result = storeAtts(parser, enc, s, &name, &bindings);
++      result = storeAtts(parser, enc, s, &name, &bindings,
++                         XML_ACCOUNT_NONE /* token spans whole start
tag */);
+       if (result != XML_ERROR_NONE) {
+         freeBindings(parser, bindings);
+         return result;
+@@ -2907,7 +3057,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) {
+@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING
*bindings) {
+ */
+ static enum XML_Error
+ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
+-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
++          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
++          enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   ELEMENT_TYPE *elementType;
+   int nDefaultAtts;
+@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const ENCODING
*enc, const char *attStr,
+       /* normalize the attribute value */
+       result = storeAttributeValue(
+           parser, enc, isCdata, parser->m_atts[i].valuePtr,
+-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
++          parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
+       if (result)
+         return result;
+       appAtts[attIndex] = poolStart(&parser->m_tempPool);
+@@ -3535,9 +3687,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) {
+@@ -3557,7 +3709,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;
+@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const
ENCODING *enc, const char **startPtr,
+   for (;;) {
+     const char *next;
+     int tok = XmlCdataSectionTok(enc, s, end, &next);
++#ifdef XML_DTD
++    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) {
+     case XML_TOK_CDATA_SECT_CLOSE:
+@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const
ENCODING *enc, const char **startPtr,
+   *eventPP = s;
+   *startPtr = NULL;
+   tok = XmlIgnoreSectionTok(enc, s, end, &next);
++#  ifdef XML_DTD
++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                XML_ACCOUNT_DIRECT)) {
++    accountingOnAbort(parser);
++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++  }
++#  endif
+   *eventEndPP = next;
+   switch (tok) {
+   case XML_TOK_IGNORE_SECT:
+@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int
isGeneralTextEntity, const char *s,
+   const char *versionend;
+   const XML_Char *storedversion = NULL;
+   int standalone = -1;
++
++#ifdef XML_DTD
++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next,
__LINE__,
++                                XML_ACCOUNT_DIRECT)) {
++    accountingOnAbort(parser);
++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++  }
++#endif
++
+   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
+           isGeneralTextEntity, parser->m_encoding, s, next, &parser-
>m_eventPtr,
+           &version, &versionend, &encodingName, &newEncoding,
&standalone)) {
+@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser parser,
const char *s, const char *end,
+ 
+   for (;;) {
+     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
++    /* Note: Except for XML_TOK_BOM below, these bytes are accounted
later in:
++             - storeEntityValue
++             - processXmlDecl
++    */
+     parser->m_eventEndPtr = next;
+     if (tok <= 0) {
+       if (! parser->m_parsingStatus.finalBuffer && tok !=
XML_TOK_INVALID) {
+@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser parser,
const char *s, const char *end,
+         break;
+       }
+       /* found end of entity value - can store it now */
+-      return storeEntityValue(parser, parser->m_encoding, s, end);
++      return storeEntityValue(parser, parser->m_encoding, s, end,
++                              XML_ACCOUNT_DIRECT);
+     } else if (tok == XML_TOK_XML_DECL) {
+       enum XML_Error result;
+       result = processXmlDecl(parser, 0, start, next);
+@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser parser,
const char *s, const char *end,
+     */
+     else if (tok == XML_TOK_BOM && next == end
+              && ! parser->m_parsingStatus.finalBuffer) {
++#  ifdef XML_DTD
++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                    XML_ACCOUNT_DIRECT)) {
++        accountingOnAbort(parser);
++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      }
++#  endif
++
+       *nextPtr = next;
+       return XML_ERROR_NONE;
+     }
+@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser parser,
const char *s, const char *end,
+   }
+   /* This would cause the next stage, i.e. doProlog to be passed
XML_TOK_BOM.
+      However, when parsing an external subset, doProlog will not
accept a BOM
+-     as valid, and report a syntax error, so we have to skip the BOM
++     as valid, and report a syntax error, so we have to skip the BOM,
and
++     account for the BOM bytes.
+   */
+   else if (tok == XML_TOK_BOM) {
++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++
+     s = next;
+     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+   }
+ 
+   parser->m_processor = prologProcessor;
+   return doProlog(parser, parser->m_encoding, s, end, tok, next,
nextPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE,
++                  XML_ACCOUNT_DIRECT);
+ }
+ 
+ static enum XML_Error PTRCALL
+@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser, const
char *s, const char *end,
+ 
+   for (;;) {
+     tok = XmlPrologTok(enc, start, end, &next);
++    /* Note: These bytes are accounted later in:
++             - storeEntityValue
++    */
+     if (tok <= 0) {
+       if (! parser->m_parsingStatus.finalBuffer && tok !=
XML_TOK_INVALID) {
+         *nextPtr = s;
+@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser, const
char *s, const char *end,
+         break;
+       }
+       /* found end of entity value - can store it now */
+-      return storeEntityValue(parser, enc, s, end);
++      return storeEntityValue(parser, enc, s, end,
XML_ACCOUNT_DIRECT);
+     }
+     start = next;
+   }
+@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const char
*s, const char *end,
+   const char *next = s;
+   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+   return doProlog(parser, parser->m_encoding, s, end, tok, next,
nextPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE,
++                  XML_ACCOUNT_DIRECT);
+ }
+ 
+ static enum XML_Error
+ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const
char *end,
+          int tok, const char *next, const char **nextPtr, XML_Bool
haveMore,
+-         XML_Bool allowClosingDoctype) {
++         XML_Bool allowClosingDoctype, enum XML_Account account) {
+ #ifdef XML_DTD
+   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
+ #endif /* XML_DTD */
+@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const ENCODING
*enc, const char *s, const char *end,
+   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
+   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
+ 
++#ifndef XML_DTD
++  UNUSED_P(account);
++#endif
++
+   /* save one level of indirection */
+   DTD *const dtd = parser->m_dtd;
+ 
+@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const ENCODING
*enc, const char *s, const char *end,
+       }
+     }
+     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
++#ifdef XML_DTD
++    switch (role) {
++    case XML_ROLE_INSTANCE_START: // bytes accounted in
contentProcessor
++    case XML_ROLE_XML_DECL:       // bytes accounted in
processXmlDecl
++    case XML_ROLE_TEXT_DECL:      // bytes accounted in
processXmlDecl
++      break;
++    default:
++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
account)) {
++        accountingOnAbort(parser);
++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      }
++    }
++#endif
+     switch (role) {
+     case XML_ROLE_XML_DECL: {
+       enum XML_Error result = processXmlDecl(parser, 0, s, next);
+@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING *enc,
const char *s, const char *end,
+         const XML_Char *attVal;
+         enum XML_Error result = storeAttributeValue(
+             parser, enc, parser->m_declAttributeIsCdata,
+-            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
&dtd->pool);
++            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
&dtd->pool,
++            XML_ACCOUNT_NONE);
+         if (result)
+           return result;
+         attVal = poolStart(&dtd->pool);
+@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING *enc,
const char *s, const char *end,
+       break;
+     case XML_ROLE_ENTITY_VALUE:
+       if (dtd->keepProcessing) {
+-        enum XML_Error result = storeEntityValue(
+-            parser, enc, s + enc->minBytesPerChar, next - enc-
>minBytesPerChar);
++        enum XML_Error result
++            = storeEntityValue(parser, enc, s + enc->minBytesPerChar,
++                               next - enc->minBytesPerChar,
XML_ACCOUNT_NONE);
+         if (parser->m_declEntity) {
+           parser->m_declEntity->textPtr = poolStart(&dtd-
>entityValuePool);
+           parser->m_declEntity->textLen
+@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const ENCODING
*enc, const char *s, const char *end,
+         if (parser->m_externalEntityRefHandler) {
+           dtd->paramEntityRead = XML_FALSE;
+           entity->open = XML_TRUE;
++          entityTrackingOnOpen(parser, entity, __LINE__);
+           if (! parser->m_externalEntityRefHandler(
+                   parser->m_externalEntityRefHandlerArg, 0, entity-
>base,
+                   entity->systemId, entity->publicId)) {
++            entityTrackingOnClose(parser, entity, __LINE__);
+             entity->open = XML_FALSE;
+             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+           }
++          entityTrackingOnClose(parser, entity, __LINE__);
+           entity->open = XML_FALSE;
+           handleDefault = XML_FALSE;
+           if (! dtd->paramEntityRead) {
+@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const char
*s, const char *end,
+   for (;;) {
+     const char *next = NULL;
+     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     parser->m_eventEndPtr = next;
+     switch (tok) {
+     /* report partial linebreak - it might be the last token */
+@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser, ENTITY
*entity, XML_Bool betweenDecl) {
+       return XML_ERROR_NO_MEMORY;
+   }
+   entity->open = XML_TRUE;
++#ifdef XML_DTD
++  entityTrackingOnOpen(parser, entity, __LINE__);
++#endif
+   entity->processed = 0;
+   openEntity->next = parser->m_openInternalEntities;
+   parser->m_openInternalEntities = openEntity;
+@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser,
ENTITY *entity, XML_Bool betweenDecl) {
+     int tok
+         = XmlPrologTok(parser->m_internalEncoding, textStart,
textEnd, &next);
+     result = doProlog(parser, parser->m_internalEncoding, textStart,
textEnd,
+-                      tok, next, &next, XML_FALSE, XML_FALSE);
++                      tok, next, &next, XML_FALSE, XML_FALSE,
++                      XML_ACCOUNT_ENTITY_EXPANSION);
+   } else
+ #endif /* XML_DTD */
+     result = doContent(parser, parser->m_tagLevel, parser-
>m_internalEncoding,
+-                       textStart, textEnd, &next, XML_FALSE);
++                       textStart, textEnd, &next, XML_FALSE,
++                       XML_ACCOUNT_ENTITY_EXPANSION);
+ 
+   if (result == XML_ERROR_NONE) {
+     if (textEnd != next && parser->m_parsingStatus.parsing ==
XML_SUSPENDED) {
+       entity->processed = (int)(next - textStart);
+       parser->m_processor = internalEntityProcessor;
+     } else {
++#ifdef XML_DTD
++      entityTrackingOnClose(parser, entity, __LINE__);
++#endif /* XML_DTD */
+       entity->open = XML_FALSE;
+       parser->m_openInternalEntities = openEntity->next;
+       /* put openEntity back in list of free instances */
+@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser parser,
const char *s, const char *end,
+     int tok
+         = XmlPrologTok(parser->m_internalEncoding, textStart,
textEnd, &next);
+     result = doProlog(parser, parser->m_internalEncoding, textStart,
textEnd,
+-                      tok, next, &next, XML_FALSE, XML_TRUE);
++                      tok, next, &next, XML_FALSE, XML_TRUE,
++                      XML_ACCOUNT_ENTITY_EXPANSION);
+   } else
+ #endif /* XML_DTD */
+     result = doContent(parser, openEntity->startTagLevel,
+                        parser->m_internalEncoding, textStart,
textEnd, &next,
+-                       XML_FALSE);
++                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
+ 
+   if (result != XML_ERROR_NONE)
+     return result;
+@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser, const
char *s, const char *end,
+     entity->processed = (int)(next - (char *)entity->textPtr);
+     return result;
+   } else {
++#ifdef XML_DTD
++    entityTrackingOnClose(parser, entity, __LINE__);
++#endif
+     entity->open = XML_FALSE;
+     parser->m_openInternalEntities = openEntity->next;
+     /* put openEntity back in list of free instances */
+@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser, const
char *s, const char *end,
+     parser->m_processor = prologProcessor;
+     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+     return doProlog(parser, parser->m_encoding, s, end, tok, next,
nextPtr,
+-                    (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE);
++                    (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE,
++                    XML_ACCOUNT_DIRECT);
+   } else
+ #endif /* XML_DTD */
+   {
+@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser, const
char *s, const char *end,
+     /* see externalEntityContentProcessor vs contentProcessor */
+     return doContent(parser, parser->m_parentParser ? 1 : 0, parser-
>m_encoding,
+                      s, end, nextPtr,
+-                     (XML_Bool)! parser-
>m_parsingStatus.finalBuffer);
++                     (XML_Bool)! parser->m_parsingStatus.finalBuffer,
++                     XML_ACCOUNT_DIRECT);
+   }
+ }
+ 
+@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const char
*s, const char *end,
+ 
+ static enum XML_Error
+ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool
isCdata,
+-                    const char *ptr, const char *end, STRING_POOL
*pool) {
++                    const char *ptr, const char *end, STRING_POOL
*pool,
++                    enum XML_Account account) {
+   enum XML_Error result
+-      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
++      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool,
account);
+   if (result)
+     return result;
+   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+ 
+ static enum XML_Error
+ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool
isCdata,
+-                     const char *ptr, const char *end, STRING_POOL
*pool) {
++                     const char *ptr, const char *end, STRING_POOL
*pool,
++                     enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
++#ifndef XML_DTD
++  UNUSED_P(account);
++#endif
++
+   for (;;) {
+     const char *next;
+     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__,
account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     switch (tok) {
+     case XML_TOK_NONE:
+       return XML_ERROR_NONE;
+@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+           enc, ptr + enc->minBytesPerChar, next - enc-
>minBytesPerChar);
+       if (ch) {
++#ifdef XML_DTD
++        /* NOTE: We are replacing 4-6 characters original input for 1
character
++         *       so there is no amplification and hence recording
without
++         *       protection. */
++        accountingDiffTolerated(parser, tok, (char *)&ch,
++                                ((char *)&ch) + sizeof(XML_Char),
__LINE__,
++                                XML_ACCOUNT_ENTITY_EXPANSION);
++#endif /* XML_DTD */
+         if (! poolAppendChar(pool, ch))
+           return XML_ERROR_NO_MEMORY;
+         break;
+@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+         enum XML_Error result;
+         const XML_Char *textEnd = entity->textPtr + entity->textLen;
+         entity->open = XML_TRUE;
++#ifdef XML_DTD
++        entityTrackingOnOpen(parser, entity, __LINE__);
++#endif
+         result = appendAttributeValue(parser, parser-
>m_internalEncoding,
+-                                      isCdata, (char *)entity-
>textPtr,
+-                                      (char *)textEnd, pool);
++                                      isCdata, (const char *)entity-
>textPtr,
++                                      (const char *)textEnd, pool,
++                                      XML_ACCOUNT_ENTITY_EXPANSION);
++#ifdef XML_DTD
++        entityTrackingOnClose(parser, entity, __LINE__);
++#endif
+         entity->open = XML_FALSE;
+         if (result)
+           return result;
+@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+ 
+ static enum XML_Error
+ storeEntityValue(XML_Parser parser, const ENCODING *enc,
+-                 const char *entityTextPtr, const char
*entityTextEnd) {
++                 const char *entityTextPtr, const char
*entityTextEnd,
++                 enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   STRING_POOL *pool = &(dtd->entityValuePool);
+   enum XML_Error result = XML_ERROR_NONE;
+ #ifdef XML_DTD
+   int oldInEntityValue = parser->m_prologState.inEntityValue;
+   parser->m_prologState.inEntityValue = 1;
++#else
++  UNUSED_P(account);
+ #endif /* XML_DTD */
+   /* never return Null for the value argument in EntityDeclHandler,
+      since this would indicate an external entity; therefore we
+@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+   for (;;) {
+     const char *next;
+     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd,
&next);
++
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, entityTextPtr, next,
__LINE__,
++                                  account)) {
++      accountingOnAbort(parser);
++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      goto endEntityValue;
++    }
++#endif
++
+     switch (tok) {
+     case XML_TOK_PARAM_ENTITY_REF:
+ #ifdef XML_DTD
+@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+           if (parser->m_externalEntityRefHandler) {
+             dtd->paramEntityRead = XML_FALSE;
+             entity->open = XML_TRUE;
++            entityTrackingOnOpen(parser, entity, __LINE__);
+             if (! parser->m_externalEntityRefHandler(
+                     parser->m_externalEntityRefHandlerArg, 0, entity-
>base,
+                     entity->systemId, entity->publicId)) {
++              entityTrackingOnClose(parser, entity, __LINE__);
+               entity->open = XML_FALSE;
+               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+               goto endEntityValue;
+             }
++            entityTrackingOnClose(parser, entity, __LINE__);
+             entity->open = XML_FALSE;
+             if (! dtd->paramEntityRead)
+               dtd->keepProcessing = dtd->standalone;
+@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+             dtd->keepProcessing = dtd->standalone;
+         } else {
+           entity->open = XML_TRUE;
++          entityTrackingOnOpen(parser, entity, __LINE__);
+           result = storeEntityValue(
+-              parser, parser->m_internalEncoding, (char *)entity-
>textPtr,
+-              (char *)(entity->textPtr + entity->textLen));
++              parser, parser->m_internalEncoding, (const char
*)entity->textPtr,
++              (const char *)(entity->textPtr + entity->textLen),
++              XML_ACCOUNT_ENTITY_EXPANSION);
++          entityTrackingOnClose(parser, entity, __LINE__);
+           entity->open = XML_FALSE;
+           if (result)
+             goto endEntityValue;
+@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const
XML_Memory_Handling_Suite *memsuite) {
+   memcpy(result, s, charsRequired * sizeof(XML_Char));
+   return result;
+ }
++
++#ifdef XML_DTD
++
++static float
++accountingGetCurrentAmplification(XML_Parser rootParser) {
++  const XmlBigCount countBytesOutput
++      = rootParser->m_accounting.countBytesDirect
++        + rootParser->m_accounting.countBytesIndirect;
++  const float amplificationFactor
++      = rootParser->m_accounting.countBytesDirect
++            ? (countBytesOutput
++               / (float)(rootParser->m_accounting.countBytesDirect))
++            : 1.0f;
++  assert(! rootParser->m_parentParser);
++  return amplificationFactor;
++}
++
++static void
++accountingReportStats(XML_Parser originParser, const char *epilog) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  if (rootParser->m_accounting.debugLevel < 1) {
++    return;
++  }
++
++  const float amplificationFactor
++      = accountingGetCurrentAmplification(rootParser);
++  fprintf(stderr,
++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
++              "10") ", indirect " EXPAT_FMT_ULL("10") ",
amplification %8.2f%s",
++          (void *)rootParser, rootParser-
>m_accounting.countBytesDirect,
++          rootParser->m_accounting.countBytesIndirect,
++          (double)amplificationFactor, epilog);
++}
++
++static void
++accountingOnAbort(XML_Parser originParser) {
++  accountingReportStats(originParser, " ABORTING\n");
++}
++
++static void
++accountingReportDiff(XML_Parser rootParser,
++                     unsigned int levelsAwayFromRootParser, const
char *before,
++                     const char *after, ptrdiff_t bytesMore, int
source_line,
++                     enum XML_Account account) {
++  assert(! rootParser->m_parentParser);
++
++  fprintf(stderr,
++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d,
xmlparse.c:%d) %*s\"",
++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
++          levelsAwayFromRootParser, source_line, 10, "");
++
++  const char ellipis[] = "[..]";
++  const size_t ellipsisLength = sizeof(ellipis) /* because compile-
time */ - 1;
++  const unsigned int contextLength = 10;
++
++  /* Note: Performance is of no concern here */
++  const char *walker = before;
++  if ((rootParser->m_accounting.debugLevel >= 3)
++      || (after - before)
++             <= (ptrdiff_t)(contextLength + ellipsisLength +
contextLength)) {
++    for (; walker < after; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++  } else {
++    for (; walker < before + contextLength; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++    fprintf(stderr, ellipis);
++    walker = after - contextLength;
++    for (; walker < after; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++  }
++  fprintf(stderr, "\"\n");
++}
++
++static XML_Bool
++accountingDiffTolerated(XML_Parser originParser, int tok, const char
*before,
++                        const char *after, int source_line,
++                        enum XML_Account account) {
++  /* Note: We need to check the token type *first* to be sure that
++   *       we can even access variable <after>, safely.
++   *       E.g. for XML_TOK_NONE <after> may hold an invalid pointer.
*/
++  switch (tok) {
++  case XML_TOK_INVALID:
++  case XML_TOK_PARTIAL:
++  case XML_TOK_PARTIAL_CHAR:
++  case XML_TOK_NONE:
++    return XML_TRUE;
++  }
++
++  if (account == XML_ACCOUNT_NONE)
++    return XML_TRUE; /* because these bytes have been accounted for,
already */
++
++  unsigned int levelsAwayFromRootParser;
++  const XML_Parser rootParser
++      = getRootParserOf(originParser, &levelsAwayFromRootParser);
++  assert(! rootParser->m_parentParser);
++
++  const int isDirect
++      = (account == XML_ACCOUNT_DIRECT) && (originParser ==
rootParser);
++  const ptrdiff_t bytesMore = after - before;
++
++  XmlBigCount *const additionTarget
++      = isDirect ? &rootParser->m_accounting.countBytesDirect
++                 : &rootParser->m_accounting.countBytesIndirect;
++
++  /* Detect and avoid integer overflow */
++  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
++    return XML_FALSE;
++  *additionTarget += bytesMore;
++
++  const XmlBigCount countBytesOutput
++      = rootParser->m_accounting.countBytesDirect
++        + rootParser->m_accounting.countBytesIndirect;
++  const float amplificationFactor
++      = accountingGetCurrentAmplification(rootParser);
++  const XML_Bool tolerated
++      = (countBytesOutput < rootParser-
>m_accounting.activationThresholdBytes)
++        || (amplificationFactor
++            <= rootParser->m_accounting.maximumAmplificationFactor);
++
++  if (rootParser->m_accounting.debugLevel >= 2) {
++    accountingReportStats(rootParser, "");
++    accountingReportDiff(rootParser, levelsAwayFromRootParser,
before, after,
++                         bytesMore, source_line, account);
++  }
++
++  return tolerated;
++}
++
++static void
++entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
++                          const char *action, int sourceLine) {
++  assert(! rootParser->m_parentParser);
++  if (rootParser->m_entity_stats.debugLevel < 1)
++    return;
++
++#  if defined(XML_UNICODE)
++  const char *const entityName = "[..]";
++#  else
++  const char *const entityName = entity->name;
++#  endif
++
++  fprintf(
++      stderr,
++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s
length %d (xmlparse.c:%d)\n",
++      (void *)rootParser, rootParser->m_entity_stats.countEverOpened,
++      rootParser->m_entity_stats.currentDepth,
++      rootParser->m_entity_stats.maximumDepthSeen,
++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
++      entity->is_param ? "%" : "&", entityName, action, entity-
>textLen,
++      sourceLine);
++}
++
++static void
++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int
sourceLine) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  rootParser->m_entity_stats.countEverOpened++;
++  rootParser->m_entity_stats.currentDepth++;
++  if (rootParser->m_entity_stats.currentDepth
++      > rootParser->m_entity_stats.maximumDepthSeen) {
++    rootParser->m_entity_stats.maximumDepthSeen++;
++  }
++
++  entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine);
++}
++
++static void
++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int
sourceLine) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine);
++  rootParser->m_entity_stats.currentDepth--;
++}
++
++static XML_Parser
++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
++  XML_Parser rootParser = parser;
++  unsigned int stepsTakenUpwards = 0;
++  while (rootParser->m_parentParser) {
++    rootParser = rootParser->m_parentParser;
++    stepsTakenUpwards++;
++  }
++  assert(! rootParser->m_parentParser);
++  if (outLevelDiff != NULL) {
++    *outLevelDiff = stepsTakenUpwards;
++  }
++  return rootParser;
++}
++
++static const char *
++unsignedCharToPrintable(unsigned char c) {
++  switch (c) {
++  case 0:
++    return "\\0";
++  case 1:
++    return "\\x1";
++  case 2:
++    return "\\x2";
++  case 3:
++    return "\\x3";
++  case 4:
++    return "\\x4";
++  case 5:
++    return "\\x5";
++  case 6:
++    return "\\x6";
++  case 7:
++    return "\\x7";
++  case 8:
++    return "\\x8";
++  case 9:
++    return "\\t";
++  case 10:
++    return "\\n";
++  case 11:
++    return "\\xB";
++  case 12:
++    return "\\xC";
++  case 13:
++    return "\\r";
++  case 14:
++    return "\\xE";
++  case 15:
++    return "\\xF";
++  case 16:
++    return "\\x10";
++  case 17:
++    return "\\x11";
++  case 18:
++    return "\\x12";
++  case 19:
++    return "\\x13";
++  case 20:
++    return "\\x14";
++  case 21:
++    return "\\x15";
++  case 22:
++    return "\\x16";
++  case 23:
++    return "\\x17";
++  case 24:
++    return "\\x18";
++  case 25:
++    return "\\x19";
++  case 26:
++    return "\\x1A";
++  case 27:
++    return "\\x1B";
++  case 28:
++    return "\\x1C";
++  case 29:
++    return "\\x1D";
++  case 30:
++    return "\\x1E";
++  case 31:
++    return "\\x1F";
++  case 32:
++    return " ";
++  case 33:
++    return "!";
++  case 34:
++    return "\\\"";
++  case 35:
++    return "#";
++  case 36:
++    return "$";
++  case 37:
++    return "%";
++  case 38:
++    return "&";
++  case 39:
++    return "'";
++  case 40:
++    return "(";
++  case 41:
++    return ")";
++  case 42:
++    return "*";
++  case 43:
++    return "+";
++  case 44:
++    return ",";
++  case 45:
++    return "-";
++  case 46:
++    return ".";
++  case 47:
++    return "/";
++  case 48:
++    return "0";
++  case 49:
++    return "1";
++  case 50:
++    return "2";
++  case 51:
++    return "3";
++  case 52:
++    return "4";
++  case 53:
++    return "5";
++  case 54:
++    return "6";
++  case 55:
++    return "7";
++  case 56:
++    return "8";
++  case 57:
++    return "9";
++  case 58:
++    return ":";
++  case 59:
++    return ";";
++  case 60:
++    return "<";
++  case 61:
++    return "=";
++  case 62:
++    return ">";
++  case 63:
++    return "?";
++  case 64:
++    return "@";
++  case 65:
++    return "A";
++  case 66:
++    return "B";
++  case 67:
++    return "C";
++  case 68:
++    return "D";
++  case 69:
++    return "E";
++  case 70:
++    return "F";
++  case 71:
++    return "G";
++  case 72:
++    return "H";
++  case 73:
++    return "I";
++  case 74:
++    return "J";
++  case 75:
++    return "K";
++  case 76:
++    return "L";
++  case 77:
++    return "M";
++  case 78:
++    return "N";
++  case 79:
++    return "O";
++  case 80:
++    return "P";
++  case 81:
++    return "Q";
++  case 82:
++    return "R";
++  case 83:
++    return "S";
++  case 84:
++    return "T";
++  case 85:
++    return "U";
++  case 86:
++    return "V";
++  case 87:
++    return "W";
++  case 88:
++    return "X";
++  case 89:
++    return "Y";
++  case 90:
++    return "Z";
++  case 91:
++    return "[";
++  case 92:
++    return "\\\\";
++  case 93:
++    return "]";
++  case 94:
++    return "^";
++  case 95:
++    return "_";
++  case 96:
++    return "`";
++  case 97:
++    return "a";
++  case 98:
++    return "b";
++  case 99:
++    return "c";
++  case 100:
++    return "d";
++  case 101:
++    return "e";
++  case 102:
++    return "f";
++  case 103:
++    return "g";
++  case 104:
++    return "h";
++  case 105:
++    return "i";
++  case 106:
++    return "j";
++  case 107:
++    return "k";
++  case 108:
++    return "l";
++  case 109:
++    return "m";
++  case 110:
++    return "n";
++  case 111:
++    return "o";
++  case 112:
++    return "p";
++  case 113:
++    return "q";
++  case 114:
++    return "r";
++  case 115:
++    return "s";
++  case 116:
++    return "t";
++  case 117:
++    return "u";
++  case 118:
++    return "v";
++  case 119:
++    return "w";
++  case 120:
++    return "x";
++  case 121:
++    return "y";
++  case 122:
++    return "z";
++  case 123:
++    return "{";
++  case 124:
++    return "|";
++  case 125:
++    return "}";
++  case 126:
++    return "~";
++  case 127:
++    return "\\x7F";
++  case 128:
++    return "\\x80";
++  case 129:
++    return "\\x81";
++  case 130:
++    return "\\x82";
++  case 131:
++    return "\\x83";
++  case 132:
++    return "\\x84";
++  case 133:
++    return "\\x85";
++  case 134:
++    return "\\x86";
++  case 135:
++    return "\\x87";
++  case 136:
++    return "\\x88";
++  case 137:
++    return "\\x89";
++  case 138:
++    return "\\x8A";
++  case 139:
++    return "\\x8B";
++  case 140:
++    return "\\x8C";
++  case 141:
++    return "\\x8D";
++  case 142:
++    return "\\x8E";
++  case 143:
++    return "\\x8F";
++  case 144:
++    return "\\x90";
++  case 145:
++    return "\\x91";
++  case 146:
++    return "\\x92";
++  case 147:
++    return "\\x93";
++  case 148:
++    return "\\x94";
++  case 149:
++    return "\\x95";
++  case 150:
++    return "\\x96";
++  case 151:
++    return "\\x97";
++  case 152:
++    return "\\x98";
++  case 153:
++    return "\\x99";
++  case 154:
++    return "\\x9A";
++  case 155:
++    return "\\x9B";
++  case 156:
++    return "\\x9C";
++  case 157:
++    return "\\x9D";
++  case 158:
++    return "\\x9E";
++  case 159:
++    return "\\x9F";
++  case 160:
++    return "\\xA0";
++  case 161:
++    return "\\xA1";
++  case 162:
++    return "\\xA2";
++  case 163:
++    return "\\xA3";
++  case 164:
++    return "\\xA4";
++  case 165:
++    return "\\xA5";
++  case 166:
++    return "\\xA6";
++  case 167:
++    return "\\xA7";
++  case 168:
++    return "\\xA8";
++  case 169:
++    return "\\xA9";
++  case 170:
++    return "\\xAA";
++  case 171:
++    return "\\xAB";
++  case 172:
++    return "\\xAC";
++  case 173:
++    return "\\xAD";
++  case 174:
++    return "\\xAE";
++  case 175:
++    return "\\xAF";
++  case 176:
++    return "\\xB0";
++  case 177:
++    return "\\xB1";
++  case 178:
++    return "\\xB2";
++  case 179:
++    return "\\xB3";
++  case 180:
++    return "\\xB4";
++  case 181:
++    return "\\xB5";
++  case 182:
++    return "\\xB6";
++  case 183:
++    return "\\xB7";
++  case 184:
++    return "\\xB8";
++  case 185:
++    return "\\xB9";
++  case 186:
++    return "\\xBA";
++  case 187:
++    return "\\xBB";
++  case 188:
++    return "\\xBC";
++  case 189:
++    return "\\xBD";
++  case 190:
++    return "\\xBE";
++  case 191:
++    return "\\xBF";
++  case 192:
++    return "\\xC0";
++  case 193:
++    return "\\xC1";
++  case 194:
++    return "\\xC2";
++  case 195:
++    return "\\xC3";
++  case 196:
++    return "\\xC4";
++  case 197:
++    return "\\xC5";
++  case 198:
++    return "\\xC6";
++  case 199:
++    return "\\xC7";
++  case 200:
++    return "\\xC8";
++  case 201:
++    return "\\xC9";
++  case 202:
++    return "\\xCA";
++  case 203:
++    return "\\xCB";
++  case 204:
++    return "\\xCC";
++  case 205:
++    return "\\xCD";
++  case 206:
++    return "\\xCE";
++  case 207:
++    return "\\xCF";
++  case 208:
++    return "\\xD0";
++  case 209:
++    return "\\xD1";
++  case 210:
++    return "\\xD2";
++  case 211:
++    return "\\xD3";
++  case 212:
++    return "\\xD4";
++  case 213:
++    return "\\xD5";
++  case 214:
++    return "\\xD6";
++  case 215:
++    return "\\xD7";
++  case 216:
++    return "\\xD8";
++  case 217:
++    return "\\xD9";
++  case 218:
++    return "\\xDA";
++  case 219:
++    return "\\xDB";
++  case 220:
++    return "\\xDC";
++  case 221:
++    return "\\xDD";
++  case 222:
++    return "\\xDE";
++  case 223:
++    return "\\xDF";
++  case 224:
++    return "\\xE0";
++  case 225:
++    return "\\xE1";
++  case 226:
++    return "\\xE2";
++  case 227:
++    return "\\xE3";
++  case 228:
++    return "\\xE4";
++  case 229:
++    return "\\xE5";
++  case 230:
++    return "\\xE6";
++  case 231:
++    return "\\xE7";
++  case 232:
++    return "\\xE8";
++  case 233:
++    return "\\xE9";
++  case 234:
++    return "\\xEA";
++  case 235:
++    return "\\xEB";
++  case 236:
++    return "\\xEC";
++  case 237:
++    return "\\xED";
++  case 238:
++    return "\\xEE";
++  case 239:
++    return "\\xEF";
++  case 240:
++    return "\\xF0";
++  case 241:
++    return "\\xF1";
++  case 242:
++    return "\\xF2";
++  case 243:
++    return "\\xF3";
++  case 244:
++    return "\\xF4";
++  case 245:
++    return "\\xF5";
++  case 246:
++    return "\\xF6";
++  case 247:
++    return "\\xF7";
++  case 248:
++    return "\\xF8";
++  case 249:
++    return "\\xF9";
++  case 250:
++    return "\\xFA";
++  case 251:
++    return "\\xFB";
++  case 252:
++    return "\\xFC";
++  case 253:
++    return "\\xFD";
++  case 254:
++    return "\\xFE";
++  case 255:
++    return "\\xFF";
++  default:
++    assert(0); /* never gets here */
++    return "dead code";
++  }
++  assert(0); /* never gets here */
++}
++
++#endif /* XML_DTD */
++
++static unsigned long
++getDebugLevel(const char *variableName, unsigned long
defaultDebugLevel) {
++  const char *const valueOrNull = getenv(variableName);
++  if (valueOrNull == NULL) {
++    return defaultDebugLevel;
++  }
++  const char *const value = valueOrNull;
++
++  errno = 0;
++  char *afterValue = (char *)value;
++  unsigned long debugLevel = strtoul(value, &afterValue, 10);
++  if ((errno != 0) || (afterValue[0] != '\0')) {
++    errno = 0;
++    return defaultDebugLevel;
++  }
++
++  return debugLevel;
++}
+-- 
+2.32.0
+
diff --git a/meta/recipes-core/expat/expat/libtool-tag.patch
b/meta/recipes-core/expat/expat/libtool-tag.patch
index 0a0aed23e5..203415a725 100644
--- a/meta/recipes-core/expat/expat/libtool-tag.patch
+++ b/meta/recipes-core/expat/expat/libtool-tag.patch
@@ -1,30 +1,27 @@
-From 10342e6b600858b091bc7771e454d9e06af06410 Mon Sep 17 00:00:00 2001
-From: Khem Raj <raj.khem@gmail.com>
-Date: Thu, 2 Nov 2017 18:20:57 +0800
+From da433dbe79f2d4d5d7d79869c669594c99c5de9c Mon Sep 17 00:00:00 2001
+From: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
+Date: Wed, 16 Jun 2021 19:00:30 +0200
 Subject: [PATCH] Add CC tag to build
 
-Add CC tag to build
-
 Upstream-Status: Pending
-Signed-off-by: Khem Raj <raj.khem@gmail.com>
-Signed-off-by: Dengke Du <dengke.du@windriver.com>
+Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
 ---
- Makefile.in | 2 +-
+ Makefile.am | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
-diff --git a/Makefile.in b/Makefile.in
-index 9560a95..d444bd6 100644
---- a/Makefile.in
-+++ b/Makefile.in
-@@ -319,7 +319,7 @@ LIBCURRENT = @LIBCURRENT@
- LIBOBJS = @LIBOBJS@
- LIBREVISION = @LIBREVISION@
- LIBS = @LIBS@
--LIBTOOL = @LIBTOOL@
-+LIBTOOL = @LIBTOOL@ --tag CC
- LIPO = @LIPO@
- LN_S = @LN_S@
- LTLIBOBJS = @LTLIBOBJS@
+diff --git a/Makefile.am b/Makefile.am
+index 5e1d37dd..f7a6dece 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -36,7 +36,7 @@ AUTOMAKE_OPTIONS = \
+     subdir-objects
+ 
+ ACLOCAL_AMFLAGS = -I m4
+-LIBTOOLFLAGS = --verbose
++LIBTOOLFLAGS = --verbose --tag=CC
+ 
+ SUBDIRS = lib # lib goes first to build first
+ if WITH_EXAMPLES
 -- 
-2.7.4
+2.32.0
 
diff --git a/meta/recipes-core/expat/expat_2.2.9.bb b/meta/recipes-
core/expat/expat_2.2.9.bb
index 174bf4be1f..cd38df91d9 100644
--- a/meta/recipes-core/expat/expat_2.2.9.bb
+++ b/meta/recipes-core/expat/expat_2.2.9.bb
@@ -6,18 +6,16 @@ LICENSE = "MIT"
 
 LIC_FILES_CHKSUM =
"file://COPYING;md5=5b8620d98e49772d95fc1d291c26aa79"
 
-SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}.tar.bz2 \
+SRC_URI = "git://github.com/libexpat/libexpat.git;protocol=https \
+           file://CVE-2013-0340.patch \
            file://libtool-tag.patch \
-	  "
+         "
 
-SRC_URI[md5sum] = "875a2c2ff3e8eb9e5a5cd62db2033ab5"
-SRC_URI[sha256sum] =
"f1063084dc4302a427dabcca499c8312b3a32a29b7d2506653ecc8f950a9a237"
+SRCREV = "a7bc26b69768f7fb24f0c7976fae24b157b85b13"
 
 inherit autotools lib_package
 
-do_configure_prepend () {
-	rm -f ${S}/conftools/libtool.m4
-}
+S = "${WORKDIR}/git/expat"
 
 BBCLASSEXTEND = "native nativesdk"
 
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
@ 2021-06-17 15:20 Jasper Orschulko
  0 siblings, 0 replies; 11+ messages in thread
From: Jasper Orschulko @ 2021-06-17 15:20 UTC (permalink / raw)
  To: openembedded-core, steve, Jasper.Orschulko

expat < 4.0 is vulnerable to billion laughs attacks (see
[https://github.com/libexpat/libexpat/issues/34]). This patch backports
the commits b1d039607d3d8a042bf0466bfcc1c0f104e353c8
and 60959f2b491876199879d97c8ed956eabb0c2e73 from upstream.

Additionally, the SRC_URI had to be adjusted due to renaming of the
source archive

Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>

Upstream-Status: Submitted [https://lists.openembedded.org/g/openembedded-core/message/153030?p=,,,20,0,0,0::Created,,Jasper,20,2,0,83581993]
---
 .../expat/expat/CVE-2013-0340.patch           | 1758 +++++++++++++++++
 .../expat/expat/libtool-tag.patch             |   41 +-
 meta/recipes-core/expat/expat_2.2.9.bb        |   12 +-
 3 files changed, 1782 insertions(+), 29 deletions(-)
 create mode 100644 meta/recipes-core/expat/expat/CVE-2013-0340.patch

diff --git a/meta/recipes-core/expat/expat/CVE-2013-0340.patch b/meta/recipes-core/expat/expat/CVE-2013-0340.patch
new file mode 100644
index 0000000000..5ef749719d
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2013-0340.patch
@@ -0,0 +1,1758 @@
+From a644ccf25392523b1329872310e24d0fc5f40629 Mon Sep 17 00:00:00 2001
+From: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon, 19 Apr 2021 21:42:51 +0200
+Subject: [PATCH] expat: Backport fix for CVE-2013-0340
+
+Issue: https://github.com/libexpat/libexpat/issues/34
+
+This patch cherry-picks the following commits from upstream release
+2.4.0 onto 2.2.9:
+
+- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
+- 60959f2b491876199879d97c8ed956eabb0c2e73
+
+Upstream-Status: Backport
+CVE: CVE-2013-0340
+Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
+---
+ lib/expat.h       |   21 +-
+ lib/internal.h    |   30 +
+ lib/libexpat.def  |    3 +
+ lib/libexpatw.def |    3 +
+ lib/xmlparse.c    | 1147 +++++++++++++++++++++++++++++++++++++--
+ 5 files changed, 1143 insertions(+), 61 deletions(-)
+
+diff --git a/lib/expat.h b/lib/expat.h
+index 48a6e2a3..0fb70d9d 100644
+--- a/lib/expat.h
++++ b/lib/expat.h
+@@ -115,7 +115,9 @@ enum XML_Error {
+   XML_ERROR_RESERVED_PREFIX_XMLNS,
+   XML_ERROR_RESERVED_NAMESPACE_URI,
+   /* Added in 2.2.1. */
+-  XML_ERROR_INVALID_ARGUMENT
++  XML_ERROR_INVALID_ARGUMENT,
++  /* Added in 2.4.0. */
++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
+ };
+ 
+ enum XML_Content_Type {
+@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
+   XML_FEATURE_SIZEOF_XML_LCHAR,
+   XML_FEATURE_NS,
+   XML_FEATURE_LARGE_SIZE,
+-  XML_FEATURE_ATTR_INFO
++  XML_FEATURE_ATTR_INFO,
++  /* Added in Expat 2.4.0. */
++  XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
++  XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT
+   /* Additional features must be added to the end of this enum. */
+ };
+ 
+@@ -1010,6 +1015,18 @@ typedef struct {
+ XMLPARSEAPI(const XML_Feature *)
+ XML_GetFeatureList(void);
+ 
++#ifdef XML_DTD
++/* Added in Expat 2.4.0. */
++XMLPARSEAPI(XML_Bool)
++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++    XML_Parser parser, float maximumAmplificationFactor);
++
++/* Added in Expat 2.4.0. */
++XMLPARSEAPI(XML_Bool)
++XML_SetBillionLaughsAttackProtectionActivationThreshold(
++    XML_Parser parser, unsigned long long activationThresholdBytes);
++#endif
++
+ /* Expat follows the semantic versioning convention.
+    See http://semver.org.
+ */
+diff --git a/lib/internal.h b/lib/internal.h
+index 60913dab..d8b31fa2 100644
+--- a/lib/internal.h
++++ b/lib/internal.h
+@@ -101,10 +101,40 @@
+ #  endif
+ #endif
+ 
++#include <limits.h> // ULONG_MAX
++
++#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
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
++#  else
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
++#  endif
++#else
++#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
++#  if ! defined(ULONG_MAX)
++#    error Compiler did not define ULONG_MAX for us
++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
++#  else
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
++#  endif
++#endif
++
+ #ifndef UNUSED_P
+ #  define UNUSED_P(p) (void)p
+ #endif
+ 
++/* NOTE BEGIN If you ever patch these defaults to greater values
++              for non-attack XML payload in your environment,
++              please file a bug report with libexpat.  Thank you!
++*/
++#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT   \
++  100.0f
++#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT    \
++  8388608 // 8 MiB, 2^23
++/* NOTE END */
++
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+diff --git a/lib/libexpat.def b/lib/libexpat.def
+index 16faf595..5aefa6df 100644
+--- a/lib/libexpat.def
++++ b/lib/libexpat.def
+@@ -76,3 +76,6 @@ EXPORTS
+   XML_SetHashSalt @67
+ ; added with version 2.2.5
+   _INTERNAL_trim_to_complete_utf8_characters @68
++; added with version 2.4.0
++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
+diff --git a/lib/libexpatw.def b/lib/libexpatw.def
+index 16faf595..5aefa6df 100644
+--- a/lib/libexpatw.def
++++ b/lib/libexpatw.def
+@@ -76,3 +76,6 @@ EXPORTS
+   XML_SetHashSalt @67
+ ; added with version 2.2.5
+   _INTERNAL_trim_to_complete_utf8_characters @68
++; added with version 2.4.0
++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
+diff --git a/lib/xmlparse.c b/lib/xmlparse.c
+index 3aaf35b9..6790bc28 100644
+--- a/lib/xmlparse.c
++++ b/lib/xmlparse.c
+@@ -47,6 +47,8 @@
+ #include <limits.h> /* UINT_MAX */
+ #include <stdio.h>  /* fprintf */
+ #include <stdlib.h> /* getenv, rand_s */
++#include <stdint.h> /* uintptr_t */
++#include <math.h>   /* isnan */
+ 
+ #ifdef _WIN32
+ #  define getpid GetCurrentProcessId
+@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
+   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+ } OPEN_INTERNAL_ENTITY;
+ 
++enum XML_Account {
++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the Expat parser */
++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during entity
++                                   expansion */
++  XML_ACCOUNT_NONE              /* i.e. do not account, was accounted already */
++};
++
++#ifdef XML_DTD
++typedef unsigned long long XmlBigCount;
++typedef struct accounting {
++  XmlBigCount countBytesDirect;
++  XmlBigCount countBytesIndirect;
++  int debugLevel;
++  float maximumAmplificationFactor; // >=1.0
++  unsigned long long activationThresholdBytes;
++} ACCOUNTING;
++
++typedef struct entity_stats {
++  unsigned int countEverOpened;
++  unsigned int currentDepth;
++  unsigned int maximumDepthSeen;
++  int debugLevel;
++} ENTITY_STATS;
++#endif /* XML_DTD */
++
+ typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
+                                          const char *end, const char **endPtr);
+ 
+@@ -403,16 +430,18 @@ static enum XML_Error initializeEncoding(XML_Parser parser);
+ static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
+                                const char *s, const char *end, int tok,
+                                const char *next, const char **nextPtr,
+-                               XML_Bool haveMore, XML_Bool allowClosingDoctype);
++                               XML_Bool haveMore, XML_Bool allowClosingDoctype,
++                               enum XML_Account account);
+ static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
+                                             XML_Bool betweenDecl);
+ static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
+                                 const ENCODING *enc, const char *start,
+                                 const char *end, const char **endPtr,
+-                                XML_Bool haveMore);
++                                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,
+@@ -422,7 +451,8 @@ static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
+ static void freeBindings(XML_Parser parser, BINDING *bindings);
+ static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
+                                 const char *s, TAG_NAME *tagNamePtr,
+-                                BINDING **bindingsPtr);
++                                BINDING **bindingsPtr,
++                                enum XML_Account account);
+ static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
+                                  const ATTRIBUTE_ID *attId, const XML_Char *uri,
+                                  BINDING **bindingsPtr);
+@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
+                            XML_Parser parser);
+ static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *,
+                                           XML_Bool isCdata, const char *,
+-                                          const char *, STRING_POOL *);
++                                          const char *, STRING_POOL *,
++                                          enum XML_Account account);
+ static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
+                                            XML_Bool isCdata, const char *,
+-                                           const char *, STRING_POOL *);
++                                           const char *, STRING_POOL *,
++                                           enum XML_Account account);
+ static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
+                                     const char *start, const char *end);
+ static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+ static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
+-                                       const char *start, const char *end);
++                                       const char *start, const char *end,
++                                       enum XML_Account account);
+ static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+                                        const char *start, const char *end);
+ static int reportComment(XML_Parser parser, const ENCODING *enc,
+@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const XML_Char *encodingName,
+ 
+ static void parserInit(XML_Parser parser, const XML_Char *encodingName);
+ 
++#ifdef XML_DTD
++static float accountingGetCurrentAmplification(XML_Parser rootParser);
++static void accountingReportStats(XML_Parser originParser, const char *epilog);
++static void accountingOnAbort(XML_Parser originParser);
++static void accountingReportDiff(XML_Parser rootParser,
++                                 unsigned int levelsAwayFromRootParser,
++                                 const char *before, const char *after,
++                                 ptrdiff_t bytesMore, int source_line,
++                                 enum XML_Account account);
++static XML_Bool accountingDiffTolerated(XML_Parser originParser, int tok,
++                                        const char *before, const char *after,
++                                        int source_line,
++                                        enum XML_Account account);
++
++static void entityTrackingReportStats(XML_Parser parser, ENTITY *entity,
++                                      const char *action, int sourceLine);
++static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
++                                 int sourceLine);
++static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
++                                  int sourceLine);
++
++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,
++                                   unsigned long defaultDebugLevel);
++
+ #define poolStart(pool) ((pool)->start)
+ #define poolEnd(pool) ((pool)->ptr)
+ #define poolLength(pool) ((pool)->ptr - (pool)->start)
+@@ -616,6 +678,10 @@ struct XML_ParserStruct {
+   enum XML_ParamEntityParsing m_paramEntityParsing;
+ #endif
+   unsigned long m_hash_secret_salt;
++#ifdef XML_DTD
++  ACCOUNTING m_accounting;
++  ENTITY_STATS m_entity_stats;
++#endif
+ };
+ 
+ #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
+@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
+   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ #endif
+   parser->m_hash_secret_salt = 0;
++
++#ifdef XML_DTD
++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
++  parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
++  parser->m_accounting.maximumAmplificationFactor
++      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
++  parser->m_accounting.activationThresholdBytes
++      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
++
++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
++  parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
++#endif
+ }
+ 
+ /* moves list of bindings to m_freeBindingList */
+@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
+   /* Added in 2.2.5. */
+   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
+     return XML_L("invalid argument");
++  /* Added in 2.4.0. */
++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
++    return XML_L(
++        "limit on input amplification factor (from DTD and entities) breached");
+   }
+   return NULL;
+ }
+@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
+ 
+ const XML_Feature *XMLCALL
+ XML_GetFeatureList(void) {
+-  static const XML_Feature features[]
+-      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+-          sizeof(XML_Char)},
+-         {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+-          sizeof(XML_LChar)},
++  static const XML_Feature features[] = {
++      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
++       sizeof(XML_Char)},
++      {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
++       sizeof(XML_LChar)},
+ #ifdef XML_UNICODE
+-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+ #endif
+ #ifdef XML_UNICODE_WCHAR_T
+-         {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
++      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+ #endif
+ #ifdef XML_DTD
+-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+ #endif
+ #ifdef XML_CONTEXT_BYTES
+-         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+-          XML_CONTEXT_BYTES},
++      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
++       XML_CONTEXT_BYTES},
+ #endif
+ #ifdef XML_MIN_SIZE
+-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+ #endif
+ #ifdef XML_NS
+-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+ #endif
+ #ifdef XML_LARGE_SIZE
+-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
++      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
+ #endif
+ #ifdef XML_ATTR_INFO
+-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
+ #endif
+-         {XML_FEATURE_END, NULL, 0}};
++#ifdef XML_DTD
++      /* Added in Expat 2.4.0. */
++      {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
++       XML_L("XML_BLAP_MAX_AMP"),
++       (long int)
++           EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT},
++      {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
++       XML_L("XML_BLAP_ACT_THRES"),
++       EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
++#endif
++      {XML_FEATURE_END, NULL, 0}};
+ 
+   return features;
+ }
+ 
++#ifdef XML_DTD
++XML_Bool XMLCALL
++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++    XML_Parser parser, float maximumAmplificationFactor) {
++  if ((parser == NULL) || (parser->m_parentParser != NULL)
++      || isnan(maximumAmplificationFactor)
++      || (maximumAmplificationFactor < 1.0f)) {
++    return XML_FALSE;
++  }
++  parser->m_accounting.maximumAmplificationFactor = maximumAmplificationFactor;
++  return XML_TRUE;
++}
++
++XML_Bool XMLCALL
++XML_SetBillionLaughsAttackProtectionActivationThreshold(
++    XML_Parser parser, unsigned long long activationThresholdBytes) {
++  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
++    return XML_FALSE;
++  }
++  parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
++  return XML_TRUE;
++}
++#endif /* XML_DTD */
++
+ /* Initially tag->rawName always points into the parse buffer;
+    for those TAG instances opened while the current parse buffer was
+    processed, and not yet closed, we need to store tag->rawName in a more
+@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
+ static enum XML_Error PTRCALL
+ contentProcessor(XML_Parser parser, const char *start, const char *end,
+                  const char **endPtr) {
+-  enum XML_Error result
+-      = doContent(parser, 0, parser->m_encoding, start, end, endPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++  enum XML_Error result = doContent(
++      parser, 0, parser->m_encoding, start, end, endPtr,
++      (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
+   if (result == XML_ERROR_NONE) {
+     if (! storeRawNames(parser))
+       return XML_ERROR_NO_MEMORY;
+@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser parser, const char *start,
+   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
+   switch (tok) {
+   case XML_TOK_BOM:
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif /* XML_DTD */
++
+     /* If we are at the end of the buffer, this would cause the next stage,
+        i.e. externalEntityInitProcessor3, to pass control directly to
+        doContent (by detecting XML_TOK_NONE) without processing any xml text
+@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser parser, const char *start,
+   const char *next = start; /* XmlContentTok doesn't always set the last arg */
+   parser->m_eventPtr = start;
+   tok = XmlContentTok(parser->m_encoding, start, end, &next);
++  /* Note: These bytes are accounted later in:
++           - processXmlDecl
++           - externalEntityContentProcessor
++  */
+   parser->m_eventEndPtr = next;
+ 
+   switch (tok) {
+@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser parser, const char *start,
+                                const char *end, const char **endPtr) {
+   enum XML_Error result
+       = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
++                  XML_ACCOUNT_ENTITY_EXPANSION);
+   if (result == XML_ERROR_NONE) {
+     if (! storeRawNames(parser))
+       return XML_ERROR_NO_MEMORY;
+@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser parser, const char *start,
+ static enum XML_Error
+ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+           const char *s, const char *end, const char **nextPtr,
+-          XML_Bool haveMore) {
++          XML_Bool haveMore, enum XML_Account account) {
+   /* save one level of indirection */
+   DTD *const dtd = parser->m_dtd;
+ 
+@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+   for (;;) {
+     const char *next = s; /* XmlContentTok doesn't always set the last arg */
+     int tok = XmlContentTok(enc, s, end, &next);
++#ifdef XML_DTD
++    const char *accountAfter
++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR))
++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
++              : next;
++    if (! accountingDiffTolerated(parser, tok, s, accountAfter, __LINE__,
++                                  account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     *eventEndPP = next;
+     switch (tok) {
+     case XML_TOK_TRAILING_CR:
+@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+           enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
+       if (ch) {
++#ifdef XML_DTD
++        /* NOTE: We are replacing 4-6 characters original input for 1 character
++         *       so there is no amplification and hence recording without
++         *       protection. */
++        accountingDiffTolerated(parser, tok, (char *)&ch,
++                                ((char *)&ch) + sizeof(XML_Char), __LINE__,
++                                XML_ACCOUNT_ENTITY_EXPANSION);
++#endif /* XML_DTD */
+         if (parser->m_characterDataHandler)
+           parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
+         else if (parser->m_defaultHandler)
+@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+       }
+       tag->name.str = (XML_Char *)tag->buf;
+       *toPtr = XML_T('\0');
+-      result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
++      result
++          = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account);
+       if (result)
+         return result;
+       if (parser->m_startElementHandler)
+@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+       if (! name.str)
+         return XML_ERROR_NO_MEMORY;
+       poolFinish(&parser->m_tempPool);
+-      result = storeAtts(parser, enc, s, &name, &bindings);
++      result = storeAtts(parser, enc, s, &name, &bindings,
++                         XML_ACCOUNT_NONE /* token spans whole start tag */);
+       if (result != XML_ERROR_NONE) {
+         freeBindings(parser, bindings);
+         return result;
+@@ -2907,7 +3057,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) {
+@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING *bindings) {
+ */
+ static enum XML_Error
+ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
+-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
++          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
++          enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   ELEMENT_TYPE *elementType;
+   int nDefaultAtts;
+@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
+       /* normalize the attribute value */
+       result = storeAttributeValue(
+           parser, enc, isCdata, parser->m_atts[i].valuePtr,
+-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
++          parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
+       if (result)
+         return result;
+       appAtts[attIndex] = poolStart(&parser->m_tempPool);
+@@ -3535,9 +3687,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) {
+@@ -3557,7 +3709,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;
+@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
+   for (;;) {
+     const char *next;
+     int tok = XmlCdataSectionTok(enc, s, end, &next);
++#ifdef XML_DTD
++    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) {
+     case XML_TOK_CDATA_SECT_CLOSE:
+@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
+   *eventPP = s;
+   *startPtr = NULL;
+   tok = XmlIgnoreSectionTok(enc, s, end, &next);
++#  ifdef XML_DTD
++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                XML_ACCOUNT_DIRECT)) {
++    accountingOnAbort(parser);
++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++  }
++#  endif
+   *eventEndPP = next;
+   switch (tok) {
+   case XML_TOK_IGNORE_SECT:
+@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s,
+   const char *versionend;
+   const XML_Char *storedversion = NULL;
+   int standalone = -1;
++
++#ifdef XML_DTD
++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__,
++                                XML_ACCOUNT_DIRECT)) {
++    accountingOnAbort(parser);
++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++  }
++#endif
++
+   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
+           isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr,
+           &version, &versionend, &encodingName, &newEncoding, &standalone)) {
+@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
+ 
+   for (;;) {
+     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
++    /* Note: Except for XML_TOK_BOM below, these bytes are accounted later in:
++             - storeEntityValue
++             - processXmlDecl
++    */
+     parser->m_eventEndPtr = next;
+     if (tok <= 0) {
+       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
+@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
+         break;
+       }
+       /* found end of entity value - can store it now */
+-      return storeEntityValue(parser, parser->m_encoding, s, end);
++      return storeEntityValue(parser, parser->m_encoding, s, end,
++                              XML_ACCOUNT_DIRECT);
+     } else if (tok == XML_TOK_XML_DECL) {
+       enum XML_Error result;
+       result = processXmlDecl(parser, 0, start, next);
+@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
+     */
+     else if (tok == XML_TOK_BOM && next == end
+              && ! parser->m_parsingStatus.finalBuffer) {
++#  ifdef XML_DTD
++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                    XML_ACCOUNT_DIRECT)) {
++        accountingOnAbort(parser);
++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      }
++#  endif
++
+       *nextPtr = next;
+       return XML_ERROR_NONE;
+     }
+@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser parser, const char *s, const char *end,
+   }
+   /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
+      However, when parsing an external subset, doProlog will not accept a BOM
+-     as valid, and report a syntax error, so we have to skip the BOM
++     as valid, and report a syntax error, so we have to skip the BOM, and
++     account for the BOM bytes.
+   */
+   else if (tok == XML_TOK_BOM) {
++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++
+     s = next;
+     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+   }
+ 
+   parser->m_processor = prologProcessor;
+   return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
++                  XML_ACCOUNT_DIRECT);
+ }
+ 
+ static enum XML_Error PTRCALL
+@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
+ 
+   for (;;) {
+     tok = XmlPrologTok(enc, start, end, &next);
++    /* Note: These bytes are accounted later in:
++             - storeEntityValue
++    */
+     if (tok <= 0) {
+       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
+         *nextPtr = s;
+@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
+         break;
+       }
+       /* found end of entity value - can store it now */
+-      return storeEntityValue(parser, enc, s, end);
++      return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT);
+     }
+     start = next;
+   }
+@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const char *s, const char *end,
+   const char *next = s;
+   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+   return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
++                  XML_ACCOUNT_DIRECT);
+ }
+ 
+ static enum XML_Error
+ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
+          int tok, const char *next, const char **nextPtr, XML_Bool haveMore,
+-         XML_Bool allowClosingDoctype) {
++         XML_Bool allowClosingDoctype, enum XML_Account account) {
+ #ifdef XML_DTD
+   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
+ #endif /* XML_DTD */
+@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
+   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
+   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
+ 
++#ifndef XML_DTD
++  UNUSED_P(account);
++#endif
++
+   /* save one level of indirection */
+   DTD *const dtd = parser->m_dtd;
+ 
+@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
+       }
+     }
+     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
++#ifdef XML_DTD
++    switch (role) {
++    case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor
++    case XML_ROLE_XML_DECL:       // bytes accounted in processXmlDecl
++    case XML_ROLE_TEXT_DECL:      // bytes accounted in processXmlDecl
++      break;
++    default:
++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
++        accountingOnAbort(parser);
++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      }
++    }
++#endif
+     switch (role) {
+     case XML_ROLE_XML_DECL: {
+       enum XML_Error result = processXmlDecl(parser, 0, s, next);
+@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
+         const XML_Char *attVal;
+         enum XML_Error result = storeAttributeValue(
+             parser, enc, parser->m_declAttributeIsCdata,
+-            s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool);
++            s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool,
++            XML_ACCOUNT_NONE);
+         if (result)
+           return result;
+         attVal = poolStart(&dtd->pool);
+@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
+       break;
+     case XML_ROLE_ENTITY_VALUE:
+       if (dtd->keepProcessing) {
+-        enum XML_Error result = storeEntityValue(
+-            parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
++        enum XML_Error result
++            = storeEntityValue(parser, enc, s + enc->minBytesPerChar,
++                               next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
+         if (parser->m_declEntity) {
+           parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
+           parser->m_declEntity->textLen
+@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
+         if (parser->m_externalEntityRefHandler) {
+           dtd->paramEntityRead = XML_FALSE;
+           entity->open = XML_TRUE;
++          entityTrackingOnOpen(parser, entity, __LINE__);
+           if (! parser->m_externalEntityRefHandler(
+                   parser->m_externalEntityRefHandlerArg, 0, entity->base,
+                   entity->systemId, entity->publicId)) {
++            entityTrackingOnClose(parser, entity, __LINE__);
+             entity->open = XML_FALSE;
+             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+           }
++          entityTrackingOnClose(parser, entity, __LINE__);
+           entity->open = XML_FALSE;
+           handleDefault = XML_FALSE;
+           if (! dtd->paramEntityRead) {
+@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
+   for (;;) {
+     const char *next = NULL;
+     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     parser->m_eventEndPtr = next;
+     switch (tok) {
+     /* report partial linebreak - it might be the last token */
+@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
+       return XML_ERROR_NO_MEMORY;
+   }
+   entity->open = XML_TRUE;
++#ifdef XML_DTD
++  entityTrackingOnOpen(parser, entity, __LINE__);
++#endif
+   entity->processed = 0;
+   openEntity->next = parser->m_openInternalEntities;
+   parser->m_openInternalEntities = openEntity;
+@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
+     int tok
+         = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
+     result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
+-                      tok, next, &next, XML_FALSE, XML_FALSE);
++                      tok, next, &next, XML_FALSE, XML_FALSE,
++                      XML_ACCOUNT_ENTITY_EXPANSION);
+   } else
+ #endif /* XML_DTD */
+     result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
+-                       textStart, textEnd, &next, XML_FALSE);
++                       textStart, textEnd, &next, XML_FALSE,
++                       XML_ACCOUNT_ENTITY_EXPANSION);
+ 
+   if (result == XML_ERROR_NONE) {
+     if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
+       entity->processed = (int)(next - textStart);
+       parser->m_processor = internalEntityProcessor;
+     } else {
++#ifdef XML_DTD
++      entityTrackingOnClose(parser, entity, __LINE__);
++#endif /* XML_DTD */
+       entity->open = XML_FALSE;
+       parser->m_openInternalEntities = openEntity->next;
+       /* put openEntity back in list of free instances */
+@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
+     int tok
+         = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
+     result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
+-                      tok, next, &next, XML_FALSE, XML_TRUE);
++                      tok, next, &next, XML_FALSE, XML_TRUE,
++                      XML_ACCOUNT_ENTITY_EXPANSION);
+   } else
+ #endif /* XML_DTD */
+     result = doContent(parser, openEntity->startTagLevel,
+                        parser->m_internalEncoding, textStart, textEnd, &next,
+-                       XML_FALSE);
++                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
+ 
+   if (result != XML_ERROR_NONE)
+     return result;
+@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
+     entity->processed = (int)(next - (char *)entity->textPtr);
+     return result;
+   } else {
++#ifdef XML_DTD
++    entityTrackingOnClose(parser, entity, __LINE__);
++#endif
+     entity->open = XML_FALSE;
+     parser->m_openInternalEntities = openEntity->next;
+     /* put openEntity back in list of free instances */
+@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
+     parser->m_processor = prologProcessor;
+     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+     return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
+-                    (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
++                    (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
++                    XML_ACCOUNT_DIRECT);
+   } else
+ #endif /* XML_DTD */
+   {
+@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
+     /* see externalEntityContentProcessor vs contentProcessor */
+     return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding,
+                      s, end, nextPtr,
+-                     (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++                     (XML_Bool)! parser->m_parsingStatus.finalBuffer,
++                     XML_ACCOUNT_DIRECT);
+   }
+ }
+ 
+@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const char *s, const char *end,
+ 
+ static enum XML_Error
+ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+-                    const char *ptr, const char *end, STRING_POOL *pool) {
++                    const char *ptr, const char *end, STRING_POOL *pool,
++                    enum XML_Account account) {
+   enum XML_Error result
+-      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
++      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool, account);
+   if (result)
+     return result;
+   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+ 
+ static enum XML_Error
+ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+-                     const char *ptr, const char *end, STRING_POOL *pool) {
++                     const char *ptr, const char *end, STRING_POOL *pool,
++                     enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
++#ifndef XML_DTD
++  UNUSED_P(account);
++#endif
++
+   for (;;) {
+     const char *next;
+     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     switch (tok) {
+     case XML_TOK_NONE:
+       return XML_ERROR_NONE;
+@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+           enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
+       if (ch) {
++#ifdef XML_DTD
++        /* NOTE: We are replacing 4-6 characters original input for 1 character
++         *       so there is no amplification and hence recording without
++         *       protection. */
++        accountingDiffTolerated(parser, tok, (char *)&ch,
++                                ((char *)&ch) + sizeof(XML_Char), __LINE__,
++                                XML_ACCOUNT_ENTITY_EXPANSION);
++#endif /* XML_DTD */
+         if (! poolAppendChar(pool, ch))
+           return XML_ERROR_NO_MEMORY;
+         break;
+@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+         enum XML_Error result;
+         const XML_Char *textEnd = entity->textPtr + entity->textLen;
+         entity->open = XML_TRUE;
++#ifdef XML_DTD
++        entityTrackingOnOpen(parser, entity, __LINE__);
++#endif
+         result = appendAttributeValue(parser, parser->m_internalEncoding,
+-                                      isCdata, (char *)entity->textPtr,
+-                                      (char *)textEnd, pool);
++                                      isCdata, (const char *)entity->textPtr,
++                                      (const char *)textEnd, pool,
++                                      XML_ACCOUNT_ENTITY_EXPANSION);
++#ifdef XML_DTD
++        entityTrackingOnClose(parser, entity, __LINE__);
++#endif
+         entity->open = XML_FALSE;
+         if (result)
+           return result;
+@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+ 
+ static enum XML_Error
+ storeEntityValue(XML_Parser parser, const ENCODING *enc,
+-                 const char *entityTextPtr, const char *entityTextEnd) {
++                 const char *entityTextPtr, const char *entityTextEnd,
++                 enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   STRING_POOL *pool = &(dtd->entityValuePool);
+   enum XML_Error result = XML_ERROR_NONE;
+ #ifdef XML_DTD
+   int oldInEntityValue = parser->m_prologState.inEntityValue;
+   parser->m_prologState.inEntityValue = 1;
++#else
++  UNUSED_P(account);
+ #endif /* XML_DTD */
+   /* never return Null for the value argument in EntityDeclHandler,
+      since this would indicate an external entity; therefore we
+@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
+   for (;;) {
+     const char *next;
+     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
++
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, entityTextPtr, next, __LINE__,
++                                  account)) {
++      accountingOnAbort(parser);
++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      goto endEntityValue;
++    }
++#endif
++
+     switch (tok) {
+     case XML_TOK_PARAM_ENTITY_REF:
+ #ifdef XML_DTD
+@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
+           if (parser->m_externalEntityRefHandler) {
+             dtd->paramEntityRead = XML_FALSE;
+             entity->open = XML_TRUE;
++            entityTrackingOnOpen(parser, entity, __LINE__);
+             if (! parser->m_externalEntityRefHandler(
+                     parser->m_externalEntityRefHandlerArg, 0, entity->base,
+                     entity->systemId, entity->publicId)) {
++              entityTrackingOnClose(parser, entity, __LINE__);
+               entity->open = XML_FALSE;
+               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+               goto endEntityValue;
+             }
++            entityTrackingOnClose(parser, entity, __LINE__);
+             entity->open = XML_FALSE;
+             if (! dtd->paramEntityRead)
+               dtd->keepProcessing = dtd->standalone;
+@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
+             dtd->keepProcessing = dtd->standalone;
+         } else {
+           entity->open = XML_TRUE;
++          entityTrackingOnOpen(parser, entity, __LINE__);
+           result = storeEntityValue(
+-              parser, parser->m_internalEncoding, (char *)entity->textPtr,
+-              (char *)(entity->textPtr + entity->textLen));
++              parser, parser->m_internalEncoding, (const char *)entity->textPtr,
++              (const char *)(entity->textPtr + entity->textLen),
++              XML_ACCOUNT_ENTITY_EXPANSION);
++          entityTrackingOnClose(parser, entity, __LINE__);
+           entity->open = XML_FALSE;
+           if (result)
+             goto endEntityValue;
+@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
+   memcpy(result, s, charsRequired * sizeof(XML_Char));
+   return result;
+ }
++
++#ifdef XML_DTD
++
++static float
++accountingGetCurrentAmplification(XML_Parser rootParser) {
++  const XmlBigCount countBytesOutput
++      = rootParser->m_accounting.countBytesDirect
++        + rootParser->m_accounting.countBytesIndirect;
++  const float amplificationFactor
++      = rootParser->m_accounting.countBytesDirect
++            ? (countBytesOutput
++               / (float)(rootParser->m_accounting.countBytesDirect))
++            : 1.0f;
++  assert(! rootParser->m_parentParser);
++  return amplificationFactor;
++}
++
++static void
++accountingReportStats(XML_Parser originParser, const char *epilog) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  if (rootParser->m_accounting.debugLevel < 1) {
++    return;
++  }
++
++  const float amplificationFactor
++      = accountingGetCurrentAmplification(rootParser);
++  fprintf(stderr,
++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
++              "10") ", indirect " EXPAT_FMT_ULL("10") ", amplification %8.2f%s",
++          (void *)rootParser, rootParser->m_accounting.countBytesDirect,
++          rootParser->m_accounting.countBytesIndirect,
++          (double)amplificationFactor, epilog);
++}
++
++static void
++accountingOnAbort(XML_Parser originParser) {
++  accountingReportStats(originParser, " ABORTING\n");
++}
++
++static void
++accountingReportDiff(XML_Parser rootParser,
++                     unsigned int levelsAwayFromRootParser, const char *before,
++                     const char *after, ptrdiff_t bytesMore, int source_line,
++                     enum XML_Account account) {
++  assert(! rootParser->m_parentParser);
++
++  fprintf(stderr,
++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d, xmlparse.c:%d) %*s\"",
++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
++          levelsAwayFromRootParser, source_line, 10, "");
++
++  const char ellipis[] = "[..]";
++  const size_t ellipsisLength = sizeof(ellipis) /* because compile-time */ - 1;
++  const unsigned int contextLength = 10;
++
++  /* Note: Performance is of no concern here */
++  const char *walker = before;
++  if ((rootParser->m_accounting.debugLevel >= 3)
++      || (after - before)
++             <= (ptrdiff_t)(contextLength + ellipsisLength + contextLength)) {
++    for (; walker < after; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++  } else {
++    for (; walker < before + contextLength; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++    fprintf(stderr, ellipis);
++    walker = after - contextLength;
++    for (; walker < after; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++  }
++  fprintf(stderr, "\"\n");
++}
++
++static XML_Bool
++accountingDiffTolerated(XML_Parser originParser, int tok, const char *before,
++                        const char *after, int source_line,
++                        enum XML_Account account) {
++  /* Note: We need to check the token type *first* to be sure that
++   *       we can even access variable <after>, safely.
++   *       E.g. for XML_TOK_NONE <after> may hold an invalid pointer. */
++  switch (tok) {
++  case XML_TOK_INVALID:
++  case XML_TOK_PARTIAL:
++  case XML_TOK_PARTIAL_CHAR:
++  case XML_TOK_NONE:
++    return XML_TRUE;
++  }
++
++  if (account == XML_ACCOUNT_NONE)
++    return XML_TRUE; /* because these bytes have been accounted for, already */
++
++  unsigned int levelsAwayFromRootParser;
++  const XML_Parser rootParser
++      = getRootParserOf(originParser, &levelsAwayFromRootParser);
++  assert(! rootParser->m_parentParser);
++
++  const int isDirect
++      = (account == XML_ACCOUNT_DIRECT) && (originParser == rootParser);
++  const ptrdiff_t bytesMore = after - before;
++
++  XmlBigCount *const additionTarget
++      = isDirect ? &rootParser->m_accounting.countBytesDirect
++                 : &rootParser->m_accounting.countBytesIndirect;
++
++  /* Detect and avoid integer overflow */
++  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
++    return XML_FALSE;
++  *additionTarget += bytesMore;
++
++  const XmlBigCount countBytesOutput
++      = rootParser->m_accounting.countBytesDirect
++        + rootParser->m_accounting.countBytesIndirect;
++  const float amplificationFactor
++      = accountingGetCurrentAmplification(rootParser);
++  const XML_Bool tolerated
++      = (countBytesOutput < rootParser->m_accounting.activationThresholdBytes)
++        || (amplificationFactor
++            <= rootParser->m_accounting.maximumAmplificationFactor);
++
++  if (rootParser->m_accounting.debugLevel >= 2) {
++    accountingReportStats(rootParser, "");
++    accountingReportDiff(rootParser, levelsAwayFromRootParser, before, after,
++                         bytesMore, source_line, account);
++  }
++
++  return tolerated;
++}
++
++static void
++entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
++                          const char *action, int sourceLine) {
++  assert(! rootParser->m_parentParser);
++  if (rootParser->m_entity_stats.debugLevel < 1)
++    return;
++
++#  if defined(XML_UNICODE)
++  const char *const entityName = "[..]";
++#  else
++  const char *const entityName = entity->name;
++#  endif
++
++  fprintf(
++      stderr,
++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s length %d (xmlparse.c:%d)\n",
++      (void *)rootParser, rootParser->m_entity_stats.countEverOpened,
++      rootParser->m_entity_stats.currentDepth,
++      rootParser->m_entity_stats.maximumDepthSeen,
++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
++      entity->is_param ? "%" : "&", entityName, action, entity->textLen,
++      sourceLine);
++}
++
++static void
++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int sourceLine) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  rootParser->m_entity_stats.countEverOpened++;
++  rootParser->m_entity_stats.currentDepth++;
++  if (rootParser->m_entity_stats.currentDepth
++      > rootParser->m_entity_stats.maximumDepthSeen) {
++    rootParser->m_entity_stats.maximumDepthSeen++;
++  }
++
++  entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine);
++}
++
++static void
++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int sourceLine) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine);
++  rootParser->m_entity_stats.currentDepth--;
++}
++
++static XML_Parser
++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
++  XML_Parser rootParser = parser;
++  unsigned int stepsTakenUpwards = 0;
++  while (rootParser->m_parentParser) {
++    rootParser = rootParser->m_parentParser;
++    stepsTakenUpwards++;
++  }
++  assert(! rootParser->m_parentParser);
++  if (outLevelDiff != NULL) {
++    *outLevelDiff = stepsTakenUpwards;
++  }
++  return rootParser;
++}
++
++static const char *
++unsignedCharToPrintable(unsigned char c) {
++  switch (c) {
++  case 0:
++    return "\\0";
++  case 1:
++    return "\\x1";
++  case 2:
++    return "\\x2";
++  case 3:
++    return "\\x3";
++  case 4:
++    return "\\x4";
++  case 5:
++    return "\\x5";
++  case 6:
++    return "\\x6";
++  case 7:
++    return "\\x7";
++  case 8:
++    return "\\x8";
++  case 9:
++    return "\\t";
++  case 10:
++    return "\\n";
++  case 11:
++    return "\\xB";
++  case 12:
++    return "\\xC";
++  case 13:
++    return "\\r";
++  case 14:
++    return "\\xE";
++  case 15:
++    return "\\xF";
++  case 16:
++    return "\\x10";
++  case 17:
++    return "\\x11";
++  case 18:
++    return "\\x12";
++  case 19:
++    return "\\x13";
++  case 20:
++    return "\\x14";
++  case 21:
++    return "\\x15";
++  case 22:
++    return "\\x16";
++  case 23:
++    return "\\x17";
++  case 24:
++    return "\\x18";
++  case 25:
++    return "\\x19";
++  case 26:
++    return "\\x1A";
++  case 27:
++    return "\\x1B";
++  case 28:
++    return "\\x1C";
++  case 29:
++    return "\\x1D";
++  case 30:
++    return "\\x1E";
++  case 31:
++    return "\\x1F";
++  case 32:
++    return " ";
++  case 33:
++    return "!";
++  case 34:
++    return "\\\"";
++  case 35:
++    return "#";
++  case 36:
++    return "$";
++  case 37:
++    return "%";
++  case 38:
++    return "&";
++  case 39:
++    return "'";
++  case 40:
++    return "(";
++  case 41:
++    return ")";
++  case 42:
++    return "*";
++  case 43:
++    return "+";
++  case 44:
++    return ",";
++  case 45:
++    return "-";
++  case 46:
++    return ".";
++  case 47:
++    return "/";
++  case 48:
++    return "0";
++  case 49:
++    return "1";
++  case 50:
++    return "2";
++  case 51:
++    return "3";
++  case 52:
++    return "4";
++  case 53:
++    return "5";
++  case 54:
++    return "6";
++  case 55:
++    return "7";
++  case 56:
++    return "8";
++  case 57:
++    return "9";
++  case 58:
++    return ":";
++  case 59:
++    return ";";
++  case 60:
++    return "<";
++  case 61:
++    return "=";
++  case 62:
++    return ">";
++  case 63:
++    return "?";
++  case 64:
++    return "@";
++  case 65:
++    return "A";
++  case 66:
++    return "B";
++  case 67:
++    return "C";
++  case 68:
++    return "D";
++  case 69:
++    return "E";
++  case 70:
++    return "F";
++  case 71:
++    return "G";
++  case 72:
++    return "H";
++  case 73:
++    return "I";
++  case 74:
++    return "J";
++  case 75:
++    return "K";
++  case 76:
++    return "L";
++  case 77:
++    return "M";
++  case 78:
++    return "N";
++  case 79:
++    return "O";
++  case 80:
++    return "P";
++  case 81:
++    return "Q";
++  case 82:
++    return "R";
++  case 83:
++    return "S";
++  case 84:
++    return "T";
++  case 85:
++    return "U";
++  case 86:
++    return "V";
++  case 87:
++    return "W";
++  case 88:
++    return "X";
++  case 89:
++    return "Y";
++  case 90:
++    return "Z";
++  case 91:
++    return "[";
++  case 92:
++    return "\\\\";
++  case 93:
++    return "]";
++  case 94:
++    return "^";
++  case 95:
++    return "_";
++  case 96:
++    return "`";
++  case 97:
++    return "a";
++  case 98:
++    return "b";
++  case 99:
++    return "c";
++  case 100:
++    return "d";
++  case 101:
++    return "e";
++  case 102:
++    return "f";
++  case 103:
++    return "g";
++  case 104:
++    return "h";
++  case 105:
++    return "i";
++  case 106:
++    return "j";
++  case 107:
++    return "k";
++  case 108:
++    return "l";
++  case 109:
++    return "m";
++  case 110:
++    return "n";
++  case 111:
++    return "o";
++  case 112:
++    return "p";
++  case 113:
++    return "q";
++  case 114:
++    return "r";
++  case 115:
++    return "s";
++  case 116:
++    return "t";
++  case 117:
++    return "u";
++  case 118:
++    return "v";
++  case 119:
++    return "w";
++  case 120:
++    return "x";
++  case 121:
++    return "y";
++  case 122:
++    return "z";
++  case 123:
++    return "{";
++  case 124:
++    return "|";
++  case 125:
++    return "}";
++  case 126:
++    return "~";
++  case 127:
++    return "\\x7F";
++  case 128:
++    return "\\x80";
++  case 129:
++    return "\\x81";
++  case 130:
++    return "\\x82";
++  case 131:
++    return "\\x83";
++  case 132:
++    return "\\x84";
++  case 133:
++    return "\\x85";
++  case 134:
++    return "\\x86";
++  case 135:
++    return "\\x87";
++  case 136:
++    return "\\x88";
++  case 137:
++    return "\\x89";
++  case 138:
++    return "\\x8A";
++  case 139:
++    return "\\x8B";
++  case 140:
++    return "\\x8C";
++  case 141:
++    return "\\x8D";
++  case 142:
++    return "\\x8E";
++  case 143:
++    return "\\x8F";
++  case 144:
++    return "\\x90";
++  case 145:
++    return "\\x91";
++  case 146:
++    return "\\x92";
++  case 147:
++    return "\\x93";
++  case 148:
++    return "\\x94";
++  case 149:
++    return "\\x95";
++  case 150:
++    return "\\x96";
++  case 151:
++    return "\\x97";
++  case 152:
++    return "\\x98";
++  case 153:
++    return "\\x99";
++  case 154:
++    return "\\x9A";
++  case 155:
++    return "\\x9B";
++  case 156:
++    return "\\x9C";
++  case 157:
++    return "\\x9D";
++  case 158:
++    return "\\x9E";
++  case 159:
++    return "\\x9F";
++  case 160:
++    return "\\xA0";
++  case 161:
++    return "\\xA1";
++  case 162:
++    return "\\xA2";
++  case 163:
++    return "\\xA3";
++  case 164:
++    return "\\xA4";
++  case 165:
++    return "\\xA5";
++  case 166:
++    return "\\xA6";
++  case 167:
++    return "\\xA7";
++  case 168:
++    return "\\xA8";
++  case 169:
++    return "\\xA9";
++  case 170:
++    return "\\xAA";
++  case 171:
++    return "\\xAB";
++  case 172:
++    return "\\xAC";
++  case 173:
++    return "\\xAD";
++  case 174:
++    return "\\xAE";
++  case 175:
++    return "\\xAF";
++  case 176:
++    return "\\xB0";
++  case 177:
++    return "\\xB1";
++  case 178:
++    return "\\xB2";
++  case 179:
++    return "\\xB3";
++  case 180:
++    return "\\xB4";
++  case 181:
++    return "\\xB5";
++  case 182:
++    return "\\xB6";
++  case 183:
++    return "\\xB7";
++  case 184:
++    return "\\xB8";
++  case 185:
++    return "\\xB9";
++  case 186:
++    return "\\xBA";
++  case 187:
++    return "\\xBB";
++  case 188:
++    return "\\xBC";
++  case 189:
++    return "\\xBD";
++  case 190:
++    return "\\xBE";
++  case 191:
++    return "\\xBF";
++  case 192:
++    return "\\xC0";
++  case 193:
++    return "\\xC1";
++  case 194:
++    return "\\xC2";
++  case 195:
++    return "\\xC3";
++  case 196:
++    return "\\xC4";
++  case 197:
++    return "\\xC5";
++  case 198:
++    return "\\xC6";
++  case 199:
++    return "\\xC7";
++  case 200:
++    return "\\xC8";
++  case 201:
++    return "\\xC9";
++  case 202:
++    return "\\xCA";
++  case 203:
++    return "\\xCB";
++  case 204:
++    return "\\xCC";
++  case 205:
++    return "\\xCD";
++  case 206:
++    return "\\xCE";
++  case 207:
++    return "\\xCF";
++  case 208:
++    return "\\xD0";
++  case 209:
++    return "\\xD1";
++  case 210:
++    return "\\xD2";
++  case 211:
++    return "\\xD3";
++  case 212:
++    return "\\xD4";
++  case 213:
++    return "\\xD5";
++  case 214:
++    return "\\xD6";
++  case 215:
++    return "\\xD7";
++  case 216:
++    return "\\xD8";
++  case 217:
++    return "\\xD9";
++  case 218:
++    return "\\xDA";
++  case 219:
++    return "\\xDB";
++  case 220:
++    return "\\xDC";
++  case 221:
++    return "\\xDD";
++  case 222:
++    return "\\xDE";
++  case 223:
++    return "\\xDF";
++  case 224:
++    return "\\xE0";
++  case 225:
++    return "\\xE1";
++  case 226:
++    return "\\xE2";
++  case 227:
++    return "\\xE3";
++  case 228:
++    return "\\xE4";
++  case 229:
++    return "\\xE5";
++  case 230:
++    return "\\xE6";
++  case 231:
++    return "\\xE7";
++  case 232:
++    return "\\xE8";
++  case 233:
++    return "\\xE9";
++  case 234:
++    return "\\xEA";
++  case 235:
++    return "\\xEB";
++  case 236:
++    return "\\xEC";
++  case 237:
++    return "\\xED";
++  case 238:
++    return "\\xEE";
++  case 239:
++    return "\\xEF";
++  case 240:
++    return "\\xF0";
++  case 241:
++    return "\\xF1";
++  case 242:
++    return "\\xF2";
++  case 243:
++    return "\\xF3";
++  case 244:
++    return "\\xF4";
++  case 245:
++    return "\\xF5";
++  case 246:
++    return "\\xF6";
++  case 247:
++    return "\\xF7";
++  case 248:
++    return "\\xF8";
++  case 249:
++    return "\\xF9";
++  case 250:
++    return "\\xFA";
++  case 251:
++    return "\\xFB";
++  case 252:
++    return "\\xFC";
++  case 253:
++    return "\\xFD";
++  case 254:
++    return "\\xFE";
++  case 255:
++    return "\\xFF";
++  default:
++    assert(0); /* never gets here */
++    return "dead code";
++  }
++  assert(0); /* never gets here */
++}
++
++#endif /* XML_DTD */
++
++static unsigned long
++getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {
++  const char *const valueOrNull = getenv(variableName);
++  if (valueOrNull == NULL) {
++    return defaultDebugLevel;
++  }
++  const char *const value = valueOrNull;
++
++  errno = 0;
++  char *afterValue = (char *)value;
++  unsigned long debugLevel = strtoul(value, &afterValue, 10);
++  if ((errno != 0) || (afterValue[0] != '\0')) {
++    errno = 0;
++    return defaultDebugLevel;
++  }
++
++  return debugLevel;
++}
+-- 
+2.32.0
+
diff --git a/meta/recipes-core/expat/expat/libtool-tag.patch b/meta/recipes-core/expat/expat/libtool-tag.patch
index 0a0aed23e5..203415a725 100644
--- a/meta/recipes-core/expat/expat/libtool-tag.patch
+++ b/meta/recipes-core/expat/expat/libtool-tag.patch
@@ -1,30 +1,27 @@
-From 10342e6b600858b091bc7771e454d9e06af06410 Mon Sep 17 00:00:00 2001
-From: Khem Raj <raj.khem@gmail.com>
-Date: Thu, 2 Nov 2017 18:20:57 +0800
+From da433dbe79f2d4d5d7d79869c669594c99c5de9c Mon Sep 17 00:00:00 2001
+From: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
+Date: Wed, 16 Jun 2021 19:00:30 +0200
 Subject: [PATCH] Add CC tag to build
 
-Add CC tag to build
-
 Upstream-Status: Pending
-Signed-off-by: Khem Raj <raj.khem@gmail.com>
-Signed-off-by: Dengke Du <dengke.du@windriver.com>
+Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
 ---
- Makefile.in | 2 +-
+ Makefile.am | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
-diff --git a/Makefile.in b/Makefile.in
-index 9560a95..d444bd6 100644
---- a/Makefile.in
-+++ b/Makefile.in
-@@ -319,7 +319,7 @@ LIBCURRENT = @LIBCURRENT@
- LIBOBJS = @LIBOBJS@
- LIBREVISION = @LIBREVISION@
- LIBS = @LIBS@
--LIBTOOL = @LIBTOOL@
-+LIBTOOL = @LIBTOOL@ --tag CC
- LIPO = @LIPO@
- LN_S = @LN_S@
- LTLIBOBJS = @LTLIBOBJS@
+diff --git a/Makefile.am b/Makefile.am
+index 5e1d37dd..f7a6dece 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -36,7 +36,7 @@ AUTOMAKE_OPTIONS = \
+     subdir-objects
+ 
+ ACLOCAL_AMFLAGS = -I m4
+-LIBTOOLFLAGS = --verbose
++LIBTOOLFLAGS = --verbose --tag=CC
+ 
+ SUBDIRS = lib # lib goes first to build first
+ if WITH_EXAMPLES
 -- 
-2.7.4
+2.32.0
 
diff --git a/meta/recipes-core/expat/expat_2.2.9.bb b/meta/recipes-core/expat/expat_2.2.9.bb
index 174bf4be1f..cd38df91d9 100644
--- a/meta/recipes-core/expat/expat_2.2.9.bb
+++ b/meta/recipes-core/expat/expat_2.2.9.bb
@@ -6,18 +6,16 @@ LICENSE = "MIT"
 
 LIC_FILES_CHKSUM = "file://COPYING;md5=5b8620d98e49772d95fc1d291c26aa79"
 
-SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}.tar.bz2 \
+SRC_URI = "git://github.com/libexpat/libexpat.git;protocol=https \
+           file://CVE-2013-0340.patch \
            file://libtool-tag.patch \
-	  "
+         "
 
-SRC_URI[md5sum] = "875a2c2ff3e8eb9e5a5cd62db2033ab5"
-SRC_URI[sha256sum] = "f1063084dc4302a427dabcca499c8312b3a32a29b7d2506653ecc8f950a9a237"
+SRCREV = "a7bc26b69768f7fb24f0c7976fae24b157b85b13"
 
 inherit autotools lib_package
 
-do_configure_prepend () {
-	rm -f ${S}/conftools/libtool.m4
-}
+S = "${WORKDIR}/git/expat"
 
 BBCLASSEXTEND = "native nativesdk"
 
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340
@ 2021-06-16 14:44 Jasper Orschulko
  0 siblings, 0 replies; 11+ messages in thread
From: Jasper Orschulko @ 2021-06-16 14:44 UTC (permalink / raw)
  To: openembedded-core

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

expat < 4.0 is vulnerable to billion laughs attacks (see
[https://github.com/libexpat/libexpat/issues/34]). This patch backports
the commits b1d039607d3d8a042bf0466bfcc1c0f104e353c8
and 60959f2b491876199879d97c8ed956eabb0c2e73 from upstream.

Additionally, the SRC_URI had to be adjusted due to renaming of the
source archive

Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
- ---
 ...expat-Backport-fix-for-CVE-2013-0340.patch | 1758 +++++++++++++++++
 meta/recipes-core/expat/expat_2.2.9.bb        |    3 +-
 2 files changed, 1760 insertions(+), 1 deletion(-)
 create mode 100644 meta/recipes-core/expat/expat/0001-expat-Backport-
fix-for-CVE-2013-0340.patch

diff --git a/meta/recipes-core/expat/expat/0001-expat-Backport-fix-for-
CVE-2013-0340.patch b/meta/recipes-core/expat/expat/0001-expat-
Backport-fix-for-CVE-2013-0340.patch
new file mode 100644
index 0000000000..b2ca066d96
- --- /dev/null
+++ b/meta/recipes-core/expat/expat/0001-expat-Backport-fix-for-CVE-
2013-0340.patch
@@ -0,0 +1,1758 @@
+From 6f68eb0439f3c1807a143ff8c8972e74d404d8f0 Mon Sep 17 00:00:00 2001
+From: Sebastian Pipping <sebastian@pipping.org>
+Date: Mon, 19 Apr 2021 21:42:51 +0200
+Subject: [PATCH] expat: Backport fix for CVE-2013-0340
+
+Issue: https://github.com/libexpat/libexpat/issues/34
+
+This patch cherry-picks the following commits from upstream release
+2.4.0 onto 2.2.9:
+
+- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
+- 60959f2b491876199879d97c8ed956eabb0c2e73
+
+Upstream-Status: Backport
+CVE: CVE-2013-0340
+Signed-off-by: Jasper Orschulko <Jasper.Orschulko@iris-sensing.com>
+---
+ expat/lib/expat.h       |   21 +-
+ expat/lib/internal.h    |   30 +
+ expat/lib/libexpat.def  |    3 +
+ expat/lib/libexpatw.def |    3 +
+ expat/lib/xmlparse.c    | 1147 +++++++++++++++++++++++++++++++++++++-
- -
+ 5 files changed, 1143 insertions(+), 61 deletions(-)
+
+diff --git a/expat/lib/expat.h b/expat/lib/expat.h
+index 48a6e2a3..796086c2 100644
+--- a/expat/lib/expat.h
++++ b/expat/lib/expat.h
+@@ -115,7 +115,9 @@ enum XML_Error {
+   XML_ERROR_RESERVED_PREFIX_XMLNS,
+   XML_ERROR_RESERVED_NAMESPACE_URI,
+   /* Added in 2.2.1. */
+-  XML_ERROR_INVALID_ARGUMENT
++  XML_ERROR_INVALID_ARGUMENT,
++  /* Backported from 2.4.0. */
++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
+ };
+ 
+ enum XML_Content_Type {
+@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
+   XML_FEATURE_SIZEOF_XML_LCHAR,
+   XML_FEATURE_NS,
+   XML_FEATURE_LARGE_SIZE,
+-  XML_FEATURE_ATTR_INFO
++  XML_FEATURE_ATTR_INFO,
++  /* Added in Expat 2.4.0. */
++ 
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFA
ULT,
++ 
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAU
LT
+   /* Additional features must be added to the end of this enum. */
+ };
+ 
+@@ -1010,6 +1015,18 @@ typedef struct {
+ XMLPARSEAPI(const XML_Feature *)
+ XML_GetFeatureList(void);
+ 
++#ifdef XML_DTD
++/* Backported from Expat 2.4.0. */
++XMLPARSEAPI(XML_Bool)
++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++    XML_Parser parser, float maximumAmplificationFactor);
++
++/* Backported from Expat 2.4.0. */
++XMLPARSEAPI(XML_Bool)
++XML_SetBillionLaughsAttackProtectionActivationThreshold(
++    XML_Parser parser, unsigned long long activationThresholdBytes);
++#endif
++
+ /* Expat follows the semantic versioning convention.
+    See http://semver.org.
+ */
+diff --git a/expat/lib/internal.h b/expat/lib/internal.h
+index 60913dab..d8b31fa2 100644
+--- a/expat/lib/internal.h
++++ b/expat/lib/internal.h
+@@ -101,10 +101,40 @@
+ #  endif
+ #endif
+ 
++#include <limits.h> // ULONG_MAX
++
++#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
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
++#  else
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
++#  endif
++#else
++#  define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
++#  if ! defined(ULONG_MAX)
++#    error Compiler did not define ULONG_MAX for us
++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
++#  else
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
++#  endif
++#endif
++
+ #ifndef UNUSED_P
+ #  define UNUSED_P(p) (void)p
+ #endif
+ 
++/* NOTE BEGIN If you ever patch these defaults to greater values
++              for non-attack XML payload in your environment,
++              please file a bug report with libexpat.  Thank you!
++*/
++#define
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT  
\
++  100.0f
++#define
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT   
\
++  8388608 // 8 MiB, 2^23
++/* NOTE END */
++
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+diff --git a/expat/lib/libexpat.def b/expat/lib/libexpat.def
+index 16faf595..b5e59d8d 100644
+--- a/expat/lib/libexpat.def
++++ b/expat/lib/libexpat.def
+@@ -76,3 +76,6 @@ EXPORTS
+   XML_SetHashSalt @67
+ ; added with version 2.2.5
+   _INTERNAL_trim_to_complete_utf8_characters @68
++; backported from version 2.4.0
++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
+diff --git a/expat/lib/libexpatw.def b/expat/lib/libexpatw.def
+index 16faf595..ebd77707 100644
+--- a/expat/lib/libexpatw.def
++++ b/expat/lib/libexpatw.def
+@@ -76,3 +76,6 @@ EXPORTS
+   XML_SetHashSalt @67
+ ; added with version 2.2.5
+   _INTERNAL_trim_to_complete_utf8_characters @68
++; backported from version 2.4.0
++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @7
+diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
+index 3aaf35b9..fdcc7296 100644
+--- a/expat/lib/xmlparse.c
++++ b/expat/lib/xmlparse.c
+@@ -47,6 +47,8 @@
+ #include <limits.h> /* UINT_MAX */
+ #include <stdio.h>  /* fprintf */
+ #include <stdlib.h> /* getenv, rand_s */
++#include <stdint.h> /* uintptr_t */
++#include <math.h>   /* isnan */
+ 
+ #ifdef _WIN32
+ #  define getpid GetCurrentProcessId
+@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
+   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+ } OPEN_INTERNAL_ENTITY;
+ 
++enum XML_Account {
++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the Expat
parser */
++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during
entity
++                                   expansion */
++  XML_ACCOUNT_NONE              /* i.e. do not account, was accounted
already */
++};
++
++#ifdef XML_DTD
++typedef unsigned long long XmlBigCount;
++typedef struct accounting {
++  XmlBigCount countBytesDirect;
++  XmlBigCount countBytesIndirect;
++  int debugLevel;
++  float maximumAmplificationFactor; // >=1.0
++  unsigned long long activationThresholdBytes;
++} ACCOUNTING;
++
++typedef struct entity_stats {
++  unsigned int countEverOpened;
++  unsigned int currentDepth;
++  unsigned int maximumDepthSeen;
++  int debugLevel;
++} ENTITY_STATS;
++#endif /* XML_DTD */
++
+ typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const
char *start,
+                                          const char *end, const char
**endPtr);
+ 
+@@ -403,16 +430,18 @@ static enum XML_Error
initializeEncoding(XML_Parser parser);
+ static enum XML_Error doProlog(XML_Parser parser, const ENCODING
*enc,
+                                const char *s, const char *end, int
tok,
+                                const char *next, const char
**nextPtr,
+-                               XML_Bool haveMore, XML_Bool
allowClosingDoctype);
++                               XML_Bool haveMore, XML_Bool
allowClosingDoctype,
++                               enum XML_Account account);
+ static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY
*entity,
+                                             XML_Bool betweenDecl);
+ static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
+                                 const ENCODING *enc, const char
*start,
+                                 const char *end, const char **endPtr,
+-                                XML_Bool haveMore);
++                                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,
+@@ -422,7 +451,8 @@ static enum XML_Error doIgnoreSection(XML_Parser
parser, const ENCODING *,
+ static void freeBindings(XML_Parser parser, BINDING *bindings);
+ static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
+                                 const char *s, TAG_NAME *tagNamePtr,
+-                                BINDING **bindingsPtr);
++                                BINDING **bindingsPtr,
++                                enum XML_Account account);
+ static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
+                                  const ATTRIBUTE_ID *attId, const
XML_Char *uri,
+                                  BINDING **bindingsPtr);
+@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE *type,
ATTRIBUTE_ID *, XML_Bool isCdata,
+                            XML_Parser parser);
+ static enum XML_Error storeAttributeValue(XML_Parser parser, const
ENCODING *,
+                                           XML_Bool isCdata, const
char *,
+-                                          const char *, STRING_POOL
*);
++                                          const char *, STRING_POOL
*,
++                                          enum XML_Account account);
+ static enum XML_Error appendAttributeValue(XML_Parser parser, const
ENCODING *,
+                                            XML_Bool isCdata, const
char *,
+-                                           const char *, STRING_POOL
*);
++                                           const char *, STRING_POOL
*,
++                                           enum XML_Account account);
+ static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING
*enc,
+                                     const char *start, const char
*end);
+ static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+ static enum XML_Error storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+-                                       const char *start, const char
*end);
++                                       const char *start, const char
*end,
++                                       enum XML_Account account);
+ static int reportProcessingInstruction(XML_Parser parser, const
ENCODING *enc,
+                                        const char *start, const char
*end);
+ static int reportComment(XML_Parser parser, const ENCODING *enc,
+@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const XML_Char
*encodingName,
+ 
+ static void parserInit(XML_Parser parser, const XML_Char
*encodingName);
+ 
++#ifdef XML_DTD
++static float accountingGetCurrentAmplification(XML_Parser
rootParser);
++static void accountingReportStats(XML_Parser originParser, const char
*epilog);
++static void accountingOnAbort(XML_Parser originParser);
++static void accountingReportDiff(XML_Parser rootParser,
++                                 unsigned int
levelsAwayFromRootParser,
++                                 const char *before, const char
*after,
++                                 ptrdiff_t bytesMore, int
source_line,
++                                 enum XML_Account account);
++static XML_Bool accountingDiffTolerated(XML_Parser originParser, int
tok,
++                                        const char *before, const
char *after,
++                                        int source_line,
++                                        enum XML_Account account);
++
++static void entityTrackingReportStats(XML_Parser parser, ENTITY
*entity,
++                                      const char *action, int
sourceLine);
++static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
++                                 int sourceLine);
++static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
++                                  int sourceLine);
++
++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,
++                                   unsigned long defaultDebugLevel);
++
+ #define poolStart(pool) ((pool)->start)
+ #define poolEnd(pool) ((pool)->ptr)
+ #define poolLength(pool) ((pool)->ptr - (pool)->start)
+@@ -616,6 +678,10 @@ struct XML_ParserStruct {
+   enum XML_ParamEntityParsing m_paramEntityParsing;
+ #endif
+   unsigned long m_hash_secret_salt;
++#ifdef XML_DTD
++  ACCOUNTING m_accounting;
++  ENTITY_STATS m_entity_stats;
++#endif
+ };
+ 
+ #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
+@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const XML_Char
*encodingName) {
+   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ #endif
+   parser->m_hash_secret_salt = 0;
++
++#ifdef XML_DTD
++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
++  parser->m_accounting.debugLevel =
getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
++  parser->m_accounting.maximumAmplificationFactor
++      =
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
++  parser->m_accounting.activationThresholdBytes
++      =
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
++
++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
++  parser->m_entity_stats.debugLevel =
getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
++#endif
+ }
+ 
+ /* moves list of bindings to m_freeBindingList */
+@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
+   /* Added in 2.2.5. */
+   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1,
already */
+     return XML_L("invalid argument");
++  /* Backported from 2.4.0. */
++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
++    return XML_L(
++        "limit on input amplification factor (from DTD and entities)
breached");
+   }
+   return NULL;
+ }
+@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
+ 
+ const XML_Feature *XMLCALL
+ XML_GetFeatureList(void) {
+-  static const XML_Feature features[]
+-      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+-          sizeof(XML_Char)},
+-         {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+-          sizeof(XML_LChar)},
++  static const XML_Feature features[] = {
++      {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
++       sizeof(XML_Char)},
++      {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
++       sizeof(XML_LChar)},
+ #ifdef XML_UNICODE
+-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+ #endif
+ #ifdef XML_UNICODE_WCHAR_T
+-         {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"),
0},
++      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+ #endif
+ #ifdef XML_DTD
+-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+ #endif
+ #ifdef XML_CONTEXT_BYTES
+-         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+-          XML_CONTEXT_BYTES},
++      {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
++       XML_CONTEXT_BYTES},
+ #endif
+ #ifdef XML_MIN_SIZE
+-         {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+ #endif
+ #ifdef XML_NS
+-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+ #endif
+ #ifdef XML_LARGE_SIZE
+-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
++      {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
+ #endif
+ #ifdef XML_ATTR_INFO
+-         {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
+ #endif
+-         {XML_FEATURE_END, NULL, 0}};
++#ifdef XML_DTD
++      /* Added in Expat 2.4.0. */
++     
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEF
AULT,
++       XML_L("XML_BLAP_MAX_AMP"),
++       (long int)
++          
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT},
++     
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFA
ULT,
++       XML_L("XML_BLAP_ACT_THRES"),
++      
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
++#endif
++      {XML_FEATURE_END, NULL, 0}};
+ 
+   return features;
+ }
+ 
++#ifdef XML_DTD
++XML_Bool XMLCALL
++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++    XML_Parser parser, float maximumAmplificationFactor) {
++  if ((parser == NULL) || (parser->m_parentParser != NULL)
++      || isnan(maximumAmplificationFactor)
++      || (maximumAmplificationFactor < 1.0f)) {
++    return XML_FALSE;
++  }
++  parser->m_accounting.maximumAmplificationFactor =
maximumAmplificationFactor;
++  return XML_TRUE;
++}
++
++XML_Bool XMLCALL
++XML_SetBillionLaughsAttackProtectionActivationThreshold(
++    XML_Parser parser, unsigned long long activationThresholdBytes) {
++  if ((parser == NULL) || (parser->m_parentParser != NULL)) {
++    return XML_FALSE;
++  }
++  parser->m_accounting.activationThresholdBytes =
activationThresholdBytes;
++  return XML_TRUE;
++}
++#endif /* XML_DTD */
++
+ /* Initially tag->rawName always points into the parse buffer;
+    for those TAG instances opened while the current parse buffer was
+    processed, and not yet closed, we need to store tag->rawName in a
more
+@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
+ static enum XML_Error PTRCALL
+ contentProcessor(XML_Parser parser, const char *start, const char
*end,
+                  const char **endPtr) {
+-  enum XML_Error result
+-      = doContent(parser, 0, parser->m_encoding, start, end, endPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++  enum XML_Error result = doContent(
++      parser, 0, parser->m_encoding, start, end, endPtr,
++      (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_ACCOUNT_DIRECT);
+   if (result == XML_ERROR_NONE) {
+     if (! storeRawNames(parser))
+       return XML_ERROR_NO_MEMORY;
+@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser parser,
const char *start,
+   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
+   switch (tok) {
+   case XML_TOK_BOM:
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif /* XML_DTD */
++
+     /* If we are at the end of the buffer, this would cause the next
stage,
+        i.e. externalEntityInitProcessor3, to pass control directly to
+        doContent (by detecting XML_TOK_NONE) without processing any
xml text
+@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser parser,
const char *start,
+   const char *next = start; /* XmlContentTok doesn't always set the
last arg */
+   parser->m_eventPtr = start;
+   tok = XmlContentTok(parser->m_encoding, start, end, &next);
++  /* Note: These bytes are accounted later in:
++           - processXmlDecl
++           - externalEntityContentProcessor
++  */
+   parser->m_eventEndPtr = next;
+ 
+   switch (tok) {
+@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser
parser, const char *start,
+                                const char *end, const char **endPtr)
{
+   enum XML_Error result
+       = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
++                  XML_ACCOUNT_ENTITY_EXPANSION);
+   if (result == XML_ERROR_NONE) {
+     if (! storeRawNames(parser))
+       return XML_ERROR_NO_MEMORY;
+@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser
parser, const char *start,
+ static enum XML_Error
+ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+           const char *s, const char *end, const char **nextPtr,
+-          XML_Bool haveMore) {
++          XML_Bool haveMore, enum XML_Account account) {
+   /* save one level of indirection */
+   DTD *const dtd = parser->m_dtd;
+ 
+@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+   for (;;) {
+     const char *next = s; /* XmlContentTok doesn't always set the
last arg */
+     int tok = XmlContentTok(enc, s, end, &next);
++#ifdef XML_DTD
++    const char *accountAfter
++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok ==
XML_TOK_TRAILING_CR))
++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
++              : next;
++    if (! accountingDiffTolerated(parser, tok, s, accountAfter,
__LINE__,
++                                  account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     *eventEndPP = next;
+     switch (tok) {
+     case XML_TOK_TRAILING_CR:
+@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+           enc, s + enc->minBytesPerChar, next - enc-
>minBytesPerChar);
+       if (ch) {
++#ifdef XML_DTD
++        /* NOTE: We are replacing 4-6 characters original input for 1
character
++         *       so there is no amplification and hence recording
without
++         *       protection. */
++        accountingDiffTolerated(parser, tok, (char *)&ch,
++                                ((char *)&ch) + sizeof(XML_Char),
__LINE__,
++                                XML_ACCOUNT_ENTITY_EXPANSION);
++#endif /* XML_DTD */
+         if (parser->m_characterDataHandler)
+           parser->m_characterDataHandler(parser->m_handlerArg, &ch,
1);
+         else if (parser->m_defaultHandler)
+@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+       }
+       tag->name.str = (XML_Char *)tag->buf;
+       *toPtr = XML_T('\0');
+-      result = storeAtts(parser, enc, s, &(tag->name), &(tag-
>bindings));
++      result
++          = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings),
account);
+       if (result)
+         return result;
+       if (parser->m_startElementHandler)
+@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc,
+       if (! name.str)
+         return XML_ERROR_NO_MEMORY;
+       poolFinish(&parser->m_tempPool);
+-      result = storeAtts(parser, enc, s, &name, &bindings);
++      result = storeAtts(parser, enc, s, &name, &bindings,
++                         XML_ACCOUNT_NONE /* token spans whole start
tag */);
+       if (result != XML_ERROR_NONE) {
+         freeBindings(parser, bindings);
+         return result;
+@@ -2907,7 +3057,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) {
+@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING
*bindings) {
+ */
+ static enum XML_Error
+ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
+-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
++          TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
++          enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   ELEMENT_TYPE *elementType;
+   int nDefaultAtts;
+@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const ENCODING
*enc, const char *attStr,
+       /* normalize the attribute value */
+       result = storeAttributeValue(
+           parser, enc, isCdata, parser->m_atts[i].valuePtr,
+-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
++          parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
+       if (result)
+         return result;
+       appAtts[attIndex] = poolStart(&parser->m_tempPool);
+@@ -3535,9 +3687,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) {
+@@ -3557,7 +3709,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;
+@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const
ENCODING *enc, const char **startPtr,
+   for (;;) {
+     const char *next;
+     int tok = XmlCdataSectionTok(enc, s, end, &next);
++#ifdef XML_DTD
++    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) {
+     case XML_TOK_CDATA_SECT_CLOSE:
+@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const
ENCODING *enc, const char **startPtr,
+   *eventPP = s;
+   *startPtr = NULL;
+   tok = XmlIgnoreSectionTok(enc, s, end, &next);
++#  ifdef XML_DTD
++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                XML_ACCOUNT_DIRECT)) {
++    accountingOnAbort(parser);
++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++  }
++#  endif
+   *eventEndPP = next;
+   switch (tok) {
+   case XML_TOK_IGNORE_SECT:
+@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int
isGeneralTextEntity, const char *s,
+   const char *versionend;
+   const XML_Char *storedversion = NULL;
+   int standalone = -1;
++
++#ifdef XML_DTD
++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next,
__LINE__,
++                                XML_ACCOUNT_DIRECT)) {
++    accountingOnAbort(parser);
++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++  }
++#endif
++
+   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
+           isGeneralTextEntity, parser->m_encoding, s, next, &parser-
>m_eventPtr,
+           &version, &versionend, &encodingName, &newEncoding,
&standalone)) {
+@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser parser,
const char *s, const char *end,
+ 
+   for (;;) {
+     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
++    /* Note: Except for XML_TOK_BOM below, these bytes are accounted
later in:
++             - storeEntityValue
++             - processXmlDecl
++    */
+     parser->m_eventEndPtr = next;
+     if (tok <= 0) {
+       if (! parser->m_parsingStatus.finalBuffer && tok !=
XML_TOK_INVALID) {
+@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser parser,
const char *s, const char *end,
+         break;
+       }
+       /* found end of entity value - can store it now */
+-      return storeEntityValue(parser, parser->m_encoding, s, end);
++      return storeEntityValue(parser, parser->m_encoding, s, end,
++                              XML_ACCOUNT_DIRECT);
+     } else if (tok == XML_TOK_XML_DECL) {
+       enum XML_Error result;
+       result = processXmlDecl(parser, 0, start, next);
+@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser parser,
const char *s, const char *end,
+     */
+     else if (tok == XML_TOK_BOM && next == end
+              && ! parser->m_parsingStatus.finalBuffer) {
++#  ifdef XML_DTD
++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                    XML_ACCOUNT_DIRECT)) {
++        accountingOnAbort(parser);
++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      }
++#  endif
++
+       *nextPtr = next;
+       return XML_ERROR_NONE;
+     }
+@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser parser,
const char *s, const char *end,
+   }
+   /* This would cause the next stage, i.e. doProlog to be passed
XML_TOK_BOM.
+      However, when parsing an external subset, doProlog will not
accept a BOM
+-     as valid, and report a syntax error, so we have to skip the BOM
++     as valid, and report a syntax error, so we have to skip the BOM,
and
++     account for the BOM bytes.
+   */
+   else if (tok == XML_TOK_BOM) {
++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++
+     s = next;
+     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+   }
+ 
+   parser->m_processor = prologProcessor;
+   return doProlog(parser, parser->m_encoding, s, end, tok, next,
nextPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE,
++                  XML_ACCOUNT_DIRECT);
+ }
+ 
+ static enum XML_Error PTRCALL
+@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser, const
char *s, const char *end,
+ 
+   for (;;) {
+     tok = XmlPrologTok(enc, start, end, &next);
++    /* Note: These bytes are accounted later in:
++             - storeEntityValue
++    */
+     if (tok <= 0) {
+       if (! parser->m_parsingStatus.finalBuffer && tok !=
XML_TOK_INVALID) {
+         *nextPtr = s;
+@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser, const
char *s, const char *end,
+         break;
+       }
+       /* found end of entity value - can store it now */
+-      return storeEntityValue(parser, enc, s, end);
++      return storeEntityValue(parser, enc, s, end,
XML_ACCOUNT_DIRECT);
+     }
+     start = next;
+   }
+@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const char
*s, const char *end,
+   const char *next = s;
+   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+   return doProlog(parser, parser->m_encoding, s, end, tok, next,
nextPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE);
++                  (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE,
++                  XML_ACCOUNT_DIRECT);
+ }
+ 
+ static enum XML_Error
+ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const
char *end,
+          int tok, const char *next, const char **nextPtr, XML_Bool
haveMore,
+-         XML_Bool allowClosingDoctype) {
++         XML_Bool allowClosingDoctype, enum XML_Account account) {
+ #ifdef XML_DTD
+   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
+ #endif /* XML_DTD */
+@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const ENCODING
*enc, const char *s, const char *end,
+   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
+   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
+ 
++#ifndef XML_DTD
++  UNUSED_P(account);
++#endif
++
+   /* save one level of indirection */
+   DTD *const dtd = parser->m_dtd;
+ 
+@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const ENCODING
*enc, const char *s, const char *end,
+       }
+     }
+     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
++#ifdef XML_DTD
++    switch (role) {
++    case XML_ROLE_INSTANCE_START: // bytes accounted in
contentProcessor
++    case XML_ROLE_XML_DECL:       // bytes accounted in
processXmlDecl
++    case XML_ROLE_TEXT_DECL:      // bytes accounted in
processXmlDecl
++      break;
++    default:
++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
account)) {
++        accountingOnAbort(parser);
++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      }
++    }
++#endif
+     switch (role) {
+     case XML_ROLE_XML_DECL: {
+       enum XML_Error result = processXmlDecl(parser, 0, s, next);
+@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING *enc,
const char *s, const char *end,
+         const XML_Char *attVal;
+         enum XML_Error result = storeAttributeValue(
+             parser, enc, parser->m_declAttributeIsCdata,
+-            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
&dtd->pool);
++            s + enc->minBytesPerChar, next - enc->minBytesPerChar,
&dtd->pool,
++            XML_ACCOUNT_NONE);
+         if (result)
+           return result;
+         attVal = poolStart(&dtd->pool);
+@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING *enc,
const char *s, const char *end,
+       break;
+     case XML_ROLE_ENTITY_VALUE:
+       if (dtd->keepProcessing) {
+-        enum XML_Error result = storeEntityValue(
+-            parser, enc, s + enc->minBytesPerChar, next - enc-
>minBytesPerChar);
++        enum XML_Error result
++            = storeEntityValue(parser, enc, s + enc->minBytesPerChar,
++                               next - enc->minBytesPerChar,
XML_ACCOUNT_NONE);
+         if (parser->m_declEntity) {
+           parser->m_declEntity->textPtr = poolStart(&dtd-
>entityValuePool);
+           parser->m_declEntity->textLen
+@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const ENCODING
*enc, const char *s, const char *end,
+         if (parser->m_externalEntityRefHandler) {
+           dtd->paramEntityRead = XML_FALSE;
+           entity->open = XML_TRUE;
++          entityTrackingOnOpen(parser, entity, __LINE__);
+           if (! parser->m_externalEntityRefHandler(
+                   parser->m_externalEntityRefHandlerArg, 0, entity-
>base,
+                   entity->systemId, entity->publicId)) {
++            entityTrackingOnClose(parser, entity, __LINE__);
+             entity->open = XML_FALSE;
+             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+           }
++          entityTrackingOnClose(parser, entity, __LINE__);
+           entity->open = XML_FALSE;
+           handleDefault = XML_FALSE;
+           if (! dtd->paramEntityRead) {
+@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const char
*s, const char *end,
+   for (;;) {
+     const char *next = NULL;
+     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     parser->m_eventEndPtr = next;
+     switch (tok) {
+     /* report partial linebreak - it might be the last token */
+@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser, ENTITY
*entity, XML_Bool betweenDecl) {
+       return XML_ERROR_NO_MEMORY;
+   }
+   entity->open = XML_TRUE;
++#ifdef XML_DTD
++  entityTrackingOnOpen(parser, entity, __LINE__);
++#endif
+   entity->processed = 0;
+   openEntity->next = parser->m_openInternalEntities;
+   parser->m_openInternalEntities = openEntity;
+@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser,
ENTITY *entity, XML_Bool betweenDecl) {
+     int tok
+         = XmlPrologTok(parser->m_internalEncoding, textStart,
textEnd, &next);
+     result = doProlog(parser, parser->m_internalEncoding, textStart,
textEnd,
+-                      tok, next, &next, XML_FALSE, XML_FALSE);
++                      tok, next, &next, XML_FALSE, XML_FALSE,
++                      XML_ACCOUNT_ENTITY_EXPANSION);
+   } else
+ #endif /* XML_DTD */
+     result = doContent(parser, parser->m_tagLevel, parser-
>m_internalEncoding,
+-                       textStart, textEnd, &next, XML_FALSE);
++                       textStart, textEnd, &next, XML_FALSE,
++                       XML_ACCOUNT_ENTITY_EXPANSION);
+ 
+   if (result == XML_ERROR_NONE) {
+     if (textEnd != next && parser->m_parsingStatus.parsing ==
XML_SUSPENDED) {
+       entity->processed = (int)(next - textStart);
+       parser->m_processor = internalEntityProcessor;
+     } else {
++#ifdef XML_DTD
++      entityTrackingOnClose(parser, entity, __LINE__);
++#endif /* XML_DTD */
+       entity->open = XML_FALSE;
+       parser->m_openInternalEntities = openEntity->next;
+       /* put openEntity back in list of free instances */
+@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser parser,
const char *s, const char *end,
+     int tok
+         = XmlPrologTok(parser->m_internalEncoding, textStart,
textEnd, &next);
+     result = doProlog(parser, parser->m_internalEncoding, textStart,
textEnd,
+-                      tok, next, &next, XML_FALSE, XML_TRUE);
++                      tok, next, &next, XML_FALSE, XML_TRUE,
++                      XML_ACCOUNT_ENTITY_EXPANSION);
+   } else
+ #endif /* XML_DTD */
+     result = doContent(parser, openEntity->startTagLevel,
+                        parser->m_internalEncoding, textStart,
textEnd, &next,
+-                       XML_FALSE);
++                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
+ 
+   if (result != XML_ERROR_NONE)
+     return result;
+@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser, const
char *s, const char *end,
+     entity->processed = (int)(next - (char *)entity->textPtr);
+     return result;
+   } else {
++#ifdef XML_DTD
++    entityTrackingOnClose(parser, entity, __LINE__);
++#endif
+     entity->open = XML_FALSE;
+     parser->m_openInternalEntities = openEntity->next;
+     /* put openEntity back in list of free instances */
+@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser, const
char *s, const char *end,
+     parser->m_processor = prologProcessor;
+     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+     return doProlog(parser, parser->m_encoding, s, end, tok, next,
nextPtr,
+-                    (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE);
++                    (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_TRUE,
++                    XML_ACCOUNT_DIRECT);
+   } else
+ #endif /* XML_DTD */
+   {
+@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser, const
char *s, const char *end,
+     /* see externalEntityContentProcessor vs contentProcessor */
+     return doContent(parser, parser->m_parentParser ? 1 : 0, parser-
>m_encoding,
+                      s, end, nextPtr,
+-                     (XML_Bool)! parser-
>m_parsingStatus.finalBuffer);
++                     (XML_Bool)! parser->m_parsingStatus.finalBuffer,
++                     XML_ACCOUNT_DIRECT);
+   }
+ }
+ 
+@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const char
*s, const char *end,
+ 
+ static enum XML_Error
+ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool
isCdata,
+-                    const char *ptr, const char *end, STRING_POOL
*pool) {
++                    const char *ptr, const char *end, STRING_POOL
*pool,
++                    enum XML_Account account) {
+   enum XML_Error result
+-      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
++      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool,
account);
+   if (result)
+     return result;
+   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+ 
+ static enum XML_Error
+ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool
isCdata,
+-                     const char *ptr, const char *end, STRING_POOL
*pool) {
++                     const char *ptr, const char *end, STRING_POOL
*pool,
++                     enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
++#ifndef XML_DTD
++  UNUSED_P(account);
++#endif
++
+   for (;;) {
+     const char *next;
+     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__,
account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     switch (tok) {
+     case XML_TOK_NONE:
+       return XML_ERROR_NONE;
+@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+           enc, ptr + enc->minBytesPerChar, next - enc-
>minBytesPerChar);
+       if (ch) {
++#ifdef XML_DTD
++        /* NOTE: We are replacing 4-6 characters original input for 1
character
++         *       so there is no amplification and hence recording
without
++         *       protection. */
++        accountingDiffTolerated(parser, tok, (char *)&ch,
++                                ((char *)&ch) + sizeof(XML_Char),
__LINE__,
++                                XML_ACCOUNT_ENTITY_EXPANSION);
++#endif /* XML_DTD */
+         if (! poolAppendChar(pool, ch))
+           return XML_ERROR_NO_MEMORY;
+         break;
+@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+         enum XML_Error result;
+         const XML_Char *textEnd = entity->textPtr + entity->textLen;
+         entity->open = XML_TRUE;
++#ifdef XML_DTD
++        entityTrackingOnOpen(parser, entity, __LINE__);
++#endif
+         result = appendAttributeValue(parser, parser-
>m_internalEncoding,
+-                                      isCdata, (char *)entity-
>textPtr,
+-                                      (char *)textEnd, pool);
++                                      isCdata, (const char *)entity-
>textPtr,
++                                      (const char *)textEnd, pool,
++                                      XML_ACCOUNT_ENTITY_EXPANSION);
++#ifdef XML_DTD
++        entityTrackingOnClose(parser, entity, __LINE__);
++#endif
+         entity->open = XML_FALSE;
+         if (result)
+           return result;
+@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser, const
ENCODING *enc, XML_Bool isCdata,
+ 
+ static enum XML_Error
+ storeEntityValue(XML_Parser parser, const ENCODING *enc,
+-                 const char *entityTextPtr, const char
*entityTextEnd) {
++                 const char *entityTextPtr, const char
*entityTextEnd,
++                 enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   STRING_POOL *pool = &(dtd->entityValuePool);
+   enum XML_Error result = XML_ERROR_NONE;
+ #ifdef XML_DTD
+   int oldInEntityValue = parser->m_prologState.inEntityValue;
+   parser->m_prologState.inEntityValue = 1;
++#else
++  UNUSED_P(account);
+ #endif /* XML_DTD */
+   /* never return Null for the value argument in EntityDeclHandler,
+      since this would indicate an external entity; therefore we
+@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+   for (;;) {
+     const char *next;
+     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd,
&next);
++
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, entityTextPtr, next,
__LINE__,
++                                  account)) {
++      accountingOnAbort(parser);
++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      goto endEntityValue;
++    }
++#endif
++
+     switch (tok) {
+     case XML_TOK_PARAM_ENTITY_REF:
+ #ifdef XML_DTD
+@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+           if (parser->m_externalEntityRefHandler) {
+             dtd->paramEntityRead = XML_FALSE;
+             entity->open = XML_TRUE;
++            entityTrackingOnOpen(parser, entity, __LINE__);
+             if (! parser->m_externalEntityRefHandler(
+                     parser->m_externalEntityRefHandlerArg, 0, entity-
>base,
+                     entity->systemId, entity->publicId)) {
++              entityTrackingOnClose(parser, entity, __LINE__);
+               entity->open = XML_FALSE;
+               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+               goto endEntityValue;
+             }
++            entityTrackingOnClose(parser, entity, __LINE__);
+             entity->open = XML_FALSE;
+             if (! dtd->paramEntityRead)
+               dtd->keepProcessing = dtd->standalone;
+@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const
ENCODING *enc,
+             dtd->keepProcessing = dtd->standalone;
+         } else {
+           entity->open = XML_TRUE;
++          entityTrackingOnOpen(parser, entity, __LINE__);
+           result = storeEntityValue(
+-              parser, parser->m_internalEncoding, (char *)entity-
>textPtr,
+-              (char *)(entity->textPtr + entity->textLen));
++              parser, parser->m_internalEncoding, (const char
*)entity->textPtr,
++              (const char *)(entity->textPtr + entity->textLen),
++              XML_ACCOUNT_ENTITY_EXPANSION);
++          entityTrackingOnClose(parser, entity, __LINE__);
+           entity->open = XML_FALSE;
+           if (result)
+             goto endEntityValue;
+@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const
XML_Memory_Handling_Suite *memsuite) {
+   memcpy(result, s, charsRequired * sizeof(XML_Char));
+   return result;
+ }
++
++#ifdef XML_DTD
++
++static float
++accountingGetCurrentAmplification(XML_Parser rootParser) {
++  const XmlBigCount countBytesOutput
++      = rootParser->m_accounting.countBytesDirect
++        + rootParser->m_accounting.countBytesIndirect;
++  const float amplificationFactor
++      = rootParser->m_accounting.countBytesDirect
++            ? (countBytesOutput
++               / (float)(rootParser->m_accounting.countBytesDirect))
++            : 1.0f;
++  assert(! rootParser->m_parentParser);
++  return amplificationFactor;
++}
++
++static void
++accountingReportStats(XML_Parser originParser, const char *epilog) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  if (rootParser->m_accounting.debugLevel < 1) {
++    return;
++  }
++
++  const float amplificationFactor
++      = accountingGetCurrentAmplification(rootParser);
++  fprintf(stderr,
++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
++              "10") ", indirect " EXPAT_FMT_ULL("10") ",
amplification %8.2f%s",
++          (void *)rootParser, rootParser-
>m_accounting.countBytesDirect,
++          rootParser->m_accounting.countBytesIndirect,
++          (double)amplificationFactor, epilog);
++}
++
++static void
++accountingOnAbort(XML_Parser originParser) {
++  accountingReportStats(originParser, " ABORTING\n");
++}
++
++static void
++accountingReportDiff(XML_Parser rootParser,
++                     unsigned int levelsAwayFromRootParser, const
char *before,
++                     const char *after, ptrdiff_t bytesMore, int
source_line,
++                     enum XML_Account account) {
++  assert(! rootParser->m_parentParser);
++
++  fprintf(stderr,
++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d,
xmlparse.c:%d) %*s\"",
++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
++          levelsAwayFromRootParser, source_line, 10, "");
++
++  const char ellipis[] = "[..]";
++  const size_t ellipsisLength = sizeof(ellipis) /* because compile-
time */ - 1;
++  const unsigned int contextLength = 10;
++
++  /* Note: Performance is of no concern here */
++  const char *walker = before;
++  if ((rootParser->m_accounting.debugLevel >= 3)
++      || (after - before)
++             <= (ptrdiff_t)(contextLength + ellipsisLength +
contextLength)) {
++    for (; walker < after; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++  } else {
++    for (; walker < before + contextLength; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++    fprintf(stderr, ellipis);
++    walker = after - contextLength;
++    for (; walker < after; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++  }
++  fprintf(stderr, "\"\n");
++}
++
++static XML_Bool
++accountingDiffTolerated(XML_Parser originParser, int tok, const char
*before,
++                        const char *after, int source_line,
++                        enum XML_Account account) {
++  /* Note: We need to check the token type *first* to be sure that
++   *       we can even access variable <after>, safely.
++   *       E.g. for XML_TOK_NONE <after> may hold an invalid pointer.
*/
++  switch (tok) {
++  case XML_TOK_INVALID:
++  case XML_TOK_PARTIAL:
++  case XML_TOK_PARTIAL_CHAR:
++  case XML_TOK_NONE:
++    return XML_TRUE;
++  }
++
++  if (account == XML_ACCOUNT_NONE)
++    return XML_TRUE; /* because these bytes have been accounted for,
already */
++
++  unsigned int levelsAwayFromRootParser;
++  const XML_Parser rootParser
++      = getRootParserOf(originParser, &levelsAwayFromRootParser);
++  assert(! rootParser->m_parentParser);
++
++  const int isDirect
++      = (account == XML_ACCOUNT_DIRECT) && (originParser ==
rootParser);
++  const ptrdiff_t bytesMore = after - before;
++
++  XmlBigCount *const additionTarget
++      = isDirect ? &rootParser->m_accounting.countBytesDirect
++                 : &rootParser->m_accounting.countBytesIndirect;
++
++  /* Detect and avoid integer overflow */
++  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
++    return XML_FALSE;
++  *additionTarget += bytesMore;
++
++  const XmlBigCount countBytesOutput
++      = rootParser->m_accounting.countBytesDirect
++        + rootParser->m_accounting.countBytesIndirect;
++  const float amplificationFactor
++      = accountingGetCurrentAmplification(rootParser);
++  const XML_Bool tolerated
++      = (countBytesOutput < rootParser-
>m_accounting.activationThresholdBytes)
++        || (amplificationFactor
++            <= rootParser->m_accounting.maximumAmplificationFactor);
++
++  if (rootParser->m_accounting.debugLevel >= 2) {
++    accountingReportStats(rootParser, "");
++    accountingReportDiff(rootParser, levelsAwayFromRootParser,
before, after,
++                         bytesMore, source_line, account);
++  }
++
++  return tolerated;
++}
++
++static void
++entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
++                          const char *action, int sourceLine) {
++  assert(! rootParser->m_parentParser);
++  if (rootParser->m_entity_stats.debugLevel < 1)
++    return;
++
++#  if defined(XML_UNICODE)
++  const char *const entityName = "[..]";
++#  else
++  const char *const entityName = entity->name;
++#  endif
++
++  fprintf(
++      stderr,
++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s
length %d (xmlparse.c:%d)\n",
++      (void *)rootParser, rootParser->m_entity_stats.countEverOpened,
++      rootParser->m_entity_stats.currentDepth,
++      rootParser->m_entity_stats.maximumDepthSeen,
++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
++      entity->is_param ? "%" : "&", entityName, action, entity-
>textLen,
++      sourceLine);
++}
++
++static void
++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int
sourceLine) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  rootParser->m_entity_stats.countEverOpened++;
++  rootParser->m_entity_stats.currentDepth++;
++  if (rootParser->m_entity_stats.currentDepth
++      > rootParser->m_entity_stats.maximumDepthSeen) {
++    rootParser->m_entity_stats.maximumDepthSeen++;
++  }
++
++  entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine);
++}
++
++static void
++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int
sourceLine) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine);
++  rootParser->m_entity_stats.currentDepth--;
++}
++
++static XML_Parser
++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
++  XML_Parser rootParser = parser;
++  unsigned int stepsTakenUpwards = 0;
++  while (rootParser->m_parentParser) {
++    rootParser = rootParser->m_parentParser;
++    stepsTakenUpwards++;
++  }
++  assert(! rootParser->m_parentParser);
++  if (outLevelDiff != NULL) {
++    *outLevelDiff = stepsTakenUpwards;
++  }
++  return rootParser;
++}
++
++static const char *
++unsignedCharToPrintable(unsigned char c) {
++  switch (c) {
++  case 0:
++    return "\\0";
++  case 1:
++    return "\\x1";
++  case 2:
++    return "\\x2";
++  case 3:
++    return "\\x3";
++  case 4:
++    return "\\x4";
++  case 5:
++    return "\\x5";
++  case 6:
++    return "\\x6";
++  case 7:
++    return "\\x7";
++  case 8:
++    return "\\x8";
++  case 9:
++    return "\\t";
++  case 10:
++    return "\\n";
++  case 11:
++    return "\\xB";
++  case 12:
++    return "\\xC";
++  case 13:
++    return "\\r";
++  case 14:
++    return "\\xE";
++  case 15:
++    return "\\xF";
++  case 16:
++    return "\\x10";
++  case 17:
++    return "\\x11";
++  case 18:
++    return "\\x12";
++  case 19:
++    return "\\x13";
++  case 20:
++    return "\\x14";
++  case 21:
++    return "\\x15";
++  case 22:
++    return "\\x16";
++  case 23:
++    return "\\x17";
++  case 24:
++    return "\\x18";
++  case 25:
++    return "\\x19";
++  case 26:
++    return "\\x1A";
++  case 27:
++    return "\\x1B";
++  case 28:
++    return "\\x1C";
++  case 29:
++    return "\\x1D";
++  case 30:
++    return "\\x1E";
++  case 31:
++    return "\\x1F";
++  case 32:
++    return " ";
++  case 33:
++    return "!";
++  case 34:
++    return "\\\"";
++  case 35:
++    return "#";
++  case 36:
++    return "$";
++  case 37:
++    return "%";
++  case 38:
++    return "&";
++  case 39:
++    return "'";
++  case 40:
++    return "(";
++  case 41:
++    return ")";
++  case 42:
++    return "*";
++  case 43:
++    return "+";
++  case 44:
++    return ",";
++  case 45:
++    return "-";
++  case 46:
++    return ".";
++  case 47:
++    return "/";
++  case 48:
++    return "0";
++  case 49:
++    return "1";
++  case 50:
++    return "2";
++  case 51:
++    return "3";
++  case 52:
++    return "4";
++  case 53:
++    return "5";
++  case 54:
++    return "6";
++  case 55:
++    return "7";
++  case 56:
++    return "8";
++  case 57:
++    return "9";
++  case 58:
++    return ":";
++  case 59:
++    return ";";
++  case 60:
++    return "<";
++  case 61:
++    return "=";
++  case 62:
++    return ">";
++  case 63:
++    return "?";
++  case 64:
++    return "@";
++  case 65:
++    return "A";
++  case 66:
++    return "B";
++  case 67:
++    return "C";
++  case 68:
++    return "D";
++  case 69:
++    return "E";
++  case 70:
++    return "F";
++  case 71:
++    return "G";
++  case 72:
++    return "H";
++  case 73:
++    return "I";
++  case 74:
++    return "J";
++  case 75:
++    return "K";
++  case 76:
++    return "L";
++  case 77:
++    return "M";
++  case 78:
++    return "N";
++  case 79:
++    return "O";
++  case 80:
++    return "P";
++  case 81:
++    return "Q";
++  case 82:
++    return "R";
++  case 83:
++    return "S";
++  case 84:
++    return "T";
++  case 85:
++    return "U";
++  case 86:
++    return "V";
++  case 87:
++    return "W";
++  case 88:
++    return "X";
++  case 89:
++    return "Y";
++  case 90:
++    return "Z";
++  case 91:
++    return "[";
++  case 92:
++    return "\\\\";
++  case 93:
++    return "]";
++  case 94:
++    return "^";
++  case 95:
++    return "_";
++  case 96:
++    return "`";
++  case 97:
++    return "a";
++  case 98:
++    return "b";
++  case 99:
++    return "c";
++  case 100:
++    return "d";
++  case 101:
++    return "e";
++  case 102:
++    return "f";
++  case 103:
++    return "g";
++  case 104:
++    return "h";
++  case 105:
++    return "i";
++  case 106:
++    return "j";
++  case 107:
++    return "k";
++  case 108:
++    return "l";
++  case 109:
++    return "m";
++  case 110:
++    return "n";
++  case 111:
++    return "o";
++  case 112:
++    return "p";
++  case 113:
++    return "q";
++  case 114:
++    return "r";
++  case 115:
++    return "s";
++  case 116:
++    return "t";
++  case 117:
++    return "u";
++  case 118:
++    return "v";
++  case 119:
++    return "w";
++  case 120:
++    return "x";
++  case 121:
++    return "y";
++  case 122:
++    return "z";
++  case 123:
++    return "{";
++  case 124:
++    return "|";
++  case 125:
++    return "}";
++  case 126:
++    return "~";
++  case 127:
++    return "\\x7F";
++  case 128:
++    return "\\x80";
++  case 129:
++    return "\\x81";
++  case 130:
++    return "\\x82";
++  case 131:
++    return "\\x83";
++  case 132:
++    return "\\x84";
++  case 133:
++    return "\\x85";
++  case 134:
++    return "\\x86";
++  case 135:
++    return "\\x87";
++  case 136:
++    return "\\x88";
++  case 137:
++    return "\\x89";
++  case 138:
++    return "\\x8A";
++  case 139:
++    return "\\x8B";
++  case 140:
++    return "\\x8C";
++  case 141:
++    return "\\x8D";
++  case 142:
++    return "\\x8E";
++  case 143:
++    return "\\x8F";
++  case 144:
++    return "\\x90";
++  case 145:
++    return "\\x91";
++  case 146:
++    return "\\x92";
++  case 147:
++    return "\\x93";
++  case 148:
++    return "\\x94";
++  case 149:
++    return "\\x95";
++  case 150:
++    return "\\x96";
++  case 151:
++    return "\\x97";
++  case 152:
++    return "\\x98";
++  case 153:
++    return "\\x99";
++  case 154:
++    return "\\x9A";
++  case 155:
++    return "\\x9B";
++  case 156:
++    return "\\x9C";
++  case 157:
++    return "\\x9D";
++  case 158:
++    return "\\x9E";
++  case 159:
++    return "\\x9F";
++  case 160:
++    return "\\xA0";
++  case 161:
++    return "\\xA1";
++  case 162:
++    return "\\xA2";
++  case 163:
++    return "\\xA3";
++  case 164:
++    return "\\xA4";
++  case 165:
++    return "\\xA5";
++  case 166:
++    return "\\xA6";
++  case 167:
++    return "\\xA7";
++  case 168:
++    return "\\xA8";
++  case 169:
++    return "\\xA9";
++  case 170:
++    return "\\xAA";
++  case 171:
++    return "\\xAB";
++  case 172:
++    return "\\xAC";
++  case 173:
++    return "\\xAD";
++  case 174:
++    return "\\xAE";
++  case 175:
++    return "\\xAF";
++  case 176:
++    return "\\xB0";
++  case 177:
++    return "\\xB1";
++  case 178:
++    return "\\xB2";
++  case 179:
++    return "\\xB3";
++  case 180:
++    return "\\xB4";
++  case 181:
++    return "\\xB5";
++  case 182:
++    return "\\xB6";
++  case 183:
++    return "\\xB7";
++  case 184:
++    return "\\xB8";
++  case 185:
++    return "\\xB9";
++  case 186:
++    return "\\xBA";
++  case 187:
++    return "\\xBB";
++  case 188:
++    return "\\xBC";
++  case 189:
++    return "\\xBD";
++  case 190:
++    return "\\xBE";
++  case 191:
++    return "\\xBF";
++  case 192:
++    return "\\xC0";
++  case 193:
++    return "\\xC1";
++  case 194:
++    return "\\xC2";
++  case 195:
++    return "\\xC3";
++  case 196:
++    return "\\xC4";
++  case 197:
++    return "\\xC5";
++  case 198:
++    return "\\xC6";
++  case 199:
++    return "\\xC7";
++  case 200:
++    return "\\xC8";
++  case 201:
++    return "\\xC9";
++  case 202:
++    return "\\xCA";
++  case 203:
++    return "\\xCB";
++  case 204:
++    return "\\xCC";
++  case 205:
++    return "\\xCD";
++  case 206:
++    return "\\xCE";
++  case 207:
++    return "\\xCF";
++  case 208:
++    return "\\xD0";
++  case 209:
++    return "\\xD1";
++  case 210:
++    return "\\xD2";
++  case 211:
++    return "\\xD3";
++  case 212:
++    return "\\xD4";
++  case 213:
++    return "\\xD5";
++  case 214:
++    return "\\xD6";
++  case 215:
++    return "\\xD7";
++  case 216:
++    return "\\xD8";
++  case 217:
++    return "\\xD9";
++  case 218:
++    return "\\xDA";
++  case 219:
++    return "\\xDB";
++  case 220:
++    return "\\xDC";
++  case 221:
++    return "\\xDD";
++  case 222:
++    return "\\xDE";
++  case 223:
++    return "\\xDF";
++  case 224:
++    return "\\xE0";
++  case 225:
++    return "\\xE1";
++  case 226:
++    return "\\xE2";
++  case 227:
++    return "\\xE3";
++  case 228:
++    return "\\xE4";
++  case 229:
++    return "\\xE5";
++  case 230:
++    return "\\xE6";
++  case 231:
++    return "\\xE7";
++  case 232:
++    return "\\xE8";
++  case 233:
++    return "\\xE9";
++  case 234:
++    return "\\xEA";
++  case 235:
++    return "\\xEB";
++  case 236:
++    return "\\xEC";
++  case 237:
++    return "\\xED";
++  case 238:
++    return "\\xEE";
++  case 239:
++    return "\\xEF";
++  case 240:
++    return "\\xF0";
++  case 241:
++    return "\\xF1";
++  case 242:
++    return "\\xF2";
++  case 243:
++    return "\\xF3";
++  case 244:
++    return "\\xF4";
++  case 245:
++    return "\\xF5";
++  case 246:
++    return "\\xF6";
++  case 247:
++    return "\\xF7";
++  case 248:
++    return "\\xF8";
++  case 249:
++    return "\\xF9";
++  case 250:
++    return "\\xFA";
++  case 251:
++    return "\\xFB";
++  case 252:
++    return "\\xFC";
++  case 253:
++    return "\\xFD";
++  case 254:
++    return "\\xFE";
++  case 255:
++    return "\\xFF";
++  default:
++    assert(0); /* never gets here */
++    return "dead code";
++  }
++  assert(0); /* never gets here */
++}
++
++#endif /* XML_DTD */
++
++static unsigned long
++getDebugLevel(const char *variableName, unsigned long
defaultDebugLevel) {
++  const char *const valueOrNull = getenv(variableName);
++  if (valueOrNull == NULL) {
++    return defaultDebugLevel;
++  }
++  const char *const value = valueOrNull;
++
++  errno = 0;
++  char *afterValue = (char *)value;
++  unsigned long debugLevel = strtoul(value, &afterValue, 10);
++  if ((errno != 0) || (afterValue[0] != '\0')) {
++    errno = 0;
++    return defaultDebugLevel;
++  }
++
++  return debugLevel;
++}
+-- 
+2.32.0
+
diff --git a/meta/recipes-core/expat/expat_2.2.9.bb b/meta/recipes-
core/expat/expat_2.2.9.bb
index 8f3db41352..3af457b2af 100644
- --- a/meta/recipes-core/expat/expat_2.2.9.bb
+++ b/meta/recipes-core/expat/expat_2.2.9.bb
@@ -6,8 +6,9 @@ LICENSE = "MIT"
 
 LIC_FILES_CHKSUM =
"file://COPYING;md5=5b8620d98e49772d95fc1d291c26aa79"
 
- -SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}.tar.bz2 \
+SRC_URI = "${SOURCEFORGE_MIRROR}/expat/expat-${PV}-RENAMED-VULNERABLE-
PLEASE-USE-2.4.1-INSTEAD.tar.bz2 \
            file://libtool-tag.patch \
+           file://0001-expat-Backport-fix-for-CVE-2013-0340.patch \
 	  "
 
 SRC_URI[md5sum] = "875a2c2ff3e8eb9e5a5cd62db2033ab5"
- -- 
2.32.0


-----BEGIN PGP SIGNATURE-----

iQEyBAEBCAAdFiEE4WyPMIC5Ap4+Ooo1Ygqew07VMNUFAmDKDhcACgkQYgqew07V
MNVM2Qf40RtDUO7tp6zxD62/MidNvrrDx0rJngCpuHh+BTmg1B1QRfnKo7vFxy40
N3pmC9g/P7CD2uaH+vk90fL5bjgP4VlL/BVFz5cD0R6UszkQvm5Dn6NxJxuKA21l
pbWt9NVaHsWxzC7YyTpEkU0a1pTTGvUh97LZOClGksn3qzrAdSzZ/uDCngxQFibp
g2kBDC2m3hfj0VphBiweoNAwOeNPWbzlmA8HfyxfQYTjly2kDFbBl2u2yckOi6Wn
nNVCHAYoA6zkbp4NiRvx4ALudNELu+LMHYdnih/5Hlu0aikI3aAv/HJk3Za1o3Zk
gSX9elNg+t3CvA8UE8ZgfEUBMXpt
=TgoB
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2021-06-17 15:21 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <168917379DAE252D.8130@lists.openembedded.org>
2021-06-16 14:48 ` [OE-core][dunfell][PATCH] expat: fix CVE-2013-0340 Jasper Orschulko
2021-06-16 15:09   ` Steve Sakoman
2021-06-16 15:17     ` Jasper Orschulko
2021-06-16 16:15       ` Steve Sakoman
2021-06-16 15:26     ` Jasper Orschulko
2021-06-16 18:19 ` Jasper Orschulko
     [not found] ` <168922F3778E5D40.4659@lists.openembedded.org>
2021-06-16 18:21   ` Jasper Orschulko
2021-06-16 21:14     ` Jasper Orschulko
2021-06-17 10:06       ` Jasper Orschulko
2021-06-17 15:20 Jasper Orschulko
  -- strict thread matches above, loose matches on Subject: below --
2021-06-16 14:44 Jasper Orschulko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.