summaryrefslogtreecommitdiffstats
path: root/meta/recipes-core/expat/expat
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-core/expat/expat')
-rw-r--r--meta/recipes-core/expat/expat/CVE-2013-0340.patch1758
-rw-r--r--meta/recipes-core/expat/expat/CVE-2021-45960.patch65
-rw-r--r--meta/recipes-core/expat/expat/CVE-2021-46143.patch49
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-22822-27.patch257
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-23852.patch33
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-23990.patch49
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-25235.patch283
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-25236.patch129
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-25313-regression.patch131
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-25313.patch230
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-25314.patch32
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-25315.patch145
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-40674.patch53
-rw-r--r--meta/recipes-core/expat/expat/CVE-2022-43680.patch33
-rw-r--r--meta/recipes-core/expat/expat/libtool-tag.patch41
15 files changed, 3266 insertions, 22 deletions
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..1ab4d06508
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2013-0340.patch
@@ -0,0 +1,1758 @@
1From a644ccf25392523b1329872310e24d0fc5f40629 Mon Sep 17 00:00:00 2001
2From: Sebastian Pipping <sebastian@pipping.org>
3Date: Mon, 19 Apr 2021 21:42:51 +0200
4Subject: [PATCH] expat: Backport fix for CVE-2013-0340
5
6Issue: https://github.com/libexpat/libexpat/issues/34
7
8This patch cherry-picks the following commits from upstream release
92.4.0 onto 2.2.9:
10
11- b1d039607d3d8a042bf0466bfcc1c0f104e353c8
12- 60959f2b491876199879d97c8ed956eabb0c2e73
13
14Upstream-Status: Backport
15CVE: CVE-2013-0340
16Signed-off-by: Jasper Orschulko <jasper@fancydomain.eu>
17---
18 lib/expat.h | 21 +-
19 lib/internal.h | 30 +
20 lib/libexpat.def | 3 +
21 lib/libexpatw.def | 3 +
22 lib/xmlparse.c | 1147 +++++++++++++++++++++++++++++++++++++--
23 5 files changed, 1143 insertions(+), 61 deletions(-)
24
25diff --git a/lib/expat.h b/lib/expat.h
26index 48a6e2a3..0fb70d9d 100644
27--- a/lib/expat.h
28+++ b/lib/expat.h
29@@ -115,7 +115,9 @@ enum XML_Error {
30 XML_ERROR_RESERVED_PREFIX_XMLNS,
31 XML_ERROR_RESERVED_NAMESPACE_URI,
32 /* Added in 2.2.1. */
33- XML_ERROR_INVALID_ARGUMENT
34+ XML_ERROR_INVALID_ARGUMENT,
35+ /* Added in 2.4.0. */
36+ XML_ERROR_AMPLIFICATION_LIMIT_BREACH
37 };
38
39 enum XML_Content_Type {
40@@ -997,7 +999,10 @@ enum XML_FeatureEnum {
41 XML_FEATURE_SIZEOF_XML_LCHAR,
42 XML_FEATURE_NS,
43 XML_FEATURE_LARGE_SIZE,
44- XML_FEATURE_ATTR_INFO
45+ XML_FEATURE_ATTR_INFO,
46+ /* Added in Expat 2.4.0. */
47+ XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
48+ XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT
49 /* Additional features must be added to the end of this enum. */
50 };
51
52@@ -1010,6 +1015,18 @@ typedef struct {
53 XMLPARSEAPI(const XML_Feature *)
54 XML_GetFeatureList(void);
55
56+#ifdef XML_DTD
57+/* Added in Expat 2.4.0. */
58+XMLPARSEAPI(XML_Bool)
59+XML_SetBillionLaughsAttackProtectionMaximumAmplification(
60+ XML_Parser parser, float maximumAmplificationFactor);
61+
62+/* Added in Expat 2.4.0. */
63+XMLPARSEAPI(XML_Bool)
64+XML_SetBillionLaughsAttackProtectionActivationThreshold(
65+ XML_Parser parser, unsigned long long activationThresholdBytes);
66+#endif
67+
68 /* Expat follows the semantic versioning convention.
69 See http://semver.org.
70 */
71diff --git a/lib/internal.h b/lib/internal.h
72index 60913dab..d8b31fa2 100644
73--- a/lib/internal.h
74+++ b/lib/internal.h
75@@ -101,10 +101,40 @@
76 # endif
77 #endif
78
79+#include <limits.h> // ULONG_MAX
80+
81+#if defined(_WIN32) && ! defined(__USE_MINGW_ANSI_STDIO)
82+# define EXPAT_FMT_ULL(midpart) "%" midpart "I64u"
83+# if defined(_WIN64) // Note: modifier "td" does not work for MinGW
84+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
85+# else
86+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
87+# endif
88+#else
89+# define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
90+# if ! defined(ULONG_MAX)
91+# error Compiler did not define ULONG_MAX for us
92+# elif ULONG_MAX == 18446744073709551615u // 2^64-1
93+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
94+# else
95+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
96+# endif
97+#endif
98+
99 #ifndef UNUSED_P
100 # define UNUSED_P(p) (void)p
101 #endif
102
103+/* NOTE BEGIN If you ever patch these defaults to greater values
104+ for non-attack XML payload in your environment,
105+ please file a bug report with libexpat. Thank you!
106+*/
107+#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT \
108+ 100.0f
109+#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT \
110+ 8388608 // 8 MiB, 2^23
111+/* NOTE END */
112+
113 #ifdef __cplusplus
114 extern "C" {
115 #endif
116diff --git a/lib/libexpat.def b/lib/libexpat.def
117index 16faf595..5aefa6df 100644
118--- a/lib/libexpat.def
119+++ b/lib/libexpat.def
120@@ -76,3 +76,6 @@ EXPORTS
121 XML_SetHashSalt @67
122 ; added with version 2.2.5
123 _INTERNAL_trim_to_complete_utf8_characters @68
124+; added with version 2.4.0
125+ XML_SetBillionLaughsAttackProtectionActivationThreshold @69
126+ XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
127diff --git a/lib/libexpatw.def b/lib/libexpatw.def
128index 16faf595..5aefa6df 100644
129--- a/lib/libexpatw.def
130+++ b/lib/libexpatw.def
131@@ -76,3 +76,6 @@ EXPORTS
132 XML_SetHashSalt @67
133 ; added with version 2.2.5
134 _INTERNAL_trim_to_complete_utf8_characters @68
135+; added with version 2.4.0
136+ XML_SetBillionLaughsAttackProtectionActivationThreshold @69
137+ XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
138diff --git a/lib/xmlparse.c b/lib/xmlparse.c
139index 3aaf35b9..6790bc28 100644
140--- a/lib/xmlparse.c
141+++ b/lib/xmlparse.c
142@@ -47,6 +47,8 @@
143 #include <limits.h> /* UINT_MAX */
144 #include <stdio.h> /* fprintf */
145 #include <stdlib.h> /* getenv, rand_s */
146+#include <stdint.h> /* uintptr_t */
147+#include <math.h> /* isnan */
148
149 #ifdef _WIN32
150 # define getpid GetCurrentProcessId
151@@ -373,6 +375,31 @@ typedef struct open_internal_entity {
152 XML_Bool betweenDecl; /* WFC: PE Between Declarations */
153 } OPEN_INTERNAL_ENTITY;
154
155+enum XML_Account {
156+ XML_ACCOUNT_DIRECT, /* bytes directly passed to the Expat parser */
157+ XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during entity
158+ expansion */
159+ XML_ACCOUNT_NONE /* i.e. do not account, was accounted already */
160+};
161+
162+#ifdef XML_DTD
163+typedef unsigned long long XmlBigCount;
164+typedef struct accounting {
165+ XmlBigCount countBytesDirect;
166+ XmlBigCount countBytesIndirect;
167+ int debugLevel;
168+ float maximumAmplificationFactor; // >=1.0
169+ unsigned long long activationThresholdBytes;
170+} ACCOUNTING;
171+
172+typedef struct entity_stats {
173+ unsigned int countEverOpened;
174+ unsigned int currentDepth;
175+ unsigned int maximumDepthSeen;
176+ int debugLevel;
177+} ENTITY_STATS;
178+#endif /* XML_DTD */
179+
180 typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
181 const char *end, const char **endPtr);
182
183@@ -403,16 +430,18 @@ static enum XML_Error initializeEncoding(XML_Parser parser);
184 static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
185 const char *s, const char *end, int tok,
186 const char *next, const char **nextPtr,
187- XML_Bool haveMore, XML_Bool allowClosingDoctype);
188+ XML_Bool haveMore, XML_Bool allowClosingDoctype,
189+ enum XML_Account account);
190 static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
191 XML_Bool betweenDecl);
192 static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
193 const ENCODING *enc, const char *start,
194 const char *end, const char **endPtr,
195- XML_Bool haveMore);
196+ XML_Bool haveMore, enum XML_Account account);
197 static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *,
198 const char **startPtr, const char *end,
199- const char **nextPtr, XML_Bool haveMore);
200+ const char **nextPtr, XML_Bool haveMore,
201+ enum XML_Account account);
202 #ifdef XML_DTD
203 static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
204 const char **startPtr, const char *end,
205@@ -422,7 +451,8 @@ static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
206 static void freeBindings(XML_Parser parser, BINDING *bindings);
207 static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
208 const char *s, TAG_NAME *tagNamePtr,
209- BINDING **bindingsPtr);
210+ BINDING **bindingsPtr,
211+ enum XML_Account account);
212 static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
213 const ATTRIBUTE_ID *attId, const XML_Char *uri,
214 BINDING **bindingsPtr);
215@@ -431,15 +461,18 @@ static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
216 XML_Parser parser);
217 static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *,
218 XML_Bool isCdata, const char *,
219- const char *, STRING_POOL *);
220+ const char *, STRING_POOL *,
221+ enum XML_Account account);
222 static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
223 XML_Bool isCdata, const char *,
224- const char *, STRING_POOL *);
225+ const char *, STRING_POOL *,
226+ enum XML_Account account);
227 static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
228 const char *start, const char *end);
229 static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
230 static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
231- const char *start, const char *end);
232+ const char *start, const char *end,
233+ enum XML_Account account);
234 static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
235 const char *start, const char *end);
236 static int reportComment(XML_Parser parser, const ENCODING *enc,
237@@ -503,6 +536,35 @@ static XML_Parser parserCreate(const XML_Char *encodingName,
238
239 static void parserInit(XML_Parser parser, const XML_Char *encodingName);
240
241+#ifdef XML_DTD
242+static float accountingGetCurrentAmplification(XML_Parser rootParser);
243+static void accountingReportStats(XML_Parser originParser, const char *epilog);
244+static void accountingOnAbort(XML_Parser originParser);
245+static void accountingReportDiff(XML_Parser rootParser,
246+ unsigned int levelsAwayFromRootParser,
247+ const char *before, const char *after,
248+ ptrdiff_t bytesMore, int source_line,
249+ enum XML_Account account);
250+static XML_Bool accountingDiffTolerated(XML_Parser originParser, int tok,
251+ const char *before, const char *after,
252+ int source_line,
253+ enum XML_Account account);
254+
255+static void entityTrackingReportStats(XML_Parser parser, ENTITY *entity,
256+ const char *action, int sourceLine);
257+static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
258+ int sourceLine);
259+static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
260+ int sourceLine);
261+
262+static XML_Parser getRootParserOf(XML_Parser parser,
263+ unsigned int *outLevelDiff);
264+static const char *unsignedCharToPrintable(unsigned char c);
265+#endif /* XML_DTD */
266+
267+static unsigned long getDebugLevel(const char *variableName,
268+ unsigned long defaultDebugLevel);
269+
270 #define poolStart(pool) ((pool)->start)
271 #define poolEnd(pool) ((pool)->ptr)
272 #define poolLength(pool) ((pool)->ptr - (pool)->start)
273@@ -616,6 +678,10 @@ struct XML_ParserStruct {
274 enum XML_ParamEntityParsing m_paramEntityParsing;
275 #endif
276 unsigned long m_hash_secret_salt;
277+#ifdef XML_DTD
278+ ACCOUNTING m_accounting;
279+ ENTITY_STATS m_entity_stats;
280+#endif
281 };
282
283 #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
284@@ -1055,6 +1121,18 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
285 parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
286 #endif
287 parser->m_hash_secret_salt = 0;
288+
289+#ifdef XML_DTD
290+ memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
291+ parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
292+ parser->m_accounting.maximumAmplificationFactor
293+ = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
294+ parser->m_accounting.activationThresholdBytes
295+ = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
296+
297+ memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
298+ parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
299+#endif
300 }
301
302 /* moves list of bindings to m_freeBindingList */
303@@ -2318,6 +2396,10 @@ XML_ErrorString(enum XML_Error code) {
304 /* Added in 2.2.5. */
305 case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
306 return XML_L("invalid argument");
307+ /* Added in 2.4.0. */
308+ case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
309+ return XML_L(
310+ "limit on input amplification factor (from DTD and entities) breached");
311 }
312 return NULL;
313 }
314@@ -2354,41 +2436,75 @@ XML_ExpatVersionInfo(void) {
315
316 const XML_Feature *XMLCALL
317 XML_GetFeatureList(void) {
318- static const XML_Feature features[]
319- = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
320- sizeof(XML_Char)},
321- {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
322- sizeof(XML_LChar)},
323+ static const XML_Feature features[] = {
324+ {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
325+ sizeof(XML_Char)},
326+ {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
327+ sizeof(XML_LChar)},
328 #ifdef XML_UNICODE
329- {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
330+ {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
331 #endif
332 #ifdef XML_UNICODE_WCHAR_T
333- {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
334+ {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
335 #endif
336 #ifdef XML_DTD
337- {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
338+ {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
339 #endif
340 #ifdef XML_CONTEXT_BYTES
341- {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
342- XML_CONTEXT_BYTES},
343+ {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
344+ XML_CONTEXT_BYTES},
345 #endif
346 #ifdef XML_MIN_SIZE
347- {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
348+ {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
349 #endif
350 #ifdef XML_NS
351- {XML_FEATURE_NS, XML_L("XML_NS"), 0},
352+ {XML_FEATURE_NS, XML_L("XML_NS"), 0},
353 #endif
354 #ifdef XML_LARGE_SIZE
355- {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
356+ {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
357 #endif
358 #ifdef XML_ATTR_INFO
359- {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
360+ {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
361 #endif
362- {XML_FEATURE_END, NULL, 0}};
363+#ifdef XML_DTD
364+ /* Added in Expat 2.4.0. */
365+ {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
366+ XML_L("XML_BLAP_MAX_AMP"),
367+ (long int)
368+ EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT},
369+ {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
370+ XML_L("XML_BLAP_ACT_THRES"),
371+ EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
372+#endif
373+ {XML_FEATURE_END, NULL, 0}};
374
375 return features;
376 }
377
378+#ifdef XML_DTD
379+XML_Bool XMLCALL
380+XML_SetBillionLaughsAttackProtectionMaximumAmplification(
381+ XML_Parser parser, float maximumAmplificationFactor) {
382+ if ((parser == NULL) || (parser->m_parentParser != NULL)
383+ || isnan(maximumAmplificationFactor)
384+ || (maximumAmplificationFactor < 1.0f)) {
385+ return XML_FALSE;
386+ }
387+ parser->m_accounting.maximumAmplificationFactor = maximumAmplificationFactor;
388+ return XML_TRUE;
389+}
390+
391+XML_Bool XMLCALL
392+XML_SetBillionLaughsAttackProtectionActivationThreshold(
393+ XML_Parser parser, unsigned long long activationThresholdBytes) {
394+ if ((parser == NULL) || (parser->m_parentParser != NULL)) {
395+ return XML_FALSE;
396+ }
397+ parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
398+ return XML_TRUE;
399+}
400+#endif /* XML_DTD */
401+
402 /* Initially tag->rawName always points into the parse buffer;
403 for those TAG instances opened while the current parse buffer was
404 processed, and not yet closed, we need to store tag->rawName in a more
405@@ -2441,9 +2557,9 @@ storeRawNames(XML_Parser parser) {
406 static enum XML_Error PTRCALL
407 contentProcessor(XML_Parser parser, const char *start, const char *end,
408 const char **endPtr) {
409- enum XML_Error result
410- = doContent(parser, 0, parser->m_encoding, start, end, endPtr,
411- (XML_Bool)! parser->m_parsingStatus.finalBuffer);
412+ enum XML_Error result = doContent(
413+ parser, 0, parser->m_encoding, start, end, endPtr,
414+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
415 if (result == XML_ERROR_NONE) {
416 if (! storeRawNames(parser))
417 return XML_ERROR_NO_MEMORY;
418@@ -2468,6 +2584,14 @@ externalEntityInitProcessor2(XML_Parser parser, const char *start,
419 int tok = XmlContentTok(parser->m_encoding, start, end, &next);
420 switch (tok) {
421 case XML_TOK_BOM:
422+#ifdef XML_DTD
423+ if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
424+ XML_ACCOUNT_DIRECT)) {
425+ accountingOnAbort(parser);
426+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
427+ }
428+#endif /* XML_DTD */
429+
430 /* If we are at the end of the buffer, this would cause the next stage,
431 i.e. externalEntityInitProcessor3, to pass control directly to
432 doContent (by detecting XML_TOK_NONE) without processing any xml text
433@@ -2505,6 +2629,10 @@ externalEntityInitProcessor3(XML_Parser parser, const char *start,
434 const char *next = start; /* XmlContentTok doesn't always set the last arg */
435 parser->m_eventPtr = start;
436 tok = XmlContentTok(parser->m_encoding, start, end, &next);
437+ /* Note: These bytes are accounted later in:
438+ - processXmlDecl
439+ - externalEntityContentProcessor
440+ */
441 parser->m_eventEndPtr = next;
442
443 switch (tok) {
444@@ -2546,7 +2674,8 @@ externalEntityContentProcessor(XML_Parser parser, const char *start,
445 const char *end, const char **endPtr) {
446 enum XML_Error result
447 = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
448- (XML_Bool)! parser->m_parsingStatus.finalBuffer);
449+ (XML_Bool)! parser->m_parsingStatus.finalBuffer,
450+ XML_ACCOUNT_ENTITY_EXPANSION);
451 if (result == XML_ERROR_NONE) {
452 if (! storeRawNames(parser))
453 return XML_ERROR_NO_MEMORY;
454@@ -2557,7 +2686,7 @@ externalEntityContentProcessor(XML_Parser parser, const char *start,
455 static enum XML_Error
456 doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
457 const char *s, const char *end, const char **nextPtr,
458- XML_Bool haveMore) {
459+ XML_Bool haveMore, enum XML_Account account) {
460 /* save one level of indirection */
461 DTD *const dtd = parser->m_dtd;
462
463@@ -2575,6 +2704,17 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
464 for (;;) {
465 const char *next = s; /* XmlContentTok doesn't always set the last arg */
466 int tok = XmlContentTok(enc, s, end, &next);
467+#ifdef XML_DTD
468+ const char *accountAfter
469+ = ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR))
470+ ? (haveMore ? s /* i.e. 0 bytes */ : end)
471+ : next;
472+ if (! accountingDiffTolerated(parser, tok, s, accountAfter, __LINE__,
473+ account)) {
474+ accountingOnAbort(parser);
475+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
476+ }
477+#endif
478 *eventEndPP = next;
479 switch (tok) {
480 case XML_TOK_TRAILING_CR:
481@@ -2630,6 +2770,14 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
482 XML_Char ch = (XML_Char)XmlPredefinedEntityName(
483 enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
484 if (ch) {
485+#ifdef XML_DTD
486+ /* NOTE: We are replacing 4-6 characters original input for 1 character
487+ * so there is no amplification and hence recording without
488+ * protection. */
489+ accountingDiffTolerated(parser, tok, (char *)&ch,
490+ ((char *)&ch) + sizeof(XML_Char), __LINE__,
491+ XML_ACCOUNT_ENTITY_EXPANSION);
492+#endif /* XML_DTD */
493 if (parser->m_characterDataHandler)
494 parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
495 else if (parser->m_defaultHandler)
496@@ -2748,7 +2896,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
497 }
498 tag->name.str = (XML_Char *)tag->buf;
499 *toPtr = XML_T('\0');
500- result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
501+ result
502+ = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account);
503 if (result)
504 return result;
505 if (parser->m_startElementHandler)
506@@ -2772,7 +2921,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
507 if (! name.str)
508 return XML_ERROR_NO_MEMORY;
509 poolFinish(&parser->m_tempPool);
510- result = storeAtts(parser, enc, s, &name, &bindings);
511+ result = storeAtts(parser, enc, s, &name, &bindings,
512+ XML_ACCOUNT_NONE /* token spans whole start tag */);
513 if (result != XML_ERROR_NONE) {
514 freeBindings(parser, bindings);
515 return result;
516@@ -2907,7 +3057,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
517 /* END disabled code */
518 else if (parser->m_defaultHandler)
519 reportDefault(parser, enc, s, next);
520- result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
521+ result
522+ = doCdataSection(parser, enc, &next, end, nextPtr, haveMore, account);
523 if (result != XML_ERROR_NONE)
524 return result;
525 else if (! next) {
526@@ -3036,7 +3187,8 @@ freeBindings(XML_Parser parser, BINDING *bindings) {
527 */
528 static enum XML_Error
529 storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
530- TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
531+ TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
532+ enum XML_Account account) {
533 DTD *const dtd = parser->m_dtd; /* save one level of indirection */
534 ELEMENT_TYPE *elementType;
535 int nDefaultAtts;
536@@ -3146,7 +3298,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
537 /* normalize the attribute value */
538 result = storeAttributeValue(
539 parser, enc, isCdata, parser->m_atts[i].valuePtr,
540- parser->m_atts[i].valueEnd, &parser->m_tempPool);
541+ parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
542 if (result)
543 return result;
544 appAtts[attIndex] = poolStart(&parser->m_tempPool);
545@@ -3535,9 +3687,9 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
546 static enum XML_Error PTRCALL
547 cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
548 const char **endPtr) {
549- enum XML_Error result
550- = doCdataSection(parser, parser->m_encoding, &start, end, endPtr,
551- (XML_Bool)! parser->m_parsingStatus.finalBuffer);
552+ enum XML_Error result = doCdataSection(
553+ parser, parser->m_encoding, &start, end, endPtr,
554+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
555 if (result != XML_ERROR_NONE)
556 return result;
557 if (start) {
558@@ -3557,7 +3709,8 @@ cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
559 */
560 static enum XML_Error
561 doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
562- const char *end, const char **nextPtr, XML_Bool haveMore) {
563+ const char *end, const char **nextPtr, XML_Bool haveMore,
564+ enum XML_Account account) {
565 const char *s = *startPtr;
566 const char **eventPP;
567 const char **eventEndPP;
568@@ -3575,6 +3728,14 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
569 for (;;) {
570 const char *next;
571 int tok = XmlCdataSectionTok(enc, s, end, &next);
572+#ifdef XML_DTD
573+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
574+ accountingOnAbort(parser);
575+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
576+ }
577+#else
578+ UNUSED_P(account);
579+#endif
580 *eventEndPP = next;
581 switch (tok) {
582 case XML_TOK_CDATA_SECT_CLOSE:
583@@ -3719,6 +3880,13 @@ doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
584 *eventPP = s;
585 *startPtr = NULL;
586 tok = XmlIgnoreSectionTok(enc, s, end, &next);
587+# ifdef XML_DTD
588+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
589+ XML_ACCOUNT_DIRECT)) {
590+ accountingOnAbort(parser);
591+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
592+ }
593+# endif
594 *eventEndPP = next;
595 switch (tok) {
596 case XML_TOK_IGNORE_SECT:
597@@ -3803,6 +3971,15 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s,
598 const char *versionend;
599 const XML_Char *storedversion = NULL;
600 int standalone = -1;
601+
602+#ifdef XML_DTD
603+ if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__,
604+ XML_ACCOUNT_DIRECT)) {
605+ accountingOnAbort(parser);
606+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
607+ }
608+#endif
609+
610 if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
611 isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr,
612 &version, &versionend, &encodingName, &newEncoding, &standalone)) {
613@@ -3952,6 +4129,10 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
614
615 for (;;) {
616 tok = XmlPrologTok(parser->m_encoding, start, end, &next);
617+ /* Note: Except for XML_TOK_BOM below, these bytes are accounted later in:
618+ - storeEntityValue
619+ - processXmlDecl
620+ */
621 parser->m_eventEndPtr = next;
622 if (tok <= 0) {
623 if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
624@@ -3970,7 +4151,8 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
625 break;
626 }
627 /* found end of entity value - can store it now */
628- return storeEntityValue(parser, parser->m_encoding, s, end);
629+ return storeEntityValue(parser, parser->m_encoding, s, end,
630+ XML_ACCOUNT_DIRECT);
631 } else if (tok == XML_TOK_XML_DECL) {
632 enum XML_Error result;
633 result = processXmlDecl(parser, 0, start, next);
634@@ -3997,6 +4179,14 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
635 */
636 else if (tok == XML_TOK_BOM && next == end
637 && ! parser->m_parsingStatus.finalBuffer) {
638+# ifdef XML_DTD
639+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
640+ XML_ACCOUNT_DIRECT)) {
641+ accountingOnAbort(parser);
642+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
643+ }
644+# endif
645+
646 *nextPtr = next;
647 return XML_ERROR_NONE;
648 }
649@@ -4039,16 +4229,24 @@ externalParEntProcessor(XML_Parser parser, const char *s, const char *end,
650 }
651 /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
652 However, when parsing an external subset, doProlog will not accept a BOM
653- as valid, and report a syntax error, so we have to skip the BOM
654+ as valid, and report a syntax error, so we have to skip the BOM, and
655+ account for the BOM bytes.
656 */
657 else if (tok == XML_TOK_BOM) {
658+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
659+ XML_ACCOUNT_DIRECT)) {
660+ accountingOnAbort(parser);
661+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
662+ }
663+
664 s = next;
665 tok = XmlPrologTok(parser->m_encoding, s, end, &next);
666 }
667
668 parser->m_processor = prologProcessor;
669 return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
670- (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
671+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
672+ XML_ACCOUNT_DIRECT);
673 }
674
675 static enum XML_Error PTRCALL
676@@ -4061,6 +4259,9 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
677
678 for (;;) {
679 tok = XmlPrologTok(enc, start, end, &next);
680+ /* Note: These bytes are accounted later in:
681+ - storeEntityValue
682+ */
683 if (tok <= 0) {
684 if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
685 *nextPtr = s;
686@@ -4078,7 +4279,7 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
687 break;
688 }
689 /* found end of entity value - can store it now */
690- return storeEntityValue(parser, enc, s, end);
691+ return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT);
692 }
693 start = next;
694 }
695@@ -4092,13 +4293,14 @@ prologProcessor(XML_Parser parser, const char *s, const char *end,
696 const char *next = s;
697 int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
698 return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
699- (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
700+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
701+ XML_ACCOUNT_DIRECT);
702 }
703
704 static enum XML_Error
705 doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
706 int tok, const char *next, const char **nextPtr, XML_Bool haveMore,
707- XML_Bool allowClosingDoctype) {
708+ XML_Bool allowClosingDoctype, enum XML_Account account) {
709 #ifdef XML_DTD
710 static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
711 #endif /* XML_DTD */
712@@ -4125,6 +4327,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
713 static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
714 static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
715
716+#ifndef XML_DTD
717+ UNUSED_P(account);
718+#endif
719+
720 /* save one level of indirection */
721 DTD *const dtd = parser->m_dtd;
722
723@@ -4189,6 +4395,19 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
724 }
725 }
726 role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
727+#ifdef XML_DTD
728+ switch (role) {
729+ case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor
730+ case XML_ROLE_XML_DECL: // bytes accounted in processXmlDecl
731+ case XML_ROLE_TEXT_DECL: // bytes accounted in processXmlDecl
732+ break;
733+ default:
734+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
735+ accountingOnAbort(parser);
736+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
737+ }
738+ }
739+#endif
740 switch (role) {
741 case XML_ROLE_XML_DECL: {
742 enum XML_Error result = processXmlDecl(parser, 0, s, next);
743@@ -4464,7 +4683,8 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
744 const XML_Char *attVal;
745 enum XML_Error result = storeAttributeValue(
746 parser, enc, parser->m_declAttributeIsCdata,
747- s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool);
748+ s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool,
749+ XML_ACCOUNT_NONE);
750 if (result)
751 return result;
752 attVal = poolStart(&dtd->pool);
753@@ -4497,8 +4717,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
754 break;
755 case XML_ROLE_ENTITY_VALUE:
756 if (dtd->keepProcessing) {
757- enum XML_Error result = storeEntityValue(
758- parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
759+ enum XML_Error result
760+ = storeEntityValue(parser, enc, s + enc->minBytesPerChar,
761+ next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
762 if (parser->m_declEntity) {
763 parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
764 parser->m_declEntity->textLen
765@@ -4888,12 +5109,15 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
766 if (parser->m_externalEntityRefHandler) {
767 dtd->paramEntityRead = XML_FALSE;
768 entity->open = XML_TRUE;
769+ entityTrackingOnOpen(parser, entity, __LINE__);
770 if (! parser->m_externalEntityRefHandler(
771 parser->m_externalEntityRefHandlerArg, 0, entity->base,
772 entity->systemId, entity->publicId)) {
773+ entityTrackingOnClose(parser, entity, __LINE__);
774 entity->open = XML_FALSE;
775 return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
776 }
777+ entityTrackingOnClose(parser, entity, __LINE__);
778 entity->open = XML_FALSE;
779 handleDefault = XML_FALSE;
780 if (! dtd->paramEntityRead) {
781@@ -5091,6 +5315,13 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
782 for (;;) {
783 const char *next = NULL;
784 int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
785+#ifdef XML_DTD
786+ if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
787+ XML_ACCOUNT_DIRECT)) {
788+ accountingOnAbort(parser);
789+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
790+ }
791+#endif
792 parser->m_eventEndPtr = next;
793 switch (tok) {
794 /* report partial linebreak - it might be the last token */
795@@ -5164,6 +5395,9 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
796 return XML_ERROR_NO_MEMORY;
797 }
798 entity->open = XML_TRUE;
799+#ifdef XML_DTD
800+ entityTrackingOnOpen(parser, entity, __LINE__);
801+#endif
802 entity->processed = 0;
803 openEntity->next = parser->m_openInternalEntities;
804 parser->m_openInternalEntities = openEntity;
805@@ -5182,17 +5416,22 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
806 int tok
807 = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
808 result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
809- tok, next, &next, XML_FALSE, XML_FALSE);
810+ tok, next, &next, XML_FALSE, XML_FALSE,
811+ XML_ACCOUNT_ENTITY_EXPANSION);
812 } else
813 #endif /* XML_DTD */
814 result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
815- textStart, textEnd, &next, XML_FALSE);
816+ textStart, textEnd, &next, XML_FALSE,
817+ XML_ACCOUNT_ENTITY_EXPANSION);
818
819 if (result == XML_ERROR_NONE) {
820 if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
821 entity->processed = (int)(next - textStart);
822 parser->m_processor = internalEntityProcessor;
823 } else {
824+#ifdef XML_DTD
825+ entityTrackingOnClose(parser, entity, __LINE__);
826+#endif /* XML_DTD */
827 entity->open = XML_FALSE;
828 parser->m_openInternalEntities = openEntity->next;
829 /* put openEntity back in list of free instances */
830@@ -5225,12 +5464,13 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
831 int tok
832 = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
833 result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
834- tok, next, &next, XML_FALSE, XML_TRUE);
835+ tok, next, &next, XML_FALSE, XML_TRUE,
836+ XML_ACCOUNT_ENTITY_EXPANSION);
837 } else
838 #endif /* XML_DTD */
839 result = doContent(parser, openEntity->startTagLevel,
840 parser->m_internalEncoding, textStart, textEnd, &next,
841- XML_FALSE);
842+ XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
843
844 if (result != XML_ERROR_NONE)
845 return result;
846@@ -5239,6 +5479,9 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
847 entity->processed = (int)(next - (char *)entity->textPtr);
848 return result;
849 } else {
850+#ifdef XML_DTD
851+ entityTrackingOnClose(parser, entity, __LINE__);
852+#endif
853 entity->open = XML_FALSE;
854 parser->m_openInternalEntities = openEntity->next;
855 /* put openEntity back in list of free instances */
856@@ -5252,7 +5495,8 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
857 parser->m_processor = prologProcessor;
858 tok = XmlPrologTok(parser->m_encoding, s, end, &next);
859 return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
860- (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
861+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
862+ XML_ACCOUNT_DIRECT);
863 } else
864 #endif /* XML_DTD */
865 {
866@@ -5260,7 +5504,8 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
867 /* see externalEntityContentProcessor vs contentProcessor */
868 return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding,
869 s, end, nextPtr,
870- (XML_Bool)! parser->m_parsingStatus.finalBuffer);
871+ (XML_Bool)! parser->m_parsingStatus.finalBuffer,
872+ XML_ACCOUNT_DIRECT);
873 }
874 }
875
876@@ -5275,9 +5520,10 @@ errorProcessor(XML_Parser parser, const char *s, const char *end,
877
878 static enum XML_Error
879 storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
880- const char *ptr, const char *end, STRING_POOL *pool) {
881+ const char *ptr, const char *end, STRING_POOL *pool,
882+ enum XML_Account account) {
883 enum XML_Error result
884- = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
885+ = appendAttributeValue(parser, enc, isCdata, ptr, end, pool, account);
886 if (result)
887 return result;
888 if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
889@@ -5289,11 +5535,22 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
890
891 static enum XML_Error
892 appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
893- const char *ptr, const char *end, STRING_POOL *pool) {
894+ const char *ptr, const char *end, STRING_POOL *pool,
895+ enum XML_Account account) {
896 DTD *const dtd = parser->m_dtd; /* save one level of indirection */
897+#ifndef XML_DTD
898+ UNUSED_P(account);
899+#endif
900+
901 for (;;) {
902 const char *next;
903 int tok = XmlAttributeValueTok(enc, ptr, end, &next);
904+#ifdef XML_DTD
905+ if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
906+ accountingOnAbort(parser);
907+ return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
908+ }
909+#endif
910 switch (tok) {
911 case XML_TOK_NONE:
912 return XML_ERROR_NONE;
913@@ -5353,6 +5610,14 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
914 XML_Char ch = (XML_Char)XmlPredefinedEntityName(
915 enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
916 if (ch) {
917+#ifdef XML_DTD
918+ /* NOTE: We are replacing 4-6 characters original input for 1 character
919+ * so there is no amplification and hence recording without
920+ * protection. */
921+ accountingDiffTolerated(parser, tok, (char *)&ch,
922+ ((char *)&ch) + sizeof(XML_Char), __LINE__,
923+ XML_ACCOUNT_ENTITY_EXPANSION);
924+#endif /* XML_DTD */
925 if (! poolAppendChar(pool, ch))
926 return XML_ERROR_NO_MEMORY;
927 break;
928@@ -5430,9 +5695,16 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
929 enum XML_Error result;
930 const XML_Char *textEnd = entity->textPtr + entity->textLen;
931 entity->open = XML_TRUE;
932+#ifdef XML_DTD
933+ entityTrackingOnOpen(parser, entity, __LINE__);
934+#endif
935 result = appendAttributeValue(parser, parser->m_internalEncoding,
936- isCdata, (char *)entity->textPtr,
937- (char *)textEnd, pool);
938+ isCdata, (const char *)entity->textPtr,
939+ (const char *)textEnd, pool,
940+ XML_ACCOUNT_ENTITY_EXPANSION);
941+#ifdef XML_DTD
942+ entityTrackingOnClose(parser, entity, __LINE__);
943+#endif
944 entity->open = XML_FALSE;
945 if (result)
946 return result;
947@@ -5462,13 +5734,16 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
948
949 static enum XML_Error
950 storeEntityValue(XML_Parser parser, const ENCODING *enc,
951- const char *entityTextPtr, const char *entityTextEnd) {
952+ const char *entityTextPtr, const char *entityTextEnd,
953+ enum XML_Account account) {
954 DTD *const dtd = parser->m_dtd; /* save one level of indirection */
955 STRING_POOL *pool = &(dtd->entityValuePool);
956 enum XML_Error result = XML_ERROR_NONE;
957 #ifdef XML_DTD
958 int oldInEntityValue = parser->m_prologState.inEntityValue;
959 parser->m_prologState.inEntityValue = 1;
960+#else
961+ UNUSED_P(account);
962 #endif /* XML_DTD */
963 /* never return Null for the value argument in EntityDeclHandler,
964 since this would indicate an external entity; therefore we
965@@ -5481,6 +5756,16 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
966 for (;;) {
967 const char *next;
968 int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
969+
970+#ifdef XML_DTD
971+ if (! accountingDiffTolerated(parser, tok, entityTextPtr, next, __LINE__,
972+ account)) {
973+ accountingOnAbort(parser);
974+ result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
975+ goto endEntityValue;
976+ }
977+#endif
978+
979 switch (tok) {
980 case XML_TOK_PARAM_ENTITY_REF:
981 #ifdef XML_DTD
982@@ -5516,13 +5801,16 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
983 if (parser->m_externalEntityRefHandler) {
984 dtd->paramEntityRead = XML_FALSE;
985 entity->open = XML_TRUE;
986+ entityTrackingOnOpen(parser, entity, __LINE__);
987 if (! parser->m_externalEntityRefHandler(
988 parser->m_externalEntityRefHandlerArg, 0, entity->base,
989 entity->systemId, entity->publicId)) {
990+ entityTrackingOnClose(parser, entity, __LINE__);
991 entity->open = XML_FALSE;
992 result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
993 goto endEntityValue;
994 }
995+ entityTrackingOnClose(parser, entity, __LINE__);
996 entity->open = XML_FALSE;
997 if (! dtd->paramEntityRead)
998 dtd->keepProcessing = dtd->standalone;
999@@ -5530,9 +5818,12 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
1000 dtd->keepProcessing = dtd->standalone;
1001 } else {
1002 entity->open = XML_TRUE;
1003+ entityTrackingOnOpen(parser, entity, __LINE__);
1004 result = storeEntityValue(
1005- parser, parser->m_internalEncoding, (char *)entity->textPtr,
1006- (char *)(entity->textPtr + entity->textLen));
1007+ parser, parser->m_internalEncoding, (const char *)entity->textPtr,
1008+ (const char *)(entity->textPtr + entity->textLen),
1009+ XML_ACCOUNT_ENTITY_EXPANSION);
1010+ entityTrackingOnClose(parser, entity, __LINE__);
1011 entity->open = XML_FALSE;
1012 if (result)
1013 goto endEntityValue;
1014@@ -6893,3 +7184,741 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
1015 memcpy(result, s, charsRequired * sizeof(XML_Char));
1016 return result;
1017 }
1018+
1019+#ifdef XML_DTD
1020+
1021+static float
1022+accountingGetCurrentAmplification(XML_Parser rootParser) {
1023+ const XmlBigCount countBytesOutput
1024+ = rootParser->m_accounting.countBytesDirect
1025+ + rootParser->m_accounting.countBytesIndirect;
1026+ const float amplificationFactor
1027+ = rootParser->m_accounting.countBytesDirect
1028+ ? (countBytesOutput
1029+ / (float)(rootParser->m_accounting.countBytesDirect))
1030+ : 1.0f;
1031+ assert(! rootParser->m_parentParser);
1032+ return amplificationFactor;
1033+}
1034+
1035+static void
1036+accountingReportStats(XML_Parser originParser, const char *epilog) {
1037+ const XML_Parser rootParser = getRootParserOf(originParser, NULL);
1038+ assert(! rootParser->m_parentParser);
1039+
1040+ if (rootParser->m_accounting.debugLevel < 1) {
1041+ return;
1042+ }
1043+
1044+ const float amplificationFactor
1045+ = accountingGetCurrentAmplification(rootParser);
1046+ fprintf(stderr,
1047+ "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
1048+ "10") ", indirect " EXPAT_FMT_ULL("10") ", amplification %8.2f%s",
1049+ (void *)rootParser, rootParser->m_accounting.countBytesDirect,
1050+ rootParser->m_accounting.countBytesIndirect,
1051+ (double)amplificationFactor, epilog);
1052+}
1053+
1054+static void
1055+accountingOnAbort(XML_Parser originParser) {
1056+ accountingReportStats(originParser, " ABORTING\n");
1057+}
1058+
1059+static void
1060+accountingReportDiff(XML_Parser rootParser,
1061+ unsigned int levelsAwayFromRootParser, const char *before,
1062+ const char *after, ptrdiff_t bytesMore, int source_line,
1063+ enum XML_Account account) {
1064+ assert(! rootParser->m_parentParser);
1065+
1066+ fprintf(stderr,
1067+ " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d, xmlparse.c:%d) %*s\"",
1068+ bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
1069+ levelsAwayFromRootParser, source_line, 10, "");
1070+
1071+ const char ellipis[] = "[..]";
1072+ const size_t ellipsisLength = sizeof(ellipis) /* because compile-time */ - 1;
1073+ const unsigned int contextLength = 10;
1074+
1075+ /* Note: Performance is of no concern here */
1076+ const char *walker = before;
1077+ if ((rootParser->m_accounting.debugLevel >= 3)
1078+ || (after - before)
1079+ <= (ptrdiff_t)(contextLength + ellipsisLength + contextLength)) {
1080+ for (; walker < after; walker++) {
1081+ fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
1082+ }
1083+ } else {
1084+ for (; walker < before + contextLength; walker++) {
1085+ fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
1086+ }
1087+ fprintf(stderr, ellipis);
1088+ walker = after - contextLength;
1089+ for (; walker < after; walker++) {
1090+ fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
1091+ }
1092+ }
1093+ fprintf(stderr, "\"\n");
1094+}
1095+
1096+static XML_Bool
1097+accountingDiffTolerated(XML_Parser originParser, int tok, const char *before,
1098+ const char *after, int source_line,
1099+ enum XML_Account account) {
1100+ /* Note: We need to check the token type *first* to be sure that
1101+ * we can even access variable <after>, safely.
1102+ * E.g. for XML_TOK_NONE <after> may hold an invalid pointer. */
1103+ switch (tok) {
1104+ case XML_TOK_INVALID:
1105+ case XML_TOK_PARTIAL:
1106+ case XML_TOK_PARTIAL_CHAR:
1107+ case XML_TOK_NONE:
1108+ return XML_TRUE;
1109+ }
1110+
1111+ if (account == XML_ACCOUNT_NONE)
1112+ return XML_TRUE; /* because these bytes have been accounted for, already */
1113+
1114+ unsigned int levelsAwayFromRootParser;
1115+ const XML_Parser rootParser
1116+ = getRootParserOf(originParser, &levelsAwayFromRootParser);
1117+ assert(! rootParser->m_parentParser);
1118+
1119+ const int isDirect
1120+ = (account == XML_ACCOUNT_DIRECT) && (originParser == rootParser);
1121+ const ptrdiff_t bytesMore = after - before;
1122+
1123+ XmlBigCount *const additionTarget
1124+ = isDirect ? &rootParser->m_accounting.countBytesDirect
1125+ : &rootParser->m_accounting.countBytesIndirect;
1126+
1127+ /* Detect and avoid integer overflow */
1128+ if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
1129+ return XML_FALSE;
1130+ *additionTarget += bytesMore;
1131+
1132+ const XmlBigCount countBytesOutput
1133+ = rootParser->m_accounting.countBytesDirect
1134+ + rootParser->m_accounting.countBytesIndirect;
1135+ const float amplificationFactor
1136+ = accountingGetCurrentAmplification(rootParser);
1137+ const XML_Bool tolerated
1138+ = (countBytesOutput < rootParser->m_accounting.activationThresholdBytes)
1139+ || (amplificationFactor
1140+ <= rootParser->m_accounting.maximumAmplificationFactor);
1141+
1142+ if (rootParser->m_accounting.debugLevel >= 2) {
1143+ accountingReportStats(rootParser, "");
1144+ accountingReportDiff(rootParser, levelsAwayFromRootParser, before, after,
1145+ bytesMore, source_line, account);
1146+ }
1147+
1148+ return tolerated;
1149+}
1150+
1151+static void
1152+entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
1153+ const char *action, int sourceLine) {
1154+ assert(! rootParser->m_parentParser);
1155+ if (rootParser->m_entity_stats.debugLevel < 1)
1156+ return;
1157+
1158+# if defined(XML_UNICODE)
1159+ const char *const entityName = "[..]";
1160+# else
1161+ const char *const entityName = entity->name;
1162+# endif
1163+
1164+ fprintf(
1165+ stderr,
1166+ "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s length %d (xmlparse.c:%d)\n",
1167+ (void *)rootParser, rootParser->m_entity_stats.countEverOpened,
1168+ rootParser->m_entity_stats.currentDepth,
1169+ rootParser->m_entity_stats.maximumDepthSeen,
1170+ (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
1171+ entity->is_param ? "%" : "&", entityName, action, entity->textLen,
1172+ sourceLine);
1173+}
1174+
1175+static void
1176+entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int sourceLine) {
1177+ const XML_Parser rootParser = getRootParserOf(originParser, NULL);
1178+ assert(! rootParser->m_parentParser);
1179+
1180+ rootParser->m_entity_stats.countEverOpened++;
1181+ rootParser->m_entity_stats.currentDepth++;
1182+ if (rootParser->m_entity_stats.currentDepth
1183+ > rootParser->m_entity_stats.maximumDepthSeen) {
1184+ rootParser->m_entity_stats.maximumDepthSeen++;
1185+ }
1186+
1187+ entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine);
1188+}
1189+
1190+static void
1191+entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int sourceLine) {
1192+ const XML_Parser rootParser = getRootParserOf(originParser, NULL);
1193+ assert(! rootParser->m_parentParser);
1194+
1195+ entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine);
1196+ rootParser->m_entity_stats.currentDepth--;
1197+}
1198+
1199+static XML_Parser
1200+getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
1201+ XML_Parser rootParser = parser;
1202+ unsigned int stepsTakenUpwards = 0;
1203+ while (rootParser->m_parentParser) {
1204+ rootParser = rootParser->m_parentParser;
1205+ stepsTakenUpwards++;
1206+ }
1207+ assert(! rootParser->m_parentParser);
1208+ if (outLevelDiff != NULL) {
1209+ *outLevelDiff = stepsTakenUpwards;
1210+ }
1211+ return rootParser;
1212+}
1213+
1214+static const char *
1215+unsignedCharToPrintable(unsigned char c) {
1216+ switch (c) {
1217+ case 0:
1218+ return "\\0";
1219+ case 1:
1220+ return "\\x1";
1221+ case 2:
1222+ return "\\x2";
1223+ case 3:
1224+ return "\\x3";
1225+ case 4:
1226+ return "\\x4";
1227+ case 5:
1228+ return "\\x5";
1229+ case 6:
1230+ return "\\x6";
1231+ case 7:
1232+ return "\\x7";
1233+ case 8:
1234+ return "\\x8";
1235+ case 9:
1236+ return "\\t";
1237+ case 10:
1238+ return "\\n";
1239+ case 11:
1240+ return "\\xB";
1241+ case 12:
1242+ return "\\xC";
1243+ case 13:
1244+ return "\\r";
1245+ case 14:
1246+ return "\\xE";
1247+ case 15:
1248+ return "\\xF";
1249+ case 16:
1250+ return "\\x10";
1251+ case 17:
1252+ return "\\x11";
1253+ case 18:
1254+ return "\\x12";
1255+ case 19:
1256+ return "\\x13";
1257+ case 20:
1258+ return "\\x14";
1259+ case 21:
1260+ return "\\x15";
1261+ case 22:
1262+ return "\\x16";
1263+ case 23:
1264+ return "\\x17";
1265+ case 24:
1266+ return "\\x18";
1267+ case 25:
1268+ return "\\x19";
1269+ case 26:
1270+ return "\\x1A";
1271+ case 27:
1272+ return "\\x1B";
1273+ case 28:
1274+ return "\\x1C";
1275+ case 29:
1276+ return "\\x1D";
1277+ case 30:
1278+ return "\\x1E";
1279+ case 31:
1280+ return "\\x1F";
1281+ case 32:
1282+ return " ";
1283+ case 33:
1284+ return "!";
1285+ case 34:
1286+ return "\\\"";
1287+ case 35:
1288+ return "#";
1289+ case 36:
1290+ return "$";
1291+ case 37:
1292+ return "%";
1293+ case 38:
1294+ return "&";
1295+ case 39:
1296+ return "'";
1297+ case 40:
1298+ return "(";
1299+ case 41:
1300+ return ")";
1301+ case 42:
1302+ return "*";
1303+ case 43:
1304+ return "+";
1305+ case 44:
1306+ return ",";
1307+ case 45:
1308+ return "-";
1309+ case 46:
1310+ return ".";
1311+ case 47:
1312+ return "/";
1313+ case 48:
1314+ return "0";
1315+ case 49:
1316+ return "1";
1317+ case 50:
1318+ return "2";
1319+ case 51:
1320+ return "3";
1321+ case 52:
1322+ return "4";
1323+ case 53:
1324+ return "5";
1325+ case 54:
1326+ return "6";
1327+ case 55:
1328+ return "7";
1329+ case 56:
1330+ return "8";
1331+ case 57:
1332+ return "9";
1333+ case 58:
1334+ return ":";
1335+ case 59:
1336+ return ";";
1337+ case 60:
1338+ return "<";
1339+ case 61:
1340+ return "=";
1341+ case 62:
1342+ return ">";
1343+ case 63:
1344+ return "?";
1345+ case 64:
1346+ return "@";
1347+ case 65:
1348+ return "A";
1349+ case 66:
1350+ return "B";
1351+ case 67:
1352+ return "C";
1353+ case 68:
1354+ return "D";
1355+ case 69:
1356+ return "E";
1357+ case 70:
1358+ return "F";
1359+ case 71:
1360+ return "G";
1361+ case 72:
1362+ return "H";
1363+ case 73:
1364+ return "I";
1365+ case 74:
1366+ return "J";
1367+ case 75:
1368+ return "K";
1369+ case 76:
1370+ return "L";
1371+ case 77:
1372+ return "M";
1373+ case 78:
1374+ return "N";
1375+ case 79:
1376+ return "O";
1377+ case 80:
1378+ return "P";
1379+ case 81:
1380+ return "Q";
1381+ case 82:
1382+ return "R";
1383+ case 83:
1384+ return "S";
1385+ case 84:
1386+ return "T";
1387+ case 85:
1388+ return "U";
1389+ case 86:
1390+ return "V";
1391+ case 87:
1392+ return "W";
1393+ case 88:
1394+ return "X";
1395+ case 89:
1396+ return "Y";
1397+ case 90:
1398+ return "Z";
1399+ case 91:
1400+ return "[";
1401+ case 92:
1402+ return "\\\\";
1403+ case 93:
1404+ return "]";
1405+ case 94:
1406+ return "^";
1407+ case 95:
1408+ return "_";
1409+ case 96:
1410+ return "`";
1411+ case 97:
1412+ return "a";
1413+ case 98:
1414+ return "b";
1415+ case 99:
1416+ return "c";
1417+ case 100:
1418+ return "d";
1419+ case 101:
1420+ return "e";
1421+ case 102:
1422+ return "f";
1423+ case 103:
1424+ return "g";
1425+ case 104:
1426+ return "h";
1427+ case 105:
1428+ return "i";
1429+ case 106:
1430+ return "j";
1431+ case 107:
1432+ return "k";
1433+ case 108:
1434+ return "l";
1435+ case 109:
1436+ return "m";
1437+ case 110:
1438+ return "n";
1439+ case 111:
1440+ return "o";
1441+ case 112:
1442+ return "p";
1443+ case 113:
1444+ return "q";
1445+ case 114:
1446+ return "r";
1447+ case 115:
1448+ return "s";
1449+ case 116:
1450+ return "t";
1451+ case 117:
1452+ return "u";
1453+ case 118:
1454+ return "v";
1455+ case 119:
1456+ return "w";
1457+ case 120:
1458+ return "x";
1459+ case 121:
1460+ return "y";
1461+ case 122:
1462+ return "z";
1463+ case 123:
1464+ return "{";
1465+ case 124:
1466+ return "|";
1467+ case 125:
1468+ return "}";
1469+ case 126:
1470+ return "~";
1471+ case 127:
1472+ return "\\x7F";
1473+ case 128:
1474+ return "\\x80";
1475+ case 129:
1476+ return "\\x81";
1477+ case 130:
1478+ return "\\x82";
1479+ case 131:
1480+ return "\\x83";
1481+ case 132:
1482+ return "\\x84";
1483+ case 133:
1484+ return "\\x85";
1485+ case 134:
1486+ return "\\x86";
1487+ case 135:
1488+ return "\\x87";
1489+ case 136:
1490+ return "\\x88";
1491+ case 137:
1492+ return "\\x89";
1493+ case 138:
1494+ return "\\x8A";
1495+ case 139:
1496+ return "\\x8B";
1497+ case 140:
1498+ return "\\x8C";
1499+ case 141:
1500+ return "\\x8D";
1501+ case 142:
1502+ return "\\x8E";
1503+ case 143:
1504+ return "\\x8F";
1505+ case 144:
1506+ return "\\x90";
1507+ case 145:
1508+ return "\\x91";
1509+ case 146:
1510+ return "\\x92";
1511+ case 147:
1512+ return "\\x93";
1513+ case 148:
1514+ return "\\x94";
1515+ case 149:
1516+ return "\\x95";
1517+ case 150:
1518+ return "\\x96";
1519+ case 151:
1520+ return "\\x97";
1521+ case 152:
1522+ return "\\x98";
1523+ case 153:
1524+ return "\\x99";
1525+ case 154:
1526+ return "\\x9A";
1527+ case 155:
1528+ return "\\x9B";
1529+ case 156:
1530+ return "\\x9C";
1531+ case 157:
1532+ return "\\x9D";
1533+ case 158:
1534+ return "\\x9E";
1535+ case 159:
1536+ return "\\x9F";
1537+ case 160:
1538+ return "\\xA0";
1539+ case 161:
1540+ return "\\xA1";
1541+ case 162:
1542+ return "\\xA2";
1543+ case 163:
1544+ return "\\xA3";
1545+ case 164:
1546+ return "\\xA4";
1547+ case 165:
1548+ return "\\xA5";
1549+ case 166:
1550+ return "\\xA6";
1551+ case 167:
1552+ return "\\xA7";
1553+ case 168:
1554+ return "\\xA8";
1555+ case 169:
1556+ return "\\xA9";
1557+ case 170:
1558+ return "\\xAA";
1559+ case 171:
1560+ return "\\xAB";
1561+ case 172:
1562+ return "\\xAC";
1563+ case 173:
1564+ return "\\xAD";
1565+ case 174:
1566+ return "\\xAE";
1567+ case 175:
1568+ return "\\xAF";
1569+ case 176:
1570+ return "\\xB0";
1571+ case 177:
1572+ return "\\xB1";
1573+ case 178:
1574+ return "\\xB2";
1575+ case 179:
1576+ return "\\xB3";
1577+ case 180:
1578+ return "\\xB4";
1579+ case 181:
1580+ return "\\xB5";
1581+ case 182:
1582+ return "\\xB6";
1583+ case 183:
1584+ return "\\xB7";
1585+ case 184:
1586+ return "\\xB8";
1587+ case 185:
1588+ return "\\xB9";
1589+ case 186:
1590+ return "\\xBA";
1591+ case 187:
1592+ return "\\xBB";
1593+ case 188:
1594+ return "\\xBC";
1595+ case 189:
1596+ return "\\xBD";
1597+ case 190:
1598+ return "\\xBE";
1599+ case 191:
1600+ return "\\xBF";
1601+ case 192:
1602+ return "\\xC0";
1603+ case 193:
1604+ return "\\xC1";
1605+ case 194:
1606+ return "\\xC2";
1607+ case 195:
1608+ return "\\xC3";
1609+ case 196:
1610+ return "\\xC4";
1611+ case 197:
1612+ return "\\xC5";
1613+ case 198:
1614+ return "\\xC6";
1615+ case 199:
1616+ return "\\xC7";
1617+ case 200:
1618+ return "\\xC8";
1619+ case 201:
1620+ return "\\xC9";
1621+ case 202:
1622+ return "\\xCA";
1623+ case 203:
1624+ return "\\xCB";
1625+ case 204:
1626+ return "\\xCC";
1627+ case 205:
1628+ return "\\xCD";
1629+ case 206:
1630+ return "\\xCE";
1631+ case 207:
1632+ return "\\xCF";
1633+ case 208:
1634+ return "\\xD0";
1635+ case 209:
1636+ return "\\xD1";
1637+ case 210:
1638+ return "\\xD2";
1639+ case 211:
1640+ return "\\xD3";
1641+ case 212:
1642+ return "\\xD4";
1643+ case 213:
1644+ return "\\xD5";
1645+ case 214:
1646+ return "\\xD6";
1647+ case 215:
1648+ return "\\xD7";
1649+ case 216:
1650+ return "\\xD8";
1651+ case 217:
1652+ return "\\xD9";
1653+ case 218:
1654+ return "\\xDA";
1655+ case 219:
1656+ return "\\xDB";
1657+ case 220:
1658+ return "\\xDC";
1659+ case 221:
1660+ return "\\xDD";
1661+ case 222:
1662+ return "\\xDE";
1663+ case 223:
1664+ return "\\xDF";
1665+ case 224:
1666+ return "\\xE0";
1667+ case 225:
1668+ return "\\xE1";
1669+ case 226:
1670+ return "\\xE2";
1671+ case 227:
1672+ return "\\xE3";
1673+ case 228:
1674+ return "\\xE4";
1675+ case 229:
1676+ return "\\xE5";
1677+ case 230:
1678+ return "\\xE6";
1679+ case 231:
1680+ return "\\xE7";
1681+ case 232:
1682+ return "\\xE8";
1683+ case 233:
1684+ return "\\xE9";
1685+ case 234:
1686+ return "\\xEA";
1687+ case 235:
1688+ return "\\xEB";
1689+ case 236:
1690+ return "\\xEC";
1691+ case 237:
1692+ return "\\xED";
1693+ case 238:
1694+ return "\\xEE";
1695+ case 239:
1696+ return "\\xEF";
1697+ case 240:
1698+ return "\\xF0";
1699+ case 241:
1700+ return "\\xF1";
1701+ case 242:
1702+ return "\\xF2";
1703+ case 243:
1704+ return "\\xF3";
1705+ case 244:
1706+ return "\\xF4";
1707+ case 245:
1708+ return "\\xF5";
1709+ case 246:
1710+ return "\\xF6";
1711+ case 247:
1712+ return "\\xF7";
1713+ case 248:
1714+ return "\\xF8";
1715+ case 249:
1716+ return "\\xF9";
1717+ case 250:
1718+ return "\\xFA";
1719+ case 251:
1720+ return "\\xFB";
1721+ case 252:
1722+ return "\\xFC";
1723+ case 253:
1724+ return "\\xFD";
1725+ case 254:
1726+ return "\\xFE";
1727+ case 255:
1728+ return "\\xFF";
1729+ default:
1730+ assert(0); /* never gets here */
1731+ return "dead code";
1732+ }
1733+ assert(0); /* never gets here */
1734+}
1735+
1736+#endif /* XML_DTD */
1737+
1738+static unsigned long
1739+getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {
1740+ const char *const valueOrNull = getenv(variableName);
1741+ if (valueOrNull == NULL) {
1742+ return defaultDebugLevel;
1743+ }
1744+ const char *const value = valueOrNull;
1745+
1746+ errno = 0;
1747+ char *afterValue = (char *)value;
1748+ unsigned long debugLevel = strtoul(value, &afterValue, 10);
1749+ if ((errno != 0) || (afterValue[0] != '\0')) {
1750+ errno = 0;
1751+ return defaultDebugLevel;
1752+ }
1753+
1754+ return debugLevel;
1755+}
1756--
17572.32.0
1758
diff --git a/meta/recipes-core/expat/expat/CVE-2021-45960.patch b/meta/recipes-core/expat/expat/CVE-2021-45960.patch
new file mode 100644
index 0000000000..523449e22c
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2021-45960.patch
@@ -0,0 +1,65 @@
1From 0adcb34c49bee5b19bd29b16a578c510c23597ea Mon Sep 17 00:00:00 2001
2From: Sebastian Pipping <sebastian@pipping.org>
3Date: Mon, 27 Dec 2021 20:15:02 +0100
4Subject: [PATCH] lib: Detect and prevent troublesome left shifts in function
5 storeAtts (CVE-2021-45960)
6
7Upstream-Status: Backport:
8https://github.com/libexpat/libexpat/pull/534/commits/0adcb34c49bee5b19bd29b16a578c510c23597ea
9
10CVE: CVE-2021-45960
11Signed-off-by: Steve Sakoman <steve@sakoman.com>
12
13---
14 expat/lib/xmlparse.c | 31 +++++++++++++++++++++++++++++--
15 1 file changed, 29 insertions(+), 2 deletions(-)
16
17diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
18index d730f41c3..b47c31b05 100644
19--- a/lib/xmlparse.c
20+++ b/lib/xmlparse.c
21@@ -3414,7 +3414,13 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
22 if (nPrefixes) {
23 int j; /* hash table index */
24 unsigned long version = parser->m_nsAttsVersion;
25- int nsAttsSize = (int)1 << parser->m_nsAttsPower;
26+
27+ /* Detect and prevent invalid shift */
28+ if (parser->m_nsAttsPower >= sizeof(unsigned int) * 8 /* bits per byte */) {
29+ return XML_ERROR_NO_MEMORY;
30+ }
31+
32+ unsigned int nsAttsSize = 1u << parser->m_nsAttsPower;
33 unsigned char oldNsAttsPower = parser->m_nsAttsPower;
34 /* size of hash table must be at least 2 * (# of prefixed attributes) */
35 if ((nPrefixes << 1)
36@@ -3425,7 +3431,28 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
37 ;
38 if (parser->m_nsAttsPower < 3)
39 parser->m_nsAttsPower = 3;
40- nsAttsSize = (int)1 << parser->m_nsAttsPower;
41+
42+ /* Detect and prevent invalid shift */
43+ if (parser->m_nsAttsPower >= sizeof(nsAttsSize) * 8 /* bits per byte */) {
44+ /* Restore actual size of memory in m_nsAtts */
45+ parser->m_nsAttsPower = oldNsAttsPower;
46+ return XML_ERROR_NO_MEMORY;
47+ }
48+
49+ nsAttsSize = 1u << parser->m_nsAttsPower;
50+
51+ /* Detect and prevent integer overflow.
52+ * The preprocessor guard addresses the "always false" warning
53+ * from -Wtype-limits on platforms where
54+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
55+#if UINT_MAX >= SIZE_MAX
56+ if (nsAttsSize > (size_t)(-1) / sizeof(NS_ATT)) {
57+ /* Restore actual size of memory in m_nsAtts */
58+ parser->m_nsAttsPower = oldNsAttsPower;
59+ return XML_ERROR_NO_MEMORY;
60+ }
61+#endif
62+
63 temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts,
64 nsAttsSize * sizeof(NS_ATT));
65 if (! temp) {
diff --git a/meta/recipes-core/expat/expat/CVE-2021-46143.patch b/meta/recipes-core/expat/expat/CVE-2021-46143.patch
new file mode 100644
index 0000000000..b1a726d9a8
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2021-46143.patch
@@ -0,0 +1,49 @@
1From 85ae9a2d7d0e9358f356b33977b842df8ebaec2b Mon Sep 17 00:00:00 2001
2From: Sebastian Pipping <sebastian@pipping.org>
3Date: Sat, 25 Dec 2021 20:52:08 +0100
4Subject: [PATCH] lib: Prevent integer overflow on m_groupSize in function
5 doProlog (CVE-2021-46143)
6
7Upstream-Status: Backport:
8https://github.com/libexpat/libexpat/pull/538/commits/85ae9a2d7d0e9358f356b33977b842df8ebaec2b
9
10CVE: CVE-2021-46143
11
12Signed-off-by: Steve Sakoman <steve@sakoman.com>
13---
14 expat/lib/xmlparse.c | 15 +++++++++++++++
15 1 file changed, 15 insertions(+)
16
17diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
18index b47c31b0..8f243126 100644
19--- a/lib/xmlparse.c
20+++ b/lib/xmlparse.c
21@@ -5046,6 +5046,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
22 if (parser->m_prologState.level >= parser->m_groupSize) {
23 if (parser->m_groupSize) {
24 {
25+ /* Detect and prevent integer overflow */
26+ if (parser->m_groupSize > (unsigned int)(-1) / 2u) {
27+ return XML_ERROR_NO_MEMORY;
28+ }
29+
30 char *const new_connector = (char *)REALLOC(
31 parser, parser->m_groupConnector, parser->m_groupSize *= 2);
32 if (new_connector == NULL) {
33@@ -5056,6 +5061,16 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
34 }
35
36 if (dtd->scaffIndex) {
37+ /* Detect and prevent integer overflow.
38+ * The preprocessor guard addresses the "always false" warning
39+ * from -Wtype-limits on platforms where
40+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
41+#if UINT_MAX >= SIZE_MAX
42+ if (parser->m_groupSize > (size_t)(-1) / sizeof(int)) {
43+ return XML_ERROR_NO_MEMORY;
44+ }
45+#endif
46+
47 int *const new_scaff_index = (int *)REALLOC(
48 parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int));
49 if (new_scaff_index == NULL)
diff --git a/meta/recipes-core/expat/expat/CVE-2022-22822-27.patch b/meta/recipes-core/expat/expat/CVE-2022-22822-27.patch
new file mode 100644
index 0000000000..e569fbc7ab
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-22822-27.patch
@@ -0,0 +1,257 @@
1From 9f93e8036e842329863bf20395b8fb8f73834d9e Mon Sep 17 00:00:00 2001
2From: Sebastian Pipping <sebastian@pipping.org>
3Date: Thu, 30 Dec 2021 22:46:03 +0100
4Subject: [PATCH] lib: Prevent integer overflow at multiple places
5 (CVE-2022-22822 to CVE-2022-22827)
6
7The involved functions are:
8- addBinding (CVE-2022-22822)
9- build_model (CVE-2022-22823)
10- defineAttribute (CVE-2022-22824)
11- lookup (CVE-2022-22825)
12- nextScaffoldPart (CVE-2022-22826)
13- storeAtts (CVE-2022-22827)
14
15Upstream-Status: Backport:
16https://github.com/libexpat/libexpat/pull/539/commits/9f93e8036e842329863bf20395b8fb8f73834d9e
17
18CVE: CVE-2022-22822 CVE-2022-22823 CVE-2022-22824 CVE-2022-22825 CVE-2022-22826 CVE-2022-22827
19Signed-off-by: Steve Sakoman <steve@sakoman.com>
20
21---
22 expat/lib/xmlparse.c | 153 ++++++++++++++++++++++++++++++++++++++++++-
23 1 file changed, 151 insertions(+), 2 deletions(-)
24
25diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
26index 8f243126..575e73ee 100644
27--- a/lib/xmlparse.c
28+++ b/lib/xmlparse.c
29@@ -3261,13 +3261,38 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
30
31 /* get the attributes from the tokenizer */
32 n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts);
33+
34+ /* Detect and prevent integer overflow */
35+ if (n > INT_MAX - nDefaultAtts) {
36+ return XML_ERROR_NO_MEMORY;
37+ }
38+
39 if (n + nDefaultAtts > parser->m_attsSize) {
40 int oldAttsSize = parser->m_attsSize;
41 ATTRIBUTE *temp;
42 #ifdef XML_ATTR_INFO
43 XML_AttrInfo *temp2;
44 #endif
45+
46+ /* Detect and prevent integer overflow */
47+ if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE)
48+ || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) {
49+ return XML_ERROR_NO_MEMORY;
50+ }
51+
52 parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
53+
54+ /* Detect and prevent integer overflow.
55+ * The preprocessor guard addresses the "always false" warning
56+ * from -Wtype-limits on platforms where
57+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
58+#if UINT_MAX >= SIZE_MAX
59+ if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) {
60+ parser->m_attsSize = oldAttsSize;
61+ return XML_ERROR_NO_MEMORY;
62+ }
63+#endif
64+
65 temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts,
66 parser->m_attsSize * sizeof(ATTRIBUTE));
67 if (temp == NULL) {
68@@ -3276,6 +3301,17 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
69 }
70 parser->m_atts = temp;
71 #ifdef XML_ATTR_INFO
72+ /* Detect and prevent integer overflow.
73+ * The preprocessor guard addresses the "always false" warning
74+ * from -Wtype-limits on platforms where
75+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
76+# if UINT_MAX >= SIZE_MAX
77+ if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) {
78+ parser->m_attsSize = oldAttsSize;
79+ return XML_ERROR_NO_MEMORY;
80+ }
81+# endif
82+
83 temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo,
84 parser->m_attsSize * sizeof(XML_AttrInfo));
85 if (temp2 == NULL) {
86@@ -3610,9 +3646,31 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
87 tagNamePtr->prefixLen = prefixLen;
88 for (i = 0; localPart[i++];)
89 ; /* i includes null terminator */
90+
91+ /* Detect and prevent integer overflow */
92+ if (binding->uriLen > INT_MAX - prefixLen
93+ || i > INT_MAX - (binding->uriLen + prefixLen)) {
94+ return XML_ERROR_NO_MEMORY;
95+ }
96+
97 n = i + binding->uriLen + prefixLen;
98 if (n > binding->uriAlloc) {
99 TAG *p;
100+
101+ /* Detect and prevent integer overflow */
102+ if (n > INT_MAX - EXPAND_SPARE) {
103+ return XML_ERROR_NO_MEMORY;
104+ }
105+ /* Detect and prevent integer overflow.
106+ * The preprocessor guard addresses the "always false" warning
107+ * from -Wtype-limits on platforms where
108+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
109+#if UINT_MAX >= SIZE_MAX
110+ if ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
111+ return XML_ERROR_NO_MEMORY;
112+ }
113+#endif
114+
115 uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char));
116 if (! uri)
117 return XML_ERROR_NO_MEMORY;
118@@ -3708,6 +3766,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
119 if (parser->m_freeBindingList) {
120 b = parser->m_freeBindingList;
121 if (len > b->uriAlloc) {
122+ /* Detect and prevent integer overflow */
123+ if (len > INT_MAX - EXPAND_SPARE) {
124+ return XML_ERROR_NO_MEMORY;
125+ }
126+
127+ /* Detect and prevent integer overflow.
128+ * The preprocessor guard addresses the "always false" warning
129+ * from -Wtype-limits on platforms where
130+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
131+#if UINT_MAX >= SIZE_MAX
132+ if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
133+ return XML_ERROR_NO_MEMORY;
134+ }
135+#endif
136+
137 XML_Char *temp = (XML_Char *)REALLOC(
138 parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
139 if (temp == NULL)
140@@ -3720,6 +3793,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
141 b = (BINDING *)MALLOC(parser, sizeof(BINDING));
142 if (! b)
143 return XML_ERROR_NO_MEMORY;
144+
145+ /* Detect and prevent integer overflow */
146+ if (len > INT_MAX - EXPAND_SPARE) {
147+ return XML_ERROR_NO_MEMORY;
148+ }
149+ /* Detect and prevent integer overflow.
150+ * The preprocessor guard addresses the "always false" warning
151+ * from -Wtype-limits on platforms where
152+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
153+#if UINT_MAX >= SIZE_MAX
154+ if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
155+ return XML_ERROR_NO_MEMORY;
156+ }
157+#endif
158+
159 b->uri
160 = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
161 if (! b->uri) {
162@@ -6141,7 +6229,24 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
163 }
164 } else {
165 DEFAULT_ATTRIBUTE *temp;
166+
167+ /* Detect and prevent integer overflow */
168+ if (type->allocDefaultAtts > INT_MAX / 2) {
169+ return 0;
170+ }
171+
172 int count = type->allocDefaultAtts * 2;
173+
174+ /* Detect and prevent integer overflow.
175+ * The preprocessor guard addresses the "always false" warning
176+ * from -Wtype-limits on platforms where
177+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
178+#if UINT_MAX >= SIZE_MAX
179+ if ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) {
180+ return 0;
181+ }
182+#endif
183+
184 temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts,
185 (count * sizeof(DEFAULT_ATTRIBUTE)));
186 if (temp == NULL)
187@@ -6792,8 +6897,20 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
188 /* check for overflow (table is half full) */
189 if (table->used >> (table->power - 1)) {
190 unsigned char newPower = table->power + 1;
191+
192+ /* Detect and prevent invalid shift */
193+ if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) {
194+ return NULL;
195+ }
196+
197 size_t newSize = (size_t)1 << newPower;
198 unsigned long newMask = (unsigned long)newSize - 1;
199+
200+ /* Detect and prevent integer overflow */
201+ if (newSize > (size_t)(-1) / sizeof(NAMED *)) {
202+ return NULL;
203+ }
204+
205 size_t tsize = newSize * sizeof(NAMED *);
206 NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
207 if (! newV)
208@@ -7143,6 +7260,20 @@ nextScaffoldPart(XML_Parser parser) {
209 if (dtd->scaffCount >= dtd->scaffSize) {
210 CONTENT_SCAFFOLD *temp;
211 if (dtd->scaffold) {
212+ /* Detect and prevent integer overflow */
213+ if (dtd->scaffSize > UINT_MAX / 2u) {
214+ return -1;
215+ }
216+ /* Detect and prevent integer overflow.
217+ * The preprocessor guard addresses the "always false" warning
218+ * from -Wtype-limits on platforms where
219+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
220+#if UINT_MAX >= SIZE_MAX
221+ if (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) {
222+ return -1;
223+ }
224+#endif
225+
226 temp = (CONTENT_SCAFFOLD *)REALLOC(
227 parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
228 if (temp == NULL)
229@@ -7212,8 +7343,26 @@ build_model(XML_Parser parser) {
230 XML_Content *ret;
231 XML_Content *cpos;
232 XML_Char *str;
233- int allocsize = (dtd->scaffCount * sizeof(XML_Content)
234- + (dtd->contentStringLen * sizeof(XML_Char)));
235+
236+ /* Detect and prevent integer overflow.
237+ * The preprocessor guard addresses the "always false" warning
238+ * from -Wtype-limits on platforms where
239+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
240+#if UINT_MAX >= SIZE_MAX
241+ if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) {
242+ return NULL;
243+ }
244+ if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) {
245+ return NULL;
246+ }
247+#endif
248+ if (dtd->scaffCount * sizeof(XML_Content)
249+ > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) {
250+ return NULL;
251+ }
252+
253+ const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content)
254+ + (dtd->contentStringLen * sizeof(XML_Char)));
255
256 ret = (XML_Content *)MALLOC(parser, allocsize);
257 if (! ret)
diff --git a/meta/recipes-core/expat/expat/CVE-2022-23852.patch b/meta/recipes-core/expat/expat/CVE-2022-23852.patch
new file mode 100644
index 0000000000..41425c108b
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-23852.patch
@@ -0,0 +1,33 @@
1From 847a645152f5ebc10ac63b74b604d0c1a79fae40 Mon Sep 17 00:00:00 2001
2From: Samanta Navarro <ferivoz@riseup.net>
3Date: Sat, 22 Jan 2022 17:48:00 +0100
4Subject: [PATCH] lib: Detect and prevent integer overflow in XML_GetBuffer
5 (CVE-2022-23852)
6
7Upstream-Status: Backport:
8https://github.com/libexpat/libexpat/commit/847a645152f5ebc10ac63b74b604d0c1a79fae40
9
10CVE: CVE-2022-23852
11
12Signed-off-by: Steve Sakoman <steve@sakoman.com>
13
14---
15 expat/lib/xmlparse.c | 5 +++++
16 1 file changed, 5 insertions(+)
17
18diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
19index d54af683..5ce31402 100644
20--- a/lib/xmlparse.c
21+++ b/lib/xmlparse.c
22@@ -2067,6 +2067,11 @@ XML_GetBuffer(XML_Parser parser, int len) {
23 keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
24 if (keep > XML_CONTEXT_BYTES)
25 keep = XML_CONTEXT_BYTES;
26+ /* Detect and prevent integer overflow */
27+ if (keep > INT_MAX - neededSize) {
28+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
29+ return NULL;
30+ }
31 neededSize += keep;
32 #endif /* defined XML_CONTEXT_BYTES */
33 if (neededSize
diff --git a/meta/recipes-core/expat/expat/CVE-2022-23990.patch b/meta/recipes-core/expat/expat/CVE-2022-23990.patch
new file mode 100644
index 0000000000..c599517b3e
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-23990.patch
@@ -0,0 +1,49 @@
1From ede41d1e186ed2aba88a06e84cac839b770af3a1 Mon Sep 17 00:00:00 2001
2From: Sebastian Pipping <sebastian@pipping.org>
3Date: Wed, 26 Jan 2022 02:36:43 +0100
4Subject: [PATCH] lib: Prevent integer overflow in doProlog (CVE-2022-23990)
5
6The change from "int nameLen" to "size_t nameLen"
7addresses the overflow on "nameLen++" in code
8"for (; name[nameLen++];)" right above the second
9change in the patch.
10
11Upstream-Status: Backport:
12https://github.com/libexpat/libexpat/pull/551/commits/ede41d1e186ed2aba88a06e84cac839b770af3a1
13
14CVE: CVE-2022-23990
15
16Signed-off-by: Steve Sakoman <steve@sakoman.com>
17
18---
19 lib/xmlparse.c | 10 ++++++++--
20 1 file changed, 8 insertions(+), 2 deletions(-)
21
22diff --git a/lib/xmlparse.c b/expat/lib/xmlparse.c
23index 5ce31402..d1d17005 100644
24--- a/lib/xmlparse.c
25+++ b/lib/xmlparse.c
26@@ -5372,7 +5372,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
27 if (dtd->in_eldecl) {
28 ELEMENT_TYPE *el;
29 const XML_Char *name;
30- int nameLen;
31+ size_t nameLen;
32 const char *nxt
33 = (quant == XML_CQUANT_NONE ? next : next - enc->minBytesPerChar);
34 int myindex = nextScaffoldPart(parser);
35@@ -5388,7 +5388,13 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
36 nameLen = 0;
37 for (; name[nameLen++];)
38 ;
39- dtd->contentStringLen += nameLen;
40+
41+ /* Detect and prevent integer overflow */
42+ if (nameLen > UINT_MAX - dtd->contentStringLen) {
43+ return XML_ERROR_NO_MEMORY;
44+ }
45+
46+ dtd->contentStringLen += (unsigned)nameLen;
47 if (parser->m_elementDeclHandler)
48 handleDefault = XML_FALSE;
49 }
diff --git a/meta/recipes-core/expat/expat/CVE-2022-25235.patch b/meta/recipes-core/expat/expat/CVE-2022-25235.patch
new file mode 100644
index 0000000000..be9182a5c1
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-25235.patch
@@ -0,0 +1,283 @@
1From ee2a5b50e7d1940ba8745715b62ceb9efd3a96da Mon Sep 17 00:00:00 2001
2From: Sebastian Pipping <sebastian@pipping.org>
3Date: Tue, 8 Feb 2022 17:37:14 +0100
4Subject: [PATCH] lib: Drop unused macro UTF8_GET_NAMING
5
6Upstream-Status: Backport
7https://github.com/libexpat/libexpat/pull/562/commits
8
9CVE: CVE-2022-25235
10
11Signed-off-by: Steve Sakoman <steve@sakoman.com>
12
13---
14 expat/lib/xmltok.c | 5 -----
15 1 file changed, 5 deletions(-)
16
17diff --git a/lib/xmltok.c b/lib/xmltok.c
18index a72200e8..3bddf125 100644
19--- a/lib/xmltok.c
20+++ b/lib/xmltok.c
21@@ -95,11 +95,6 @@
22 + ((((byte)[1]) & 3) << 1) + ((((byte)[2]) >> 5) & 1)] \
23 & (1u << (((byte)[2]) & 0x1F)))
24
25-#define UTF8_GET_NAMING(pages, p, n) \
26- ((n) == 2 \
27- ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
28- : ((n) == 3 ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) : 0))
29-
30 /* Detection of invalid UTF-8 sequences is based on Table 3.1B
31 of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
32 with the additional restriction of not allowing the Unicode
33From 3f0a0cb644438d4d8e3294cd0b1245d0edb0c6c6 Mon Sep 17 00:00:00 2001
34From: Sebastian Pipping <sebastian@pipping.org>
35Date: Tue, 8 Feb 2022 04:32:20 +0100
36Subject: [PATCH] lib: Add missing validation of encoding (CVE-2022-25235)
37
38---
39 expat/lib/xmltok_impl.c | 8 ++++++--
40 1 file changed, 6 insertions(+), 2 deletions(-)
41
42diff --git a/lib/xmltok_impl.c b/lib/xmltok_impl.c
43index 0430591b4..64a3b2c15 100644
44--- a/lib/xmltok_impl.c
45+++ b/lib/xmltok_impl.c
46@@ -61,7 +61,7 @@
47 case BT_LEAD##n: \
48 if (end - ptr < n) \
49 return XML_TOK_PARTIAL_CHAR; \
50- if (! IS_NAME_CHAR(enc, ptr, n)) { \
51+ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NAME_CHAR(enc, ptr, n)) { \
52 *nextTokPtr = ptr; \
53 return XML_TOK_INVALID; \
54 } \
55@@ -90,7 +90,7 @@
56 case BT_LEAD##n: \
57 if (end - ptr < n) \
58 return XML_TOK_PARTIAL_CHAR; \
59- if (! IS_NMSTRT_CHAR(enc, ptr, n)) { \
60+ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NMSTRT_CHAR(enc, ptr, n)) { \
61 *nextTokPtr = ptr; \
62 return XML_TOK_INVALID; \
63 } \
64@@ -1134,6 +1134,10 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
65 case BT_LEAD##n: \
66 if (end - ptr < n) \
67 return XML_TOK_PARTIAL_CHAR; \
68+ if (IS_INVALID_CHAR(enc, ptr, n)) { \
69+ *nextTokPtr = ptr; \
70+ return XML_TOK_INVALID; \
71+ } \
72 if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
73 ptr += n; \
74 tok = XML_TOK_NAME; \
75From c85a3025e7a1be086dc34e7559fbc543914d047f Mon Sep 17 00:00:00 2001
76From: Sebastian Pipping <sebastian@pipping.org>
77Date: Wed, 9 Feb 2022 01:00:38 +0100
78Subject: [PATCH] lib: Add comments to BT_LEAD* cases where encoding has
79 already been validated
80
81---
82 expat/lib/xmltok_impl.c | 10 +++++-----
83 1 file changed, 5 insertions(+), 5 deletions(-)
84
85diff --git a/lib/xmltok_impl.c b/lib/xmltok_impl.c
86index 64a3b2c1..84ff35f9 100644
87--- a/lib/xmltok_impl.c
88+++ b/lib/xmltok_impl.c
89@@ -1266,7 +1266,7 @@ PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end,
90 switch (BYTE_TYPE(enc, ptr)) {
91 # define LEAD_CASE(n) \
92 case BT_LEAD##n: \
93- ptr += n; \
94+ ptr += n; /* NOTE: The encoding has already been validated. */ \
95 break;
96 LEAD_CASE(2)
97 LEAD_CASE(3)
98@@ -1335,7 +1335,7 @@ PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end,
99 switch (BYTE_TYPE(enc, ptr)) {
100 # define LEAD_CASE(n) \
101 case BT_LEAD##n: \
102- ptr += n; \
103+ ptr += n; /* NOTE: The encoding has already been validated. */ \
104 break;
105 LEAD_CASE(2)
106 LEAD_CASE(3)
107@@ -1514,7 +1514,7 @@ PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
108 state = inName; \
109 }
110 # define LEAD_CASE(n) \
111- case BT_LEAD##n: \
112+ case BT_LEAD##n: /* NOTE: The encoding has already been validated. */ \
113 START_NAME ptr += (n - MINBPC(enc)); \
114 break;
115 LEAD_CASE(2)
116@@ -1726,7 +1726,7 @@ PREFIX(nameLength)(const ENCODING *enc, const char *ptr) {
117 switch (BYTE_TYPE(enc, ptr)) {
118 # define LEAD_CASE(n) \
119 case BT_LEAD##n: \
120- ptr += n; \
121+ ptr += n; /* NOTE: The encoding has already been validated. */ \
122 break;
123 LEAD_CASE(2)
124 LEAD_CASE(3)
125@@ -1771,7 +1771,7 @@ PREFIX(updatePosition)(const ENCODING *enc, const char *ptr, const char *end,
126 switch (BYTE_TYPE(enc, ptr)) {
127 # define LEAD_CASE(n) \
128 case BT_LEAD##n: \
129- ptr += n; \
130+ ptr += n; /* NOTE: The encoding has already been validated. */ \
131 break;
132 LEAD_CASE(2)
133 LEAD_CASE(3)
134From 6a5510bc6b7efe743356296724e0b38300f05379 Mon Sep 17 00:00:00 2001
135From: Sebastian Pipping <sebastian@pipping.org>
136Date: Tue, 8 Feb 2022 04:06:21 +0100
137Subject: [PATCH] tests: Cover missing validation of encoding (CVE-2022-25235)
138
139---
140 expat/tests/runtests.c | 109 +++++++++++++++++++++++++++++++++++++++++
141 1 file changed, 109 insertions(+)
142
143diff --git a/tests/runtests.c b/tests/runtests.c
144index bc5344b1..9b155b82 100644
145--- a/tests/runtests.c
146+++ b/tests/runtests.c
147@@ -5998,6 +5998,105 @@ START_TEST(test_utf8_in_cdata_section_2) {
148 }
149 END_TEST
150
151+START_TEST(test_utf8_in_start_tags) {
152+ struct test_case {
153+ bool goodName;
154+ bool goodNameStart;
155+ const char *tagName;
156+ };
157+
158+ // The idea with the tests below is this:
159+ // We want to cover 1-, 2- and 3-byte sequences, 4-byte sequences
160+ // go to isNever and are hence not a concern.
161+ //
162+ // We start with a character that is a valid name character
163+ // (or even name-start character, see XML 1.0r4 spec) and then we flip
164+ // single bits at places where (1) the result leaves the UTF-8 encoding space
165+ // and (2) we stay in the same n-byte sequence family.
166+ //
167+ // The flipped bits are highlighted in angle brackets in comments,
168+ // e.g. "[<1>011 1001]" means we had [0011 1001] but we now flipped
169+ // the most significant bit to 1 to leave UTF-8 encoding space.
170+ struct test_case cases[] = {
171+ // 1-byte UTF-8: [0xxx xxxx]
172+ {true, true, "\x3A"}, // [0011 1010] = ASCII colon ':'
173+ {false, false, "\xBA"}, // [<1>011 1010]
174+ {true, false, "\x39"}, // [0011 1001] = ASCII nine '9'
175+ {false, false, "\xB9"}, // [<1>011 1001]
176+
177+ // 2-byte UTF-8: [110x xxxx] [10xx xxxx]
178+ {true, true, "\xDB\xA5"}, // [1101 1011] [1010 0101] =
179+ // Arabic small waw U+06E5
180+ {false, false, "\x9B\xA5"}, // [1<0>01 1011] [1010 0101]
181+ {false, false, "\xDB\x25"}, // [1101 1011] [<0>010 0101]
182+ {false, false, "\xDB\xE5"}, // [1101 1011] [1<1>10 0101]
183+ {true, false, "\xCC\x81"}, // [1100 1100] [1000 0001] =
184+ // combining char U+0301
185+ {false, false, "\x8C\x81"}, // [1<0>00 1100] [1000 0001]
186+ {false, false, "\xCC\x01"}, // [1100 1100] [<0>000 0001]
187+ {false, false, "\xCC\xC1"}, // [1100 1100] [1<1>00 0001]
188+
189+ // 3-byte UTF-8: [1110 xxxx] [10xx xxxx] [10xxxxxx]
190+ {true, true, "\xE0\xA4\x85"}, // [1110 0000] [1010 0100] [1000 0101] =
191+ // Devanagari Letter A U+0905
192+ {false, false, "\xA0\xA4\x85"}, // [1<0>10 0000] [1010 0100] [1000 0101]
193+ {false, false, "\xE0\x24\x85"}, // [1110 0000] [<0>010 0100] [1000 0101]
194+ {false, false, "\xE0\xE4\x85"}, // [1110 0000] [1<1>10 0100] [1000 0101]
195+ {false, false, "\xE0\xA4\x05"}, // [1110 0000] [1010 0100] [<0>000 0101]
196+ {false, false, "\xE0\xA4\xC5"}, // [1110 0000] [1010 0100] [1<1>00 0101]
197+ {true, false, "\xE0\xA4\x81"}, // [1110 0000] [1010 0100] [1000 0001] =
198+ // combining char U+0901
199+ {false, false, "\xA0\xA4\x81"}, // [1<0>10 0000] [1010 0100] [1000 0001]
200+ {false, false, "\xE0\x24\x81"}, // [1110 0000] [<0>010 0100] [1000 0001]
201+ {false, false, "\xE0\xE4\x81"}, // [1110 0000] [1<1>10 0100] [1000 0001]
202+ {false, false, "\xE0\xA4\x01"}, // [1110 0000] [1010 0100] [<0>000 0001]
203+ {false, false, "\xE0\xA4\xC1"}, // [1110 0000] [1010 0100] [1<1>00 0001]
204+ };
205+ const bool atNameStart[] = {true, false};
206+
207+ size_t i = 0;
208+ char doc[1024];
209+ size_t failCount = 0;
210+
211+ for (; i < sizeof(cases) / sizeof(cases[0]); i++) {
212+ size_t j = 0;
213+ for (; j < sizeof(atNameStart) / sizeof(atNameStart[0]); j++) {
214+ const bool expectedSuccess
215+ = atNameStart[j] ? cases[i].goodNameStart : cases[i].goodName;
216+ sprintf(doc, "<%s%s><!--", atNameStart[j] ? "" : "a", cases[i].tagName);
217+ XML_Parser parser = XML_ParserCreate(NULL);
218+
219+ const enum XML_Status status
220+ = XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_FALSE);
221+
222+ bool success = true;
223+ if ((status == XML_STATUS_OK) != expectedSuccess) {
224+ success = false;
225+ }
226+ if ((status == XML_STATUS_ERROR)
227+ && (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)) {
228+ success = false;
229+ }
230+
231+ if (! success) {
232+ fprintf(
233+ stderr,
234+ "FAIL case %2u (%sat name start, %u-byte sequence, error code %d)\n",
235+ (unsigned)i + 1u, atNameStart[j] ? " " : "not ",
236+ (unsigned)strlen(cases[i].tagName), XML_GetErrorCode(parser));
237+ failCount++;
238+ }
239+
240+ XML_ParserFree(parser);
241+ }
242+ }
243+
244+ if (failCount > 0) {
245+ fail("UTF-8 regression detected");
246+ }
247+}
248+END_TEST
249+
250 /* Test trailing spaces in elements are accepted */
251 static void XMLCALL
252 record_element_end_handler(void *userData, const XML_Char *name) {
253@@ -6175,6 +6274,14 @@ START_TEST(test_bad_doctype) {
254 }
255 END_TEST
256
257+START_TEST(test_bad_doctype_utf8) {
258+ const char *text = "<!DOCTYPE \xDB\x25"
259+ "doc><doc/>"; // [1101 1011] [<0>010 0101]
260+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
261+ "Invalid UTF-8 in DOCTYPE not faulted");
262+}
263+END_TEST
264+
265 START_TEST(test_bad_doctype_utf16) {
266 const char text[] =
267 /* <!DOCTYPE doc [ \x06f2 ]><doc/>
268@@ -11870,6 +11977,7 @@ make_suite(void) {
269 tcase_add_test(tc_basic, test_ext_entity_utf8_non_bom);
270 tcase_add_test(tc_basic, test_utf8_in_cdata_section);
271 tcase_add_test(tc_basic, test_utf8_in_cdata_section_2);
272+ tcase_add_test(tc_basic, test_utf8_in_start_tags);
273 tcase_add_test(tc_basic, test_trailing_spaces_in_elements);
274 tcase_add_test(tc_basic, test_utf16_attribute);
275 tcase_add_test(tc_basic, test_utf16_second_attr);
276@@ -11878,6 +11986,7 @@ make_suite(void) {
277 tcase_add_test(tc_basic, test_bad_attr_desc_keyword);
278 tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16);
279 tcase_add_test(tc_basic, test_bad_doctype);
280+ tcase_add_test(tc_basic, test_bad_doctype_utf8);
281 tcase_add_test(tc_basic, test_bad_doctype_utf16);
282 tcase_add_test(tc_basic, test_bad_doctype_plus);
283 tcase_add_test(tc_basic, test_bad_doctype_star);
diff --git a/meta/recipes-core/expat/expat/CVE-2022-25236.patch b/meta/recipes-core/expat/expat/CVE-2022-25236.patch
new file mode 100644
index 0000000000..ba6443fc6a
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-25236.patch
@@ -0,0 +1,129 @@
1From 6881a4fc8596307ab9ff2e85e605afa2e413ab71 Mon Sep 17 00:00:00 2001
2From: Sebastian Pipping <sebastian@pipping.org>
3Date: Sat, 12 Feb 2022 00:19:13 +0100
4Subject: [PATCH] lib: Fix (harmless) use of uninitialized memory
5
6Upstream-Status: Backport
7https://github.com/libexpat/libexpat/pull/561/commits
8
9CVE: CVE-2022-25236
10
11Signed-off-by: Steve Sakoman <steve@sakoman.com>
12
13---
14 expat/lib/xmlparse.c | 6 ++----
15 1 file changed, 2 insertions(+), 4 deletions(-)
16
17diff --git a/lib/xmlparse.c b/lib/xmlparse.c
18index 902895d5..c768f856 100644
19--- a/lib/xmlparse.c
20+++ b/lib/xmlparse.c
21@@ -718,8 +718,7 @@ XML_ParserCreate(const XML_Char *encodingName) {
22
23 XML_Parser XMLCALL
24 XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
25- XML_Char tmp[2];
26- *tmp = nsSep;
27+ XML_Char tmp[2] = {nsSep, 0};
28 return XML_ParserCreate_MM(encodingName, NULL, tmp);
29 }
30
31@@ -1344,8 +1343,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
32 would be otherwise.
33 */
34 if (parser->m_ns) {
35- XML_Char tmp[2];
36- *tmp = parser->m_namespaceSeparator;
37+ XML_Char tmp[2] = {parser->m_namespaceSeparator, 0};
38 parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
39 } else {
40 parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
41From a2fe525e660badd64b6c557c2b1ec26ddc07f6e4 Mon Sep 17 00:00:00 2001
42From: Sebastian Pipping <sebastian@pipping.org>
43Date: Sat, 12 Feb 2022 01:09:29 +0100
44Subject: [PATCH] lib: Protect against malicious namespace declarations
45 (CVE-2022-25236)
46
47---
48 expat/lib/xmlparse.c | 11 +++++++++++
49 1 file changed, 11 insertions(+)
50
51diff --git a/lib/xmlparse.c b/lib/xmlparse.c
52index c768f856..a3aef88c 100644
53--- a/lib/xmlparse.c
54+++ b/lib/xmlparse.c
55@@ -3754,6 +3754,17 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
56 if (! mustBeXML && isXMLNS
57 && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
58 isXMLNS = XML_FALSE;
59+
60+ // NOTE: While Expat does not validate namespace URIs against RFC 3986,
61+ // we have to at least make sure that the XML processor on top of
62+ // Expat (that is splitting tag names by namespace separator into
63+ // 2- or 3-tuples (uri-local or uri-local-prefix)) cannot be confused
64+ // by an attacker putting additional namespace separator characters
65+ // into namespace declarations. That would be ambiguous and not to
66+ // be expected.
67+ if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)) {
68+ return XML_ERROR_SYNTAX;
69+ }
70 }
71 isXML = isXML && len == xmlLen;
72 isXMLNS = isXMLNS && len == xmlnsLen;
73From 2de077423fb22750ebea599677d523b53cb93b1d Mon Sep 17 00:00:00 2001
74From: Sebastian Pipping <sebastian@pipping.org>
75Date: Sat, 12 Feb 2022 00:51:43 +0100
76Subject: [PATCH] tests: Cover CVE-2022-25236
77
78---
79 expat/tests/runtests.c | 30 ++++++++++++++++++++++++++++++
80 1 file changed, 30 insertions(+)
81
82diff --git a/tests/runtests.c b/tests/runtests.c
83index d07203f2..bc5344b1 100644
84--- a/tests/runtests.c
85+++ b/tests/runtests.c
86@@ -7220,6 +7220,35 @@ START_TEST(test_ns_double_colon_doctype) {
87 }
88 END_TEST
89
90+START_TEST(test_ns_separator_in_uri) {
91+ struct test_case {
92+ enum XML_Status expectedStatus;
93+ const char *doc;
94+ };
95+ struct test_case cases[] = {
96+ {XML_STATUS_OK, "<doc xmlns='one_two' />"},
97+ {XML_STATUS_ERROR, "<doc xmlns='one&#x0A;two' />"},
98+ };
99+
100+ size_t i = 0;
101+ size_t failCount = 0;
102+ for (; i < sizeof(cases) / sizeof(cases[0]); i++) {
103+ XML_Parser parser = XML_ParserCreateNS(NULL, '\n');
104+ XML_SetElementHandler(parser, dummy_start_element, dummy_end_element);
105+ if (XML_Parse(parser, cases[i].doc, (int)strlen(cases[i].doc),
106+ /*isFinal*/ XML_TRUE)
107+ != cases[i].expectedStatus) {
108+ failCount++;
109+ }
110+ XML_ParserFree(parser);
111+ }
112+
113+ if (failCount) {
114+ fail("Namespace separator handling is broken");
115+ }
116+}
117+END_TEST
118+
119 /* Control variable; the number of times duff_allocator() will successfully
120 * allocate */
121 #define ALLOC_ALWAYS_SUCCEED (-1)
122@@ -11905,6 +11934,7 @@ make_suite(void) {
123 tcase_add_test(tc_namespace, test_ns_utf16_doctype);
124 tcase_add_test(tc_namespace, test_ns_invalid_doctype);
125 tcase_add_test(tc_namespace, test_ns_double_colon_doctype);
126+ tcase_add_test(tc_namespace, test_ns_separator_in_uri);
127
128 suite_add_tcase(s, tc_misc);
129 tcase_add_checked_fixture(tc_misc, NULL, basic_teardown);
diff --git a/meta/recipes-core/expat/expat/CVE-2022-25313-regression.patch b/meta/recipes-core/expat/expat/CVE-2022-25313-regression.patch
new file mode 100644
index 0000000000..af255e8cb5
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-25313-regression.patch
@@ -0,0 +1,131 @@
1From b12f34fe32821a69dc12ff9a021daca0856de238 Mon Sep 17 00:00:00 2001
2From: Samanta Navarro <ferivoz@riseup.net>
3Date: Sat, 19 Feb 2022 23:59:25 +0000
4Subject: [PATCH] Fix build_model regression.
5
6The iterative approach in build_model failed to fill children arrays
7correctly. A preorder traversal is not required and turned out to be the
8culprit. Use an easier algorithm:
9
10Add nodes from scaffold tree starting at index 0 (root) to the target
11array whenever children are encountered. This ensures that children
12are adjacent to each other. This complies with the recursive version.
13
14Store only the scaffold index in numchildren field to prevent a direct
15processing of these children, which would require a recursive solution.
16This allows the algorithm to iterate through the target array from start
17to end without jumping back and forth, converting on the fly.
18
19Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
20---
21 lib/xmlparse.c | 79 ++++++++++++++++++++++++++------------------
22 1 file changed, 47 insertions(+), 32 deletions(-)
23
24diff --git a/lib/xmlparse.c b/lib/xmlparse.c
25index c479a258..84885b5a 100644
26--- a/lib/xmlparse.c
27+++ b/lib/xmlparse.c
28@@ -7373,39 +7373,58 @@ build_model(XML_Parser parser) {
29 *
30 * The iterative approach works as follows:
31 *
32- * - We use space in the target array for building a temporary stack structure
33- * while that space is still unused.
34- * The stack grows from the array's end downwards and the "actual data"
35- * grows from the start upwards, sequentially.
36- * (Because stack grows downwards, pushing onto the stack is a decrement
37- * while popping off the stack is an increment.)
38+ * - We have two writing pointers, both walking up the result array; one does
39+ * the work, the other creates "jobs" for its colleague to do, and leads
40+ * the way:
41 *
42- * - A stack element appears as a regular XML_Content node on the outside,
43- * but only uses a single field -- numchildren -- to store the source
44- * tree node array index. These are the breadcrumbs leading the way back
45- * during pre-order (node first) depth-first traversal.
46+ * - The faster one, pointer jobDest, always leads and writes "what job
47+ * to do" by the other, once they reach that place in the
48+ * array: leader "jobDest" stores the source node array index (relative
49+ * to array dtd->scaffold) in field "numchildren".
50 *
51- * - The reason we know the stack will never grow into (or overlap with)
52- * the area with data of value at the start of the array is because
53- * the overall number of elements to process matches the size of the array,
54- * and the sum of fully processed nodes and yet-to-be processed nodes
55- * on the stack, cannot be more than the total number of nodes.
56- * It is possible for the top of the stack and the about-to-write node
57- * to meet, but that is safe because we get the source index out
58- * before doing any writes on that node.
59+ * - The slower one, pointer dest, looks at the value stored in the
60+ * "numchildren" field (which actually holds a source node array index
61+ * at that time) and puts the real data from dtd->scaffold in.
62+ *
63+ * - Before the loop starts, jobDest writes source array index 0
64+ * (where the root node is located) so that dest will have something to do
65+ * when it starts operation.
66+ *
67+ * - Whenever nodes with children are encountered, jobDest appends
68+ * them as new jobs, in order. As a result, tree node siblings are
69+ * adjacent in the resulting array, for example:
70+ *
71+ * [0] root, has two children
72+ * [1] first child of 0, has three children
73+ * [3] first child of 1, does not have children
74+ * [4] second child of 1, does not have children
75+ * [5] third child of 1, does not have children
76+ * [2] second child of 0, does not have children
77+ *
78+ * Or (the same data) presented in flat array view:
79+ *
80+ * [0] root, has two children
81+ *
82+ * [1] first child of 0, has three children
83+ * [2] second child of 0, does not have children
84+ *
85+ * [3] first child of 1, does not have children
86+ * [4] second child of 1, does not have children
87+ * [5] third child of 1, does not have children
88+ *
89+ * - The algorithm repeats until all target array indices have been processed.
90 */
91 XML_Content *dest = ret; /* tree node writing location, moves upwards */
92 XML_Content *const destLimit = &ret[dtd->scaffCount];
93- XML_Content *const stackBottom = &ret[dtd->scaffCount];
94- XML_Content *stackTop = stackBottom; /* i.e. stack is initially empty */
95+ XML_Content *jobDest = ret; /* next free writing location in target array */
96 str = (XML_Char *)&ret[dtd->scaffCount];
97
98- /* Push source tree root node index onto the stack */
99- (--stackTop)->numchildren = 0;
100+ /* Add the starting job, the root node (index 0) of the source tree */
101+ (jobDest++)->numchildren = 0;
102
103 for (; dest < destLimit; dest++) {
104- /* Pop source tree node index off the stack */
105- const int src_node = (int)(stackTop++)->numchildren;
106+ /* Retrieve source tree array index from job storage */
107+ const int src_node = (int)dest->numchildren;
108
109 /* Convert item */
110 dest->type = dtd->scaffold[src_node].type;
111@@ -7427,16 +7446,12 @@ build_model(XML_Parser parser) {
112 int cn;
113 dest->name = NULL;
114 dest->numchildren = dtd->scaffold[src_node].childcnt;
115- dest->children = &dest[1];
116+ dest->children = jobDest;
117
118- /* Push children to the stack
119- * in a way where the first child ends up at the top of the
120- * (downwards growing) stack, in order to be processed first. */
121- stackTop -= dest->numchildren;
122+ /* Append scaffold indices of children to array */
123 for (i = 0, cn = dtd->scaffold[src_node].firstchild;
124- i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib) {
125- (stackTop + i)->numchildren = (unsigned int)cn;
126- }
127+ i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib)
128+ (jobDest++)->numchildren = (unsigned int)cn;
129 }
130 }
131
diff --git a/meta/recipes-core/expat/expat/CVE-2022-25313.patch b/meta/recipes-core/expat/expat/CVE-2022-25313.patch
new file mode 100644
index 0000000000..470d66e9dd
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-25313.patch
@@ -0,0 +1,230 @@
1From 9b4ce651b26557f16103c3a366c91934ecd439ab Mon Sep 17 00:00:00 2001
2From: Samanta Navarro <ferivoz@riseup.net>
3Date: Tue, 15 Feb 2022 11:54:29 +0000
4Subject: [PATCH] Prevent stack exhaustion in build_model
5
6It is possible to trigger stack exhaustion in build_model function if
7depth of nested children in DTD element is large enough. This happens
8because build_node is a recursively called function within build_model.
9
10The code has been adjusted to run iteratively. It uses the already
11allocated heap space as temporary stack (growing from top to bottom).
12
13Output is identical to recursive version. No new fields in data
14structures were added, i.e. it keeps full API and ABI compatibility.
15Instead the numchildren variable is used to temporarily keep the
16index of items (uint vs int).
17
18Documentation and readability improvements kindly added by Sebastian.
19
20Proof of Concept:
21
221. Compile poc binary which parses XML file line by line
23
24```
25cat > poc.c << EOF
26 #include <err.h>
27 #include <expat.h>
28 #include <stdio.h>
29
30 XML_Parser parser;
31
32 static void XMLCALL
33 dummy_element_decl_handler(void *userData, const XML_Char *name,
34 XML_Content *model) {
35 XML_FreeContentModel(parser, model);
36 }
37
38 int main(int argc, char *argv[]) {
39 FILE *fp;
40 char *p = NULL;
41 size_t s = 0;
42 ssize_t l;
43 if (argc != 2)
44 errx(1, "usage: poc poc.xml");
45 if ((parser = XML_ParserCreate(NULL)) == NULL)
46 errx(1, "XML_ParserCreate");
47 XML_SetElementDeclHandler(parser, dummy_element_decl_handler);
48 if ((fp = fopen(argv[1], "r")) == NULL)
49 err(1, "fopen");
50 while ((l = getline(&p, &s, fp)) > 0)
51 if (XML_Parse(parser, p, (int)l, XML_FALSE) != XML_STATUS_OK)
52 errx(1, "XML_Parse");
53 XML_ParserFree(parser);
54 free(p);
55 fclose(fp);
56 return 0;
57 }
58EOF
59cc -std=c11 -D_POSIX_C_SOURCE=200809L -lexpat -o poc poc.c
60```
61
622. Create XML file with a lot of nested groups in DTD element
63
64```
65cat > poc.xml.zst.b64 << EOF
66KLUv/aQkACAAPAEA+DwhRE9DVFlQRSB1d3UgWwo8IUVMRU1FTlQgdXd1CigBAHv/58AJAgAQKAIA
67ECgCABAoAgAQKAIAECgCABAoAgAQKHwAAChvd28KKQIA2/8gV24XBAIAECkCABApAgAQKQIAECkC
68ABApAgAQKQIAEClVAAAgPl0+CgEA4A4I2VwwnQ==
69EOF
70base64 -d poc.xml.zst.b64 | zstd -d > poc.xml
71```
72
733. Run Proof of Concept
74
75```
76./poc poc.xml
77```
78
79Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
80
81Upstream-Status: Backport
82https://github.com/libexpat/libexpat/pull/558/commits/9b4ce651b26557f16103c3a366c91934ecd439ab
83
84CVE: CVE-2022-25313
85
86Signed-off-by: Steve Sakoman <steve@sakoman.com>
87
88---
89 expat/lib/xmlparse.c | 116 +++++++++++++++++++++++++++++--------------
90 1 file changed, 79 insertions(+), 37 deletions(-)
91
92diff --git a/lib/xmlparse.c b/lib/xmlparse.c
93index 4b43e613..594cf12c 100644
94--- a/lib/xmlparse.c
95+++ b/lib/xmlparse.c
96@@ -7317,44 +7317,15 @@ nextScaffoldPart(XML_Parser parser) {
97 return next;
98 }
99
100-static void
101-build_node(XML_Parser parser, int src_node, XML_Content *dest,
102- XML_Content **contpos, XML_Char **strpos) {
103- DTD *const dtd = parser->m_dtd; /* save one level of indirection */
104- dest->type = dtd->scaffold[src_node].type;
105- dest->quant = dtd->scaffold[src_node].quant;
106- if (dest->type == XML_CTYPE_NAME) {
107- const XML_Char *src;
108- dest->name = *strpos;
109- src = dtd->scaffold[src_node].name;
110- for (;;) {
111- *(*strpos)++ = *src;
112- if (! *src)
113- break;
114- src++;
115- }
116- dest->numchildren = 0;
117- dest->children = NULL;
118- } else {
119- unsigned int i;
120- int cn;
121- dest->numchildren = dtd->scaffold[src_node].childcnt;
122- dest->children = *contpos;
123- *contpos += dest->numchildren;
124- for (i = 0, cn = dtd->scaffold[src_node].firstchild; i < dest->numchildren;
125- i++, cn = dtd->scaffold[cn].nextsib) {
126- build_node(parser, cn, &(dest->children[i]), contpos, strpos);
127- }
128- dest->name = NULL;
129- }
130-}
131-
132 static XML_Content *
133 build_model(XML_Parser parser) {
134+ /* Function build_model transforms the existing parser->m_dtd->scaffold
135+ * array of CONTENT_SCAFFOLD tree nodes into a new array of
136+ * XML_Content tree nodes followed by a gapless list of zero-terminated
137+ * strings. */
138 DTD *const dtd = parser->m_dtd; /* save one level of indirection */
139 XML_Content *ret;
140- XML_Content *cpos;
141- XML_Char *str;
142+ XML_Char *str; /* the current string writing location */
143
144 /* Detect and prevent integer overflow.
145 * The preprocessor guard addresses the "always false" warning
146@@ -7380,10 +7351,81 @@ build_model(XML_Parser parser) {
147 if (! ret)
148 return NULL;
149
150- str = (XML_Char *)(&ret[dtd->scaffCount]);
151- cpos = &ret[1];
152+ /* What follows is an iterative implementation (of what was previously done
153+ * recursively in a dedicated function called "build_node". The old recursive
154+ * build_node could be forced into stack exhaustion from input as small as a
155+ * few megabyte, and so that was a security issue. Hence, a function call
156+ * stack is avoided now by resolving recursion.)
157+ *
158+ * The iterative approach works as follows:
159+ *
160+ * - We use space in the target array for building a temporary stack structure
161+ * while that space is still unused.
162+ * The stack grows from the array's end downwards and the "actual data"
163+ * grows from the start upwards, sequentially.
164+ * (Because stack grows downwards, pushing onto the stack is a decrement
165+ * while popping off the stack is an increment.)
166+ *
167+ * - A stack element appears as a regular XML_Content node on the outside,
168+ * but only uses a single field -- numchildren -- to store the source
169+ * tree node array index. These are the breadcrumbs leading the way back
170+ * during pre-order (node first) depth-first traversal.
171+ *
172+ * - The reason we know the stack will never grow into (or overlap with)
173+ * the area with data of value at the start of the array is because
174+ * the overall number of elements to process matches the size of the array,
175+ * and the sum of fully processed nodes and yet-to-be processed nodes
176+ * on the stack, cannot be more than the total number of nodes.
177+ * It is possible for the top of the stack and the about-to-write node
178+ * to meet, but that is safe because we get the source index out
179+ * before doing any writes on that node.
180+ */
181+ XML_Content *dest = ret; /* tree node writing location, moves upwards */
182+ XML_Content *const destLimit = &ret[dtd->scaffCount];
183+ XML_Content *const stackBottom = &ret[dtd->scaffCount];
184+ XML_Content *stackTop = stackBottom; /* i.e. stack is initially empty */
185+ str = (XML_Char *)&ret[dtd->scaffCount];
186+
187+ /* Push source tree root node index onto the stack */
188+ (--stackTop)->numchildren = 0;
189+
190+ for (; dest < destLimit; dest++) {
191+ /* Pop source tree node index off the stack */
192+ const int src_node = (int)(stackTop++)->numchildren;
193+
194+ /* Convert item */
195+ dest->type = dtd->scaffold[src_node].type;
196+ dest->quant = dtd->scaffold[src_node].quant;
197+ if (dest->type == XML_CTYPE_NAME) {
198+ const XML_Char *src;
199+ dest->name = str;
200+ src = dtd->scaffold[src_node].name;
201+ for (;;) {
202+ *str++ = *src;
203+ if (! *src)
204+ break;
205+ src++;
206+ }
207+ dest->numchildren = 0;
208+ dest->children = NULL;
209+ } else {
210+ unsigned int i;
211+ int cn;
212+ dest->name = NULL;
213+ dest->numchildren = dtd->scaffold[src_node].childcnt;
214+ dest->children = &dest[1];
215+
216+ /* Push children to the stack
217+ * in a way where the first child ends up at the top of the
218+ * (downwards growing) stack, in order to be processed first. */
219+ stackTop -= dest->numchildren;
220+ for (i = 0, cn = dtd->scaffold[src_node].firstchild;
221+ i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib) {
222+ (stackTop + i)->numchildren = (unsigned int)cn;
223+ }
224+ }
225+ }
226
227- build_node(parser, 0, ret, &cpos, &str);
228 return ret;
229 }
230
diff --git a/meta/recipes-core/expat/expat/CVE-2022-25314.patch b/meta/recipes-core/expat/expat/CVE-2022-25314.patch
new file mode 100644
index 0000000000..2f713ebb54
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-25314.patch
@@ -0,0 +1,32 @@
1From efcb347440ade24b9f1054671e6bd05e60b4cafd Mon Sep 17 00:00:00 2001
2From: Samanta Navarro <ferivoz@riseup.net>
3Date: Tue, 15 Feb 2022 11:56:57 +0000
4Subject: [PATCH] Prevent integer overflow in copyString
5
6The copyString function is only used for encoding string supplied by
7the library user.
8
9Upstream-Status: Backport
10https://github.com/libexpat/libexpat/pull/560/commits/efcb347440ade24b9f1054671e6bd05e60b4cafd
11
12CVE: CVE-2022-25314
13
14Signed-off-by: Steve Sakoman <steve@sakoman.com>
15
16---
17 expat/lib/xmlparse.c | 2 +-
18 1 file changed, 1 insertion(+), 1 deletion(-)
19
20diff --git a/lib/xmlparse.c b/lib/xmlparse.c
21index 4b43e613..a39377c2 100644
22--- a/lib/xmlparse.c
23+++ b/lib/xmlparse.c
24@@ -7412,7 +7412,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
25
26 static XML_Char *
27 copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
28- int charsRequired = 0;
29+ size_t charsRequired = 0;
30 XML_Char *result;
31
32 /* First determine how long the string is */
diff --git a/meta/recipes-core/expat/expat/CVE-2022-25315.patch b/meta/recipes-core/expat/expat/CVE-2022-25315.patch
new file mode 100644
index 0000000000..a39771d28a
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-25315.patch
@@ -0,0 +1,145 @@
1From eb0362808b4f9f1e2345a0cf203b8cc196d776d9 Mon Sep 17 00:00:00 2001
2From: Samanta Navarro <ferivoz@riseup.net>
3Date: Tue, 15 Feb 2022 11:55:46 +0000
4Subject: [PATCH] Prevent integer overflow in storeRawNames
5
6It is possible to use an integer overflow in storeRawNames for out of
7boundary heap writes. Default configuration is affected. If compiled
8with XML_UNICODE then the attack does not work. Compiling with
9-fsanitize=address confirms the following proof of concept.
10
11The problem can be exploited by abusing the m_buffer expansion logic.
12Even though the initial size of m_buffer is a power of two, eventually
13it can end up a little bit lower, thus allowing allocations very close
14to INT_MAX (since INT_MAX/2 can be surpassed). This means that tag
15names can be parsed which are almost INT_MAX in size.
16
17Unfortunately (from an attacker point of view) INT_MAX/2 is also a
18limitation in string pools. Having a tag name of INT_MAX/2 characters
19or more is not possible.
20
21Expat can convert between different encodings. UTF-16 documents which
22contain only ASCII representable characters are twice as large as their
23ASCII encoded counter-parts.
24
25The proof of concept works by taking these three considerations into
26account:
27
281. Move the m_buffer size slightly below a power of two by having a
29 short root node <a>. This allows the m_buffer to grow very close
30 to INT_MAX.
312. The string pooling forbids tag names longer than or equal to
32 INT_MAX/2, so keep the attack tag name smaller than that.
333. To be able to still overflow INT_MAX even though the name is
34 limited at INT_MAX/2-1 (nul byte) we use UTF-16 encoding and a tag
35 which only contains ASCII characters. UTF-16 always stores two
36 bytes per character while the tag name is converted to using only
37 one. Our attack node byte count must be a bit higher than
38 2/3 INT_MAX so the converted tag name is around INT_MAX/3 which
39 in sum can overflow INT_MAX.
40
41Thanks to our small root node, m_buffer can handle 2/3 INT_MAX bytes
42without running into INT_MAX boundary check. The string pooling is
43able to store INT_MAX/3 as tag name because the amount is below
44INT_MAX/2 limitation. And creating the sum of both eventually overflows
45in storeRawNames.
46
47Proof of Concept:
48
491. Compile expat with -fsanitize=address.
50
512. Create Proof of Concept binary which iterates through input
52 file 16 MB at once for better performance and easier integer
53 calculations:
54
55```
56cat > poc.c << EOF
57 #include <err.h>
58 #include <expat.h>
59 #include <stdlib.h>
60 #include <stdio.h>
61
62 #define CHUNK (16 * 1024 * 1024)
63 int main(int argc, char *argv[]) {
64 XML_Parser parser;
65 FILE *fp;
66 char *buf;
67 int i;
68
69 if (argc != 2)
70 errx(1, "usage: poc file.xml");
71 if ((parser = XML_ParserCreate(NULL)) == NULL)
72 errx(1, "failed to create expat parser");
73 if ((fp = fopen(argv[1], "r")) == NULL) {
74 XML_ParserFree(parser);
75 err(1, "failed to open file");
76 }
77 if ((buf = malloc(CHUNK)) == NULL) {
78 fclose(fp);
79 XML_ParserFree(parser);
80 err(1, "failed to allocate buffer");
81 }
82 i = 0;
83 while (fread(buf, CHUNK, 1, fp) == 1) {
84 printf("iteration %d: XML_Parse returns %d\n", ++i,
85 XML_Parse(parser, buf, CHUNK, XML_FALSE));
86 }
87 free(buf);
88 fclose(fp);
89 XML_ParserFree(parser);
90 return 0;
91 }
92EOF
93gcc -fsanitize=address -lexpat -o poc poc.c
94```
95
963. Construct specially prepared UTF-16 XML file:
97
98```
99dd if=/dev/zero bs=1024 count=794624 | tr '\0' 'a' > poc-utf8.xml
100echo -n '<a><' | dd conv=notrunc of=poc-utf8.xml
101echo -n '><' | dd conv=notrunc of=poc-utf8.xml bs=1 seek=805306368
102iconv -f UTF-8 -t UTF-16LE poc-utf8.xml > poc-utf16.xml
103```
104
1054. Run proof of concept:
106
107```
108./poc poc-utf16.xml
109```
110
111Upstream-Status: Backport
112https://github.com/libexpat/libexpat/pull/559/commits/eb0362808b4f9f1e2345a0cf203b8cc196d776d9
113
114CVE: CVE-2022-25315
115
116Signed-off-by: Steve Sakoman <steve@sakoman.com>
117---
118 lib/xmlparse.c | 7 ++++++-
119 1 file changed, 6 insertions(+), 1 deletion(-)
120
121diff --git a/lib/xmlparse.c b/lib/xmlparse.c
122index 4b43e613..f34d6ab5 100644
123--- a/lib/xmlparse.c
124+++ b/lib/xmlparse.c
125@@ -2563,6 +2563,7 @@ storeRawNames(XML_Parser parser) {
126 while (tag) {
127 int bufSize;
128 int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
129+ size_t rawNameLen;
130 char *rawNameBuf = tag->buf + nameLen;
131 /* Stop if already stored. Since m_tagStack is a stack, we can stop
132 at the first entry that has already been copied; everything
133@@ -2574,7 +2575,11 @@ storeRawNames(XML_Parser parser) {
134 /* For re-use purposes we need to ensure that the
135 size of tag->buf is a multiple of sizeof(XML_Char).
136 */
137- bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
138+ rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
139+ /* Detect and prevent integer overflow. */
140+ if (rawNameLen > (size_t)INT_MAX - nameLen)
141+ return XML_FALSE;
142+ bufSize = nameLen + (int)rawNameLen;
143 if (bufSize > tag->bufEnd - tag->buf) {
144 char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
145 if (temp == NULL)
diff --git a/meta/recipes-core/expat/expat/CVE-2022-40674.patch b/meta/recipes-core/expat/expat/CVE-2022-40674.patch
new file mode 100644
index 0000000000..8b95f5f198
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-40674.patch
@@ -0,0 +1,53 @@
1From 4a32da87e931ba54393d465bb77c40b5c33d343b Mon Sep 17 00:00:00 2001
2From: Rhodri James <rhodri@wildebeest.org.uk>
3Date: Wed, 17 Aug 2022 18:26:18 +0100
4Subject: [PATCH] Ensure raw tagnames are safe exiting internalEntityParser
5
6It is possible to concoct a situation in which parsing is
7suspended while substituting in an internal entity, so that
8XML_ResumeParser directly uses internalEntityProcessor as
9its processor. If the subsequent parse includes some unclosed
10tags, this will return without calling storeRawNames to ensure
11that the raw versions of the tag names are stored in memory other
12than the parse buffer itself. If the parse buffer is then changed
13or reallocated (for example if processing a file line by line),
14badness will ensue.
15
16This patch ensures storeRawNames is always called when needed
17after calling doContent. The earlier call do doContent does
18not need the same protection; it only deals with entity
19substitution, which cannot leave unbalanced tags, and in any
20case the raw names will be pointing into the stored entity
21value not the parse buffer.
22
23Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/4a32da87e931ba54393d465bb77c40b5c33d343b]
24CVE: CVE-2022-40674
25Signed-off-by: Virendra Thakur <virendrak@kpit.com>
26---
27 expat/lib/xmlparse.c | 13 +++++++++----
28 1 file changed, 9 insertions(+), 4 deletions(-)
29
30Index: expat/lib/xmlparse.c
31===================================================================
32--- a/lib/xmlparse.c
33+++ b/lib/xmlparse.c
34@@ -5657,10 +5657,15 @@ internalEntityProcessor(XML_Parser parse
35 {
36 parser->m_processor = contentProcessor;
37 /* see externalEntityContentProcessor vs contentProcessor */
38- return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding,
39- s, end, nextPtr,
40- (XML_Bool)! parser->m_parsingStatus.finalBuffer,
41- XML_ACCOUNT_DIRECT);
42+ result = doContent(parser, parser->m_parentParser ? 1 : 0,
43+ parser->m_encoding, s, end, nextPtr,
44+ (XML_Bool)! parser->m_parsingStatus.finalBuffer,
45+ XML_ACCOUNT_DIRECT);
46+ if (result == XML_ERROR_NONE) {
47+ if (! storeRawNames(parser))
48+ return XML_ERROR_NO_MEMORY;
49+ }
50+ return result;
51 }
52 }
53
diff --git a/meta/recipes-core/expat/expat/CVE-2022-43680.patch b/meta/recipes-core/expat/expat/CVE-2022-43680.patch
new file mode 100644
index 0000000000..6f93bc3ed7
--- /dev/null
+++ b/meta/recipes-core/expat/expat/CVE-2022-43680.patch
@@ -0,0 +1,33 @@
1From 5290462a7ea1278a8d5c0d5b2860d4e244f997e4 Mon Sep 17 00:00:00 2001
2From: Sebastian Pipping <sebastian@pipping.org>
3Date: Tue, 20 Sep 2022 02:44:34 +0200
4Subject: [PATCH] lib: Fix overeager DTD destruction in
5 XML_ExternalEntityParserCreate
6
7CVE: CVE-2022-43680
8Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/5290462a7ea1278a8d5c0d5b2860d4e244f997e4.patch]
9Signed-off-by: Ranjitsinh Rathod <ranjitsinh.rathod@kpit.com>
10Comments: Hunk refreshed
11---
12 lib/xmlparse.c | 8 ++++++++
13 1 file changed, 8 insertions(+)
14
15diff --git a/lib/xmlparse.c b/lib/xmlparse.c
16index aacd6e7fc..57bf103cc 100644
17--- a/lib/xmlparse.c
18+++ b/lib/xmlparse.c
19@@ -1035,6 +1035,14 @@ parserCreate(const XML_Char *encodingNam
20 parserInit(parser, encodingName);
21
22 if (encodingName && ! parser->m_protocolEncodingName) {
23+ if (dtd) {
24+ // We need to stop the upcoming call to XML_ParserFree from happily
25+ // destroying parser->m_dtd because the DTD is shared with the parent
26+ // parser and the only guard that keeps XML_ParserFree from destroying
27+ // parser->m_dtd is parser->m_isParamEntity but it will be set to
28+ // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all).
29+ parser->m_dtd = NULL;
30+ }
31 XML_ParserFree(parser);
32 return NULL;
33 }
diff --git a/meta/recipes-core/expat/expat/libtool-tag.patch b/meta/recipes-core/expat/expat/libtool-tag.patch
index 0a0aed23e5..c59ccbbede 100644
--- a/meta/recipes-core/expat/expat/libtool-tag.patch
+++ b/meta/recipes-core/expat/expat/libtool-tag.patch
@@ -1,30 +1,27 @@
1From 10342e6b600858b091bc7771e454d9e06af06410 Mon Sep 17 00:00:00 2001 1From da433dbe79f2d4d5d7d79869c669594c99c5de9c Mon Sep 17 00:00:00 2001
2From: Khem Raj <raj.khem@gmail.com> 2From: Jasper Orschulko <jasper@fancydomain.eu>
3Date: Thu, 2 Nov 2017 18:20:57 +0800 3Date: Wed, 16 Jun 2021 19:00:30 +0200
4Subject: [PATCH] Add CC tag to build 4Subject: [PATCH] Add CC tag to build
5 5
6Add CC tag to build
7
8Upstream-Status: Pending 6Upstream-Status: Pending
9Signed-off-by: Khem Raj <raj.khem@gmail.com> 7Signed-off-by: Jasper Orschulko <jasper@fancydomain.eu>
10Signed-off-by: Dengke Du <dengke.du@windriver.com>
11--- 8---
12 Makefile.in | 2 +- 9 Makefile.am | 2 +-
13 1 file changed, 1 insertion(+), 1 deletion(-) 10 1 file changed, 1 insertion(+), 1 deletion(-)
14 11
15diff --git a/Makefile.in b/Makefile.in 12diff --git a/Makefile.am b/Makefile.am
16index 9560a95..d444bd6 100644 13index 5e1d37dd..f7a6dece 100644
17--- a/Makefile.in 14--- a/Makefile.am
18+++ b/Makefile.in 15+++ b/Makefile.am
19@@ -319,7 +319,7 @@ LIBCURRENT = @LIBCURRENT@ 16@@ -36,7 +36,7 @@ AUTOMAKE_OPTIONS = \
20 LIBOBJS = @LIBOBJS@ 17 subdir-objects
21 LIBREVISION = @LIBREVISION@ 18
22 LIBS = @LIBS@ 19 ACLOCAL_AMFLAGS = -I m4
23-LIBTOOL = @LIBTOOL@ 20-LIBTOOLFLAGS = --verbose
24+LIBTOOL = @LIBTOOL@ --tag CC 21+LIBTOOLFLAGS = --verbose --tag=CC
25 LIPO = @LIPO@ 22
26 LN_S = @LN_S@ 23 SUBDIRS = lib # lib goes first to build first
27 LTLIBOBJS = @LTLIBOBJS@ 24 if WITH_EXAMPLES
28-- 25--
292.7.4 262.32.0
30 27