summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Sakoman <steve@sakoman.com>2024-04-10 06:00:20 -0700
committerSteve Sakoman <steve@sakoman.com>2024-04-19 04:50:38 -0700
commitca3bb1f53edd77f581e616b3382eeb8af25e06d1 (patch)
treeb39e4b40b93e1973c97d19ed8dddd9d90b2deb76
parent71267466e9cea253067375376aa7cbbd1e0593e7 (diff)
downloadpoky-ca3bb1f53edd77f581e616b3382eeb8af25e06d1.tar.gz
Revert "expat: fix CVE-2023-52425"
This reverts commit 1bdcd10930a2998f6bbe56b3ba4c9b6c91203b39. Causes ptest failures: {'expat': ['test_accounting_precision', 'test_return_ns_triplet', 'test_column_number_after_parse', 'test_default_current', 'test_external_entity_values']} (From OE-Core rev: 46fb46c0fff83da85f37a1ea705170a6d2039eff) Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0001.patch40
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0002.patch87
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0003.patch222
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0004.patch42
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0005.patch69
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0006.patch67
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0007.patch159
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0008.patch95
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0009.patch52
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0010.patch111
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0011.patch89
-rw-r--r--meta/recipes-core/expat/expat/CVE-2023-52425-0012.patch87
-rw-r--r--meta/recipes-core/expat/expat_2.5.0.bb12
13 files changed, 0 insertions, 1132 deletions
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0001.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0001.patch
deleted file mode 100644
index 4e21ade018..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0001.patch
+++ /dev/null
@@ -1,40 +0,0 @@
1From d5b02e96ab95d2a7ae0aea72d00054b9d036d76d Mon Sep 17 00:00:00 2001
2From: Sebastian Pipping <sebastian@pipping.org>
3Date: Thu, 9 Nov 2023 19:28:05 +0100
4Subject: [PATCH] xmlwf: Document argument "-q"
5
6Rebased-and-adapted-by: Snild Dolkow <snild@sony.com>
7
8CVE: CVE-2023-52425
9
10Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/d5b02e96ab95d2a7ae0aea72d00054b9d036d76d]
11
12Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
13---
14 doc/xmlwf.xml | 10 ++++++++++
15 1 file changed, 10 insertions(+)
16
17diff --git a/doc/xmlwf.xml b/doc/xmlwf.xml
18index 9603abf..3d35393 100644
19--- a/doc/xmlwf.xml
20+++ b/doc/xmlwf.xml
21@@ -313,6 +313,16 @@ supports both.
22 </listitem>
23 </varlistentry>
24
25+ <varlistentry>
26+ <term><option>-q</option></term>
27+ <listitem>
28+ <para>
29+ Disable reparse deferral, and allow quadratic parse runtime
30+ on large tokens (default: reparse deferral enabled).
31+ </para>
32+ </listitem>
33+ </varlistentry>
34+
35 <varlistentry>
36 <term><option>-r</option></term>
37 <listitem>
38--
392.40.0
40
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0002.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0002.patch
deleted file mode 100644
index 8376727778..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0002.patch
+++ /dev/null
@@ -1,87 +0,0 @@
1From 09fdf998e7cf3f8f9327e6602077791095aedd4d Mon Sep 17 00:00:00 2001
2From: Sebastian Pipping <sebastian@pipping.org>
3Date: Thu, 9 Nov 2023 19:14:14 +0100
4Subject: [PATCH] xmlwf: Support disabling reparse deferral
5
6Rebased-and-adapted-by: Snild Dolkow <snild@sony.com>
7
8CVE: CVE-2023-52425
9
10Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/09fdf998e7cf3f8f9327e6602077791095aedd4d]
11
12Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
13---
14 xmlwf/xmlwf.c | 20 ++++++++++++++++++++
15 xmlwf/xmlwf_helpgen.py | 4 ++++
16 2 files changed, 24 insertions(+)
17
18diff --git a/xmlwf/xmlwf.c b/xmlwf/xmlwf.c
19index dd023a9..9a5441c 100644
20--- a/xmlwf/xmlwf.c
21+++ b/xmlwf/xmlwf.c
22@@ -911,6 +911,9 @@ usage(const XML_Char *prog, int rc) {
23 T("billion laughs attack protection:\n")
24 T(" NOTE: If you ever need to increase these values for non-attack payload, please file a bug report.\n")
25 T("\n")
26+ T("reparse deferral:\n")
27+ T(" -q disable reparse deferral, and allow [q]uadratic parse runtime with large tokens\n")
28+ T("\n")
29 T(" -a FACTOR set maximum tolerated [a]mplification factor (default: 100.0)\n")
30 T(" -b BYTES set number of output [b]ytes needed to activate (default: 8 MiB)\n")
31 T("\n")
32@@ -967,6 +970,8 @@ tmain(int argc, XML_Char **argv) {
33 unsigned long long attackThresholdBytes;
34 XML_Bool attackThresholdGiven = XML_FALSE;
35
36+ XML_Bool disableDeferral = XML_FALSE;
37+
38 int exitCode = XMLWF_EXIT_SUCCESS;
39 enum XML_ParamEntityParsing paramEntityParsing
40 = XML_PARAM_ENTITY_PARSING_NEVER;
41@@ -1091,6 +1096,11 @@ tmain(int argc, XML_Char **argv) {
42 #endif
43 break;
44 }
45+ case T('q'): {
46+ disableDeferral = XML_TRUE;
47+ j++;
48+ break;
49+ }
50 case T('\0'):
51 if (j > 1) {
52 i++;
53@@ -1136,6 +1146,16 @@ tmain(int argc, XML_Char **argv) {
54 #endif
55 }
56
57+ if (disableDeferral) {
58+ const XML_Bool success = XML_SetReparseDeferralEnabled(parser, XML_FALSE);
59+ if (! success) {
60+ // This prevents tperror(..) from reporting misleading "[..]: Success"
61+ errno = EINVAL;
62+ tperror(T("Failed to disable reparse deferral"));
63+ exit(XMLWF_EXIT_INTERNAL_ERROR);
64+ }
65+ }
66+
67 if (requireStandalone)
68 XML_SetNotStandaloneHandler(parser, notStandalone);
69 XML_SetParamEntityParsing(parser, paramEntityParsing);
70diff --git a/xmlwf/xmlwf_helpgen.py b/xmlwf/xmlwf_helpgen.py
71index c2a527f..1bd0a0a 100755
72--- a/xmlwf/xmlwf_helpgen.py
73+++ b/xmlwf/xmlwf_helpgen.py
74@@ -81,6 +81,10 @@ billion_laughs.add_argument('-a', metavar='FACTOR',
75 help='set maximum tolerated [a]mplification factor (default: 100.0)')
76 billion_laughs.add_argument('-b', metavar='BYTES', help='set number of output [b]ytes needed to activate (default: 8 MiB)')
77
78+reparse_deferral = parser.add_argument_group('reparse deferral')
79+reparse_deferral.add_argument('-q', metavar='FACTOR',
80+ help='disable reparse deferral, and allow [q]uadratic parse runtime with large tokens')
81+
82 parser.add_argument('files', metavar='FILE', nargs='*', help='file to process (default: STDIN)')
83
84 info = parser.add_argument_group('info arguments')
85--
862.40.0
87
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0003.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0003.patch
deleted file mode 100644
index e5c3606e19..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0003.patch
+++ /dev/null
@@ -1,222 +0,0 @@
1From 9cdf9b8d77d5c2c2a27d15fb68dd3f83cafb45a1 Mon Sep 17 00:00:00 2001
2From: Snild Dolkow <snild@sony.com>
3Date: Thu, 17 Aug 2023 16:25:26 +0200
4Subject: [PATCH] Skip parsing after repeated partials on the same token When
5 the parse buffer contains the starting bytes of a token but not all of them,
6 we cannot parse the token to completion. We call this a partial token. When
7 this happens, the parse position is reset to the start of the token, and the
8 parse() call returns. The client is then expected to provide more data and
9 call parse() again.
10MIME-Version: 1.0
11Content-Type: text/plain; charset=UTF-8
12Content-Transfer-Encoding: 8bit
13
14In extreme cases, this means that the bytes of a token may be parsed
15many times: once for every buffer refill required before the full token
16is present in the buffer.
17
18Math:
19 Assume there's a token of T bytes
20 Assume the client fills the buffer in chunks of X bytes
21 We'll try to parse X, 2X, 3X, 4X ... until mX == T (technically >=)
22 That's (m²+m)X/2 = (T²/X+T)/2 bytes parsed (arithmetic progression)
23 While it is alleviated by larger refills, this amounts to O(T²)
24
25Expat grows its internal buffer by doubling it when necessary, but has
26no way to inform the client about how much space is available. Instead,
27we add a heuristic that skips parsing when we've repeatedly stopped on
28an incomplete token. Specifically:
29
30 * Only try to parse if we have a certain amount of data buffered
31 * Every time we stop on an incomplete token, double the threshold
32 * As soon as any token completes, the threshold is reset
33
34This means that when we get stuck on an incomplete token, the threshold
35grows exponentially, effectively making the client perform larger buffer
36fills, limiting how many times we can end up re-parsing the same bytes.
37
38Math:
39 Assume there's a token of T bytes
40 Assume the client fills the buffer in chunks of X bytes
41 We'll try to parse X, 2X, 4X, 8X ... until (2^k)X == T (or larger)
42 That's (2^(k+1)-1)X bytes parsed -- e.g. 15X if T = 8X
43 This is equal to 2T-X, which amounts to O(T)
44
45We could've chosen a faster growth rate, e.g. 4 or 8. Those seem to
46increase performance further, at the cost of further increasing the
47risk of growing the buffer more than necessary. This can easily be
48adjusted in the future, if desired.
49
50This is all completely transparent to the client, except for:
511. possible delay of some callbacks (when our heuristic overshoots)
522. apps that never do isFinal=XML_TRUE could miss data at the end
53
54For the affected testdata, this change shows a 100-400x speedup.
55The recset.xml benchmark shows no clear change either way.
56
57Before:
58benchmark -n ../testdata/largefiles/recset.xml 65535 3
59 3 loops, with buffer size 65535. Average time per loop: 0.270223
60benchmark -n ../testdata/largefiles/aaaaaa_attr.xml 4096 3
61 3 loops, with buffer size 4096. Average time per loop: 15.033048
62benchmark -n ../testdata/largefiles/aaaaaa_cdata.xml 4096 3
63 3 loops, with buffer size 4096. Average time per loop: 0.018027
64benchmark -n ../testdata/largefiles/aaaaaa_comment.xml 4096 3
65 3 loops, with buffer size 4096. Average time per loop: 11.775362
66benchmark -n ../testdata/largefiles/aaaaaa_tag.xml 4096 3
67 3 loops, with buffer size 4096. Average time per loop: 11.711414
68benchmark -n ../testdata/largefiles/aaaaaa_text.xml 4096 3
69 3 loops, with buffer size 4096. Average time per loop: 0.019362
70
71After:
72./run.sh benchmark -n ../testdata/largefiles/recset.xml 65535 3
73 3 loops, with buffer size 65535. Average time per loop: 0.269030
74./run.sh benchmark -n ../testdata/largefiles/aaaaaa_attr.xml 4096 3
75 3 loops, with buffer size 4096. Average time per loop: 0.044794
76./run.sh benchmark -n ../testdata/largefiles/aaaaaa_cdata.xml 4096 3
77 3 loops, with buffer size 4096. Average time per loop: 0.016377
78./run.sh benchmark -n ../testdata/largefiles/aaaaaa_comment.xml 4096 3
79 3 loops, with buffer size 4096. Average time per loop: 0.027022
80./run.sh benchmark -n ../testdata/largefiles/aaaaaa_tag.xml 4096 3
81 3 loops, with buffer size 4096. Average time per loop: 0.099360
82./run.sh benchmark -n ../testdata/largefiles/aaaaaa_text.xml 4096 3
83 3 loops, with buffer size 4096. Average time per loop: 0.017956
84
85CVE: CVE-2023-52425
86
87Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/9cdf9b8d77d5c2c2a27d15fb68dd3f83cafb45a1]
88
89Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
90---
91 lib/xmlparse.c | 58 +++++++++++++++++++++++++++++++++-----------------
92 1 file changed, 39 insertions(+), 19 deletions(-)
93
94diff --git a/lib/xmlparse.c b/lib/xmlparse.c
95index bbffcaa..5695417 100644
96--- a/lib/xmlparse.c
97+++ b/lib/xmlparse.c
98@@ -81,6 +81,7 @@
99 # endif
100 #endif
101
102+#include <stdbool.h>
103 #include <stddef.h>
104 #include <string.h> /* memset(), memcpy() */
105 #include <assert.h>
106@@ -629,6 +630,7 @@ struct XML_ParserStruct {
107 const char *m_bufferLim;
108 XML_Index m_parseEndByteIndex;
109 const char *m_parseEndPtr;
110+ size_t m_partialTokenBytesBefore; /* used in heuristic to avoid O(n^2) */
111 XML_Char *m_dataBuf;
112 XML_Char *m_dataBufEnd;
113 XML_StartElementHandler m_startElementHandler;
114@@ -960,6 +962,32 @@ get_hash_secret_salt(XML_Parser parser) {
115 return parser->m_hash_secret_salt;
116 }
117
118+static enum XML_Error
119+callProcessor(XML_Parser parser, const char *start, const char *end,
120+ const char **endPtr) {
121+ const size_t have_now = EXPAT_SAFE_PTR_DIFF(end, start);
122+
123+ if (! parser->m_parsingStatus.finalBuffer) {
124+ // Heuristic: don't try to parse a partial token again until the amount of
125+ // available data has increased significantly.
126+ const size_t had_before = parser->m_partialTokenBytesBefore;
127+ const bool enough = (have_now >= 2 * had_before);
128+
129+ if (! enough) {
130+ *endPtr = start; // callers may expect this to be set
131+ return XML_ERROR_NONE;
132+ }
133+ }
134+ const enum XML_Error ret = parser->m_processor(parser, start, end, endPtr);
135+ // if we consumed nothing, remember what we had on this parse attempt.
136+ if (*endPtr == start) {
137+ parser->m_partialTokenBytesBefore = have_now;
138+ } else {
139+ parser->m_partialTokenBytesBefore = 0;
140+ }
141+ return ret;
142+}
143+
144 static XML_Bool /* only valid for root parser */
145 startParsing(XML_Parser parser) {
146 /* hash functions must be initialized before setContext() is called */
147@@ -1141,6 +1169,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
148 parser->m_bufferEnd = parser->m_buffer;
149 parser->m_parseEndByteIndex = 0;
150 parser->m_parseEndPtr = NULL;
151+ parser->m_partialTokenBytesBefore = 0;
152 parser->m_declElementType = NULL;
153 parser->m_declAttributeId = NULL;
154 parser->m_declEntity = NULL;
155@@ -1872,29 +1901,20 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
156 to detect errors based on that fact.
157 */
158 parser->m_errorCode
159- = parser->m_processor(parser, parser->m_bufferPtr,
160- parser->m_parseEndPtr, &parser->m_bufferPtr);
161+ = callProcessor(parser, parser->m_bufferPtr, parser->m_parseEndPtr,
162+ &parser->m_bufferPtr);
163
164 if (parser->m_errorCode == XML_ERROR_NONE) {
165 switch (parser->m_parsingStatus.parsing) {
166 case XML_SUSPENDED:
167- /* It is hard to be certain, but it seems that this case
168- * cannot occur. This code is cleaning up a previous parse
169- * with no new data (since len == 0). Changing the parsing
170- * state requires getting to execute a handler function, and
171- * there doesn't seem to be an opportunity for that while in
172- * this circumstance.
173- *
174- * Given the uncertainty, we retain the code but exclude it
175- * from coverage tests.
176- *
177- * LCOV_EXCL_START
178- */
179+ /* While we added no new data, the finalBuffer flag may have caused
180+ * us to parse previously-unparsed data in the internal buffer.
181+ * If that triggered a callback to the application, it would have
182+ * had an opportunity to suspend parsing. */
183 XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
184 parser->m_bufferPtr, &parser->m_position);
185 parser->m_positionPtr = parser->m_bufferPtr;
186 return XML_STATUS_SUSPENDED;
187- /* LCOV_EXCL_STOP */
188 case XML_INITIALIZED:
189 case XML_PARSING:
190 parser->m_parsingStatus.parsing = XML_FINISHED;
191@@ -1924,7 +1944,7 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
192 parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
193
194 parser->m_errorCode
195- = parser->m_processor(parser, s, parser->m_parseEndPtr = s + len, &end);
196+ = callProcessor(parser, s, parser->m_parseEndPtr = s + len, &end);
197
198 if (parser->m_errorCode != XML_ERROR_NONE) {
199 parser->m_eventEndPtr = parser->m_eventPtr;
200@@ -2027,8 +2047,8 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) {
201 parser->m_parseEndByteIndex += len;
202 parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
203
204- parser->m_errorCode = parser->m_processor(
205- parser, start, parser->m_parseEndPtr, &parser->m_bufferPtr);
206+ parser->m_errorCode = callProcessor(parser, start, parser->m_parseEndPtr,
207+ &parser->m_bufferPtr);
208
209 if (parser->m_errorCode != XML_ERROR_NONE) {
210 parser->m_eventEndPtr = parser->m_eventPtr;
211@@ -2220,7 +2240,7 @@ XML_ResumeParser(XML_Parser parser) {
212 }
213 parser->m_parsingStatus.parsing = XML_PARSING;
214
215- parser->m_errorCode = parser->m_processor(
216+ parser->m_errorCode = callProcessor(
217 parser, parser->m_bufferPtr, parser->m_parseEndPtr, &parser->m_bufferPtr);
218
219 if (parser->m_errorCode != XML_ERROR_NONE) {
220--
2212.40.0
222
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0004.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0004.patch
deleted file mode 100644
index 35e8e0b1e5..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0004.patch
+++ /dev/null
@@ -1,42 +0,0 @@
1From 1b9d398517befeb944cbbadadf10992b07e96fa2 Mon Sep 17 00:00:00 2001
2From: Snild Dolkow <snild@sony.com>
3Date: Mon, 4 Sep 2023 17:21:14 +0200
4Subject: [PATCH] [PATCH] Don't update partial token heuristic on error
5
6Suggested-by: Sebastian Pipping <sebastian@pipping.org>
7
8CVE: CVE-2023-52425
9
10Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/1b9d398517befeb944cbbadadf10992b07e96fa2]
11
12Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
13---
14 lib/xmlparse.c | 12 +++++++-----
15 1 file changed, 7 insertions(+), 5 deletions(-)
16
17diff --git a/lib/xmlparse.c b/lib/xmlparse.c
18index 5695417..5c66f54 100644
19--- a/lib/xmlparse.c
20+++ b/lib/xmlparse.c
21@@ -979,11 +979,13 @@ callProcessor(XML_Parser parser, const char *start, const char *end,
22 }
23 }
24 const enum XML_Error ret = parser->m_processor(parser, start, end, endPtr);
25- // if we consumed nothing, remember what we had on this parse attempt.
26- if (*endPtr == start) {
27- parser->m_partialTokenBytesBefore = have_now;
28- } else {
29- parser->m_partialTokenBytesBefore = 0;
30+ if (ret == XML_ERROR_NONE) {
31+ // if we consumed nothing, remember what we had on this parse attempt.
32+ if (*endPtr == start) {
33+ parser->m_partialTokenBytesBefore = have_now;
34+ } else {
35+ parser->m_partialTokenBytesBefore = 0;
36+ }
37 }
38 return ret;
39 }
40--
412.40.0
42
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0005.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0005.patch
deleted file mode 100644
index d4e112db58..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0005.patch
+++ /dev/null
@@ -1,69 +0,0 @@
1From 09957b8ced725b96a95acff150facda93f03afe1 Mon Sep 17 00:00:00 2001
2From: Snild Dolkow <snild@sony.com>
3Date: Thu, 26 Oct 2023 10:41:00 +0200
4Subject: [PATCH] Allow XML_GetBuffer() with len=0 on a fresh parser
5
6len=0 was previously OK if there had previously been a non-zero call.
7It makes sense to allow an application to work the same way on a
8newly-created parser, and not have to care if its incoming buffer
9happens to be 0.
10
11CVE: CVE-2023-52425
12
13Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/09957b8ced725b96a95acff150facda93f03afe1]
14
15Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
16---
17 lib/xmlparse.c | 22 +++++++++++-----------
18 1 file changed, 11 insertions(+), 11 deletions(-)
19
20diff --git a/lib/xmlparse.c b/lib/xmlparse.c
21index 5c66f54..5b112c6 100644
22--- a/lib/xmlparse.c
23+++ b/lib/xmlparse.c
24@@ -2095,7 +2095,8 @@ XML_GetBuffer(XML_Parser parser, int len) {
25 default:;
26 }
27
28- if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)) {
29+ if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)
30+ || parser->m_buffer == NULL) {
31 #ifdef XML_CONTEXT_BYTES
32 int keep;
33 #endif /* defined XML_CONTEXT_BYTES */
34@@ -2118,8 +2119,9 @@ XML_GetBuffer(XML_Parser parser, int len) {
35 }
36 neededSize += keep;
37 #endif /* defined XML_CONTEXT_BYTES */
38- if (neededSize
39- <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
40+ if (parser->m_buffer && parser->m_bufferPtr
41+ && neededSize
42+ <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
43 #ifdef XML_CONTEXT_BYTES
44 if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) {
45 int offset
46@@ -2133,14 +2135,12 @@ XML_GetBuffer(XML_Parser parser, int len) {
47 parser->m_bufferPtr -= offset;
48 }
49 #else
50- if (parser->m_buffer && parser->m_bufferPtr) {
51- memmove(parser->m_buffer, parser->m_bufferPtr,
52- EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
53- parser->m_bufferEnd
54- = parser->m_buffer
55- + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
56- parser->m_bufferPtr = parser->m_buffer;
57- }
58+ memmove(parser->m_buffer, parser->m_bufferPtr,
59+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
60+ parser->m_bufferEnd
61+ = parser->m_buffer
62+ + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
63+ parser->m_bufferPtr = parser->m_buffer;
64 #endif /* not defined XML_CONTEXT_BYTES */
65 } else {
66 char *newBuf;
67--
682.40.0
69
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0006.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0006.patch
deleted file mode 100644
index c1fb4893ed..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0006.patch
+++ /dev/null
@@ -1,67 +0,0 @@
1From 9fe3672459c1bf10926b85f013aa1b623d855545 Mon Sep 17 00:00:00 2001
2From: Snild Dolkow <snild@sony.com>
3Date: Mon, 18 Sep 2023 20:32:55 +0200
4Subject: [PATCH] tests: Run both with and without partial token heuristic
5
6If we always run with the heuristic enabled, it may hide some bugs by
7grouping up input into bigger parse attempts.
8
9CI-fighting-assistance-by: Sebastian Pipping <sebastian@pipping.org>
10
11CVE: CVE-2023-52425
12
13Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/9fe3672459c1bf10926b85f013aa1b623d855545]
14
15Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
16---
17 lib/internal.h | 3 +++
18 lib/xmlparse.c | 5 ++++-
19 2 files changed, 7 insertions(+), 1 deletion(-)
20
21diff --git a/lib/internal.h b/lib/internal.h
22index 03c8fde..1df417f 100644
23--- a/lib/internal.h
24+++ b/lib/internal.h
25@@ -31,6 +31,7 @@
26 Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
27 Copyright (c) 2018 Yury Gribov <tetra2005@gmail.com>
28 Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
29+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
30 Licensed under the MIT license:
31
32 Permission is hereby granted, free of charge, to any person obtaining
33@@ -160,6 +161,8 @@ unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
34 const char *unsignedCharToPrintable(unsigned char c);
35 #endif
36
37+extern XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c
38+ //
39 #ifdef __cplusplus
40 }
41 #endif
42diff --git a/lib/xmlparse.c b/lib/xmlparse.c
43index 5b112c6..be6dd92 100644
44--- a/lib/xmlparse.c
45+++ b/lib/xmlparse.c
46@@ -615,6 +615,8 @@ static unsigned long getDebugLevel(const char *variableName,
47 ? 0 \
48 : ((*((pool)->ptr)++ = c), 1))
49
50+XML_Bool g_reparseDeferralEnabledDefault = XML_TRUE; // write ONLY in runtests.c
51+ //
52 struct XML_ParserStruct {
53 /* The first member must be m_userData so that the XML_GetUserData
54 macro works. */
55@@ -967,7 +969,8 @@ callProcessor(XML_Parser parser, const char *start, const char *end,
56 const char **endPtr) {
57 const size_t have_now = EXPAT_SAFE_PTR_DIFF(end, start);
58
59- if (! parser->m_parsingStatus.finalBuffer) {
60+ if (g_reparseDeferralEnabledDefault
61+ && ! parser->m_parsingStatus.finalBuffer) {
62 // Heuristic: don't try to parse a partial token again until the amount of
63 // available data has increased significantly.
64 const size_t had_before = parser->m_partialTokenBytesBefore;
65--
662.40.0
67
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0007.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0007.patch
deleted file mode 100644
index e2fb35eae6..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0007.patch
+++ /dev/null
@@ -1,159 +0,0 @@
1From 1d3162da8a85a398ab451aadd6c2ad19587e5a68 Mon Sep 17 00:00:00 2001
2From: Snild Dolkow <snild@sony.com>
3Date: Mon, 11 Sep 2023 15:31:24 +0200
4Subject: [PATCH] Add app setting for enabling/disabling reparse heuristic
5
6Suggested-by: Sebastian Pipping <sebastian@pipping.org>
7CI-fighting-assistance-by: Sebastian Pipping <sebastian@pipping.org>
8
9CVE: CVE-2023-52425
10
11Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/1d3162da8a85a398ab451aadd6c2ad19587e5a68]
12
13Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
14---
15 doc/reference.html | 30 ++++++++++++++++++++++++------
16 lib/expat.h | 5 +++++
17 lib/libexpat.def.cmake | 2 ++
18 lib/xmlparse.c | 13 ++++++++++++-
19 4 files changed, 43 insertions(+), 7 deletions(-)
20
21diff --git a/doc/reference.html b/doc/reference.html
22index 9953aa7..7dd9370 100644
23--- a/doc/reference.html
24+++ b/doc/reference.html
25@@ -151,10 +151,11 @@ interface.</p>
26 </ul>
27 </li>
28 <li>
29- <a href="#billion-laughs">Billion Laughs Attack Protection</a>
30+ <a href="#attack-protection">Attack Protection</a>
31 <ul>
32 <li><a href="#XML_SetBillionLaughsAttackProtectionMaximumAmplification">XML_SetBillionLaughsAttackProtectionMaximumAmplification</a></li>
33 <li><a href="#XML_SetBillionLaughsAttackProtectionActivationThreshold">XML_SetBillionLaughsAttackProtectionActivationThreshold</a></li>
34+ <li><a href="#XML_SetReparseDeferralEnabled">XML_SetReparseDeferralEnabled</a></li>
35 </ul>
36 </li>
37 <li><a href="#miscellaneous">Miscellaneous Functions</a>
38@@ -2123,11 +2124,7 @@ parse position may be before the beginning of the buffer.</p>
39 return NULL.</p>
40 </div>
41
42-<h3><a name="billion-laughs">Billion Laughs Attack Protection</a></h3>
43-
44-<p>The functions in this section configure the built-in
45- protection against various forms of
46- <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>.</p>
47+<h3><a name="attack-protection">Attack Protection</a><a name="billion-laughs"></a></h3>
48
49 <h4 id="XML_SetBillionLaughsAttackProtectionMaximumAmplification">XML_SetBillionLaughsAttackProtectionMaximumAmplification</h4>
50 <pre class="fcndec">
51@@ -2215,6 +2212,27 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold(XML_Parser p,
52 </p>
53 </div>
54
55+<h4 id="XML_SetReparseDeferralEnabled">XML_SetReparseDeferralEnabled</h4>
56+<pre class="fcndec">
57+/* Added in Expat 2.6.0. */
58+XML_Bool XMLCALL
59+XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
60+</pre>
61+<div class="fcndef">
62+ <p>
63+ Large tokens may require many parse calls before enough data is available for Expat to parse it in full.
64+ If Expat retried parsing the token on every parse call, parsing could take quadratic time.
65+ To avoid this, Expat only retries once a significant amount of new data is available.
66+ This function allows disabling this behavior.
67+ </p>
68+ <p>
69+ The <code>enabled</code> argument should be <code>XML_TRUE</code> or <code>XML_FALSE</code>.
70+ </p>
71+ <p>
72+ Returns <code>XML_TRUE</code> on success, and <code>XML_FALSE</code> on error.
73+ </p>
74+</div>
75+
76 <h3><a name="miscellaneous">Miscellaneous functions</a></h3>
77
78 <p>The functions in this section either obtain state information from
79diff --git a/lib/expat.h b/lib/expat.h
80index 9e64174..73dda6d 100644
81--- a/lib/expat.h
82+++ b/lib/expat.h
83@@ -16,6 +16,7 @@
84 Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
85 Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
86 Copyright (c) 2022 Thijs Schreijer <thijs@thijsschreijer.nl>
87+ Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
88 Licensed under the MIT license:
89
90 Permission is hereby granted, free of charge, to any person obtaining
91@@ -1054,6 +1055,10 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold(
92 XML_Parser parser, unsigned long long activationThresholdBytes);
93 #endif
94
95+/* Added in Expat 2.6.0. */
96+XMLPARSEAPI(XML_Bool)
97+XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
98+
99 /* Expat follows the semantic versioning convention.
100 See http://semver.org.
101 */
102diff --git a/lib/libexpat.def.cmake b/lib/libexpat.def.cmake
103index 61a4f00..10ee9cd 100644
104--- a/lib/libexpat.def.cmake
105+++ b/lib/libexpat.def.cmake
106@@ -77,3 +77,5 @@ EXPORTS
107 ; added with version 2.4.0
108 @_EXPAT_COMMENT_DTD_OR_GE@ XML_SetBillionLaughsAttackProtectionActivationThreshold @69
109 @_EXPAT_COMMENT_DTD_OR_GE@ XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
110+; added with version 2.6.0
111+ XML_SetReparseDeferralEnabled @71
112diff --git a/lib/xmlparse.c b/lib/xmlparse.c
113index be6dd92..8cf32e0 100644
114--- a/lib/xmlparse.c
115+++ b/lib/xmlparse.c
116@@ -633,6 +633,7 @@ struct XML_ParserStruct {
117 XML_Index m_parseEndByteIndex;
118 const char *m_parseEndPtr;
119 size_t m_partialTokenBytesBefore; /* used in heuristic to avoid O(n^2) */
120+ XML_Bool m_reparseDeferralEnabled;
121 XML_Char *m_dataBuf;
122 XML_Char *m_dataBufEnd;
123 XML_StartElementHandler m_startElementHandler;
124@@ -969,7 +970,7 @@ callProcessor(XML_Parser parser, const char *start, const char *end,
125 const char **endPtr) {
126 const size_t have_now = EXPAT_SAFE_PTR_DIFF(end, start);
127
128- if (g_reparseDeferralEnabledDefault
129+ if (parser->m_reparseDeferralEnabled
130 && ! parser->m_parsingStatus.finalBuffer) {
131 // Heuristic: don't try to parse a partial token again until the amount of
132 // available data has increased significantly.
133@@ -1175,6 +1176,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
134 parser->m_parseEndByteIndex = 0;
135 parser->m_parseEndPtr = NULL;
136 parser->m_partialTokenBytesBefore = 0;
137+ parser->m_reparseDeferralEnabled = g_reparseDeferralEnabledDefault;
138 parser->m_declElementType = NULL;
139 parser->m_declAttributeId = NULL;
140 parser->m_declEntity = NULL;
141@@ -2601,6 +2603,15 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold(
142 }
143 #endif /* XML_GE == 1 */
144
145+XML_Bool XMLCALL
146+XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled) {
147+ if (parser != NULL && (enabled == XML_TRUE || enabled == XML_FALSE)) {
148+ parser->m_reparseDeferralEnabled = enabled;
149+ return XML_TRUE;
150+ }
151+ return XML_FALSE;
152+}
153+
154 /* Initially tag->rawName always points into the parse buffer;
155 for those TAG instances opened while the current parse buffer was
156 processed, and not yet closed, we need to store tag->rawName in a more
157--
1582.40.0
159
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0008.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0008.patch
deleted file mode 100644
index fa25fcd2db..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0008.patch
+++ /dev/null
@@ -1,95 +0,0 @@
1From 8ddd8e86aa446d02eb8d398972d3b10d4cad908a Mon Sep 17 00:00:00 2001
2From: Snild Dolkow <snild@sony.com>
3Date: Fri, 29 Sep 2023 10:14:59 +0200
4Subject: [PATCH] Try to parse even when incoming len is zero
5
6If the reparse deferral setting has changed, it may be possible to
7finish a token.
8
9CVE: CVE-2023-52425
10
11Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/8ddd8e86aa446d02eb8d398972d3b10d4cad908a]
12
13Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
14---
15 lib/xmlparse.c | 55 ++++++++------------------------------------------
16 1 file changed, 8 insertions(+), 47 deletions(-)
17
18diff --git a/lib/xmlparse.c b/lib/xmlparse.c
19index 8cf32e0..f4ff66e 100644
20--- a/lib/xmlparse.c
21+++ b/lib/xmlparse.c
22@@ -1896,46 +1896,8 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
23 parser->m_parsingStatus.parsing = XML_PARSING;
24 }
25
26- if (len == 0) {
27- parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
28- if (! isFinal)
29- return XML_STATUS_OK;
30- parser->m_positionPtr = parser->m_bufferPtr;
31- parser->m_parseEndPtr = parser->m_bufferEnd;
32-
33- /* If data are left over from last buffer, and we now know that these
34- data are the final chunk of input, then we have to check them again
35- to detect errors based on that fact.
36- */
37- parser->m_errorCode
38- = callProcessor(parser, parser->m_bufferPtr, parser->m_parseEndPtr,
39- &parser->m_bufferPtr);
40-
41- if (parser->m_errorCode == XML_ERROR_NONE) {
42- switch (parser->m_parsingStatus.parsing) {
43- case XML_SUSPENDED:
44- /* While we added no new data, the finalBuffer flag may have caused
45- * us to parse previously-unparsed data in the internal buffer.
46- * If that triggered a callback to the application, it would have
47- * had an opportunity to suspend parsing. */
48- XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
49- parser->m_bufferPtr, &parser->m_position);
50- parser->m_positionPtr = parser->m_bufferPtr;
51- return XML_STATUS_SUSPENDED;
52- case XML_INITIALIZED:
53- case XML_PARSING:
54- parser->m_parsingStatus.parsing = XML_FINISHED;
55- /* fall through */
56- default:
57- return XML_STATUS_OK;
58- }
59- }
60- parser->m_eventEndPtr = parser->m_eventPtr;
61- parser->m_processor = errorProcessor;
62- return XML_STATUS_ERROR;
63- }
64 #ifndef XML_CONTEXT_BYTES
65- else if (parser->m_bufferPtr == parser->m_bufferEnd) {
66+ if (parser->m_bufferPtr == parser->m_bufferEnd) {
67 const char *end;
68 int nLeftOver;
69 enum XML_Status result;
70@@ -2006,15 +1968,14 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
71 return result;
72 }
73 #endif /* not defined XML_CONTEXT_BYTES */
74- else {
75- void *buff = XML_GetBuffer(parser, len);
76- if (buff == NULL)
77- return XML_STATUS_ERROR;
78- else {
79- memcpy(buff, s, len);
80- return XML_ParseBuffer(parser, len, isFinal);
81- }
82+ void *buff = XML_GetBuffer(parser, len);
83+ if (buff == NULL)
84+ return XML_STATUS_ERROR;
85+ if (len > 0) {
86+ assert(s != NULL); // make sure s==NULL && len!=0 was rejected above
87+ memcpy(buff, s, len);
88 }
89+ return XML_ParseBuffer(parser, len, isFinal);
90 }
91
92 enum XML_Status XMLCALL
93--
942.40.0
95
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0009.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0009.patch
deleted file mode 100644
index 9c1157faac..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0009.patch
+++ /dev/null
@@ -1,52 +0,0 @@
1From ad9c01be8ee5d3d5cac2bfd3949ad764541d35e7 Mon Sep 17 00:00:00 2001
2From: Snild Dolkow <snild@sony.com>
3Date: Thu, 26 Oct 2023 13:55:02 +0200
4Subject: [PATCH] Make external entity parser inherit partial token heuristic
5 setting
6
7The test is essentially a copy of the existing test for the setter,
8adapted to run on the external parser instead of the original one.
9
10Suggested-by: Sebastian Pipping <sebastian@pipping.org>
11CI-fighting-assistance-by: Sebastian Pipping <sebastian@pipping.org>
12
13CVE: CVE-2023-52425
14
15Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/ad9c01be8ee5d3d5cac2bfd3949ad764541d35e7]
16
17Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
18---
19 lib/xmlparse.c | 3 +++
20 1 file changed, 3 insertions(+)
21
22diff --git a/lib/xmlparse.c b/lib/xmlparse.c
23index f4ff66e..6746d70 100644
24--- a/lib/xmlparse.c
25+++ b/lib/xmlparse.c
26@@ -1346,6 +1346,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
27 to worry which hash secrets each table has.
28 */
29 unsigned long oldhash_secret_salt;
30+ XML_Bool oldReparseDeferralEnabled;
31
32 /* Validate the oldParser parameter before we pull everything out of it */
33 if (oldParser == NULL)
34@@ -1390,6 +1391,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
35 to worry which hash secrets each table has.
36 */
37 oldhash_secret_salt = parser->m_hash_secret_salt;
38+ oldReparseDeferralEnabled = parser->m_reparseDeferralEnabled;
39
40 #ifdef XML_DTD
41 if (! context)
42@@ -1442,6 +1444,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
43 parser->m_defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
44 parser->m_ns_triplets = oldns_triplets;
45 parser->m_hash_secret_salt = oldhash_secret_salt;
46+ parser->m_reparseDeferralEnabled = oldReparseDeferralEnabled;
47 parser->m_parentParser = oldParser;
48 #ifdef XML_DTD
49 parser->m_paramEntityParsing = oldParamEntityParsing;
50--
512.40.0
52
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0010.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0010.patch
deleted file mode 100644
index 3fbf69de08..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0010.patch
+++ /dev/null
@@ -1,111 +0,0 @@
1From 60b74209899a67d426d208662674b55a5eed918c Mon Sep 17 00:00:00 2001
2From: Snild Dolkow <snild@sony.com>
3Date: Wed, 4 Oct 2023 16:00:14 +0200
4Subject: [PATCH] Bypass partial token heuristic when close to maximum buffer
5 size
6
7For huge tokens, we may end up in a situation where the partial token
8parse deferral heuristic demands more bytes than Expat's maximum buffer
9size (currently ~half of INT_MAX) could fit.
10
11INT_MAX/2 is 1024 MiB on most systems. Clearly, a token of 950 MiB could
12fit in that buffer, but the reparse threshold might be such that
13callProcessor() will defer it, allowing the app to keep filling the
14buffer until XML_GetBuffer() eventually returns a memory error.
15
16By bypassing the heuristic when we're getting close to the maximum
17buffer size, it will once again be possible to parse tokens in the size
18range INT_MAX/2/ratio < size < INT_MAX/2 reliably.
19
20We subtract the last buffer fill size as a way to detect that the next
21XML_GetBuffer() call has a risk of returning a memory error -- assuming
22that the application is likely to keep using the same (or smaller) fill.
23
24We subtract XML_CONTEXT_BYTES because that's the maximum amount of bytes
25that could remain at the start of the buffer, preceding the partial
26token. Technically, it could be fewer bytes, but XML_CONTEXT_BYTES is
27normally small relative to INT_MAX, and is much simpler to use.
28
29Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
30
31CVE: CVE-2023-52425
32
33Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/60b74209899a67d426d208662674b55a5eed918c]
34
35Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
36---
37 lib/xmlparse.c | 23 ++++++++++++++++++++++-
38 1 file changed, 22 insertions(+), 1 deletion(-)
39
40diff --git a/lib/xmlparse.c b/lib/xmlparse.c
41index 6746d70..32c57f6 100644
42--- a/lib/xmlparse.c
43+++ b/lib/xmlparse.c
44@@ -205,6 +205,8 @@ typedef char ICHAR;
45 /* Do safe (NULL-aware) pointer arithmetic */
46 #define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0)
47
48+#define EXPAT_MIN(a, b) (((a) < (b)) ? (a) : (b))
49+
50 #include "internal.h"
51 #include "xmltok.h"
52 #include "xmlrole.h"
53@@ -634,6 +636,7 @@ struct XML_ParserStruct {
54 const char *m_parseEndPtr;
55 size_t m_partialTokenBytesBefore; /* used in heuristic to avoid O(n^2) */
56 XML_Bool m_reparseDeferralEnabled;
57+ int m_lastBufferRequestSize;
58 XML_Char *m_dataBuf;
59 XML_Char *m_dataBufEnd;
60 XML_StartElementHandler m_startElementHandler;
61@@ -975,7 +978,18 @@ callProcessor(XML_Parser parser, const char *start, const char *end,
62 // Heuristic: don't try to parse a partial token again until the amount of
63 // available data has increased significantly.
64 const size_t had_before = parser->m_partialTokenBytesBefore;
65- const bool enough = (have_now >= 2 * had_before);
66+ // ...but *do* try anyway if we're close to reaching the max buffer size.
67+ size_t close_to_maxbuf = INT_MAX / 2 + (INT_MAX & 1); // round up
68+#if XML_CONTEXT_BYTES > 0
69+ // subtract XML_CONTEXT_BYTES, but don't go below zero
70+ close_to_maxbuf -= EXPAT_MIN(close_to_maxbuf, XML_CONTEXT_BYTES);
71+#endif
72+ // subtract the last buffer fill size, but don't go below zero
73+ // m_lastBufferRequestSize is never assigned a value < 0, so the cast is ok
74+ close_to_maxbuf
75+ -= EXPAT_MIN(close_to_maxbuf, (size_t)parser->m_lastBufferRequestSize);
76+ const bool enough
77+ = (have_now >= 2 * had_before) || (have_now > close_to_maxbuf);
78
79 if (! enough) {
80 *endPtr = start; // callers may expect this to be set
81@@ -1177,6 +1191,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
82 parser->m_parseEndPtr = NULL;
83 parser->m_partialTokenBytesBefore = 0;
84 parser->m_reparseDeferralEnabled = g_reparseDeferralEnabledDefault;
85+ parser->m_lastBufferRequestSize = 0;
86 parser->m_declElementType = NULL;
87 parser->m_declAttributeId = NULL;
88 parser->m_declEntity = NULL;
89@@ -1911,6 +1926,9 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
90 parser->m_processor = errorProcessor;
91 return XML_STATUS_ERROR;
92 }
93+ // though this isn't a buffer request, we assume that `len` is the app's
94+ // preferred buffer fill size, and therefore save it here.
95+ parser->m_lastBufferRequestSize = len;
96 parser->m_parseEndByteIndex += len;
97 parser->m_positionPtr = s;
98 parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
99@@ -2064,6 +2082,9 @@ XML_GetBuffer(XML_Parser parser, int len) {
100 default:;
101 }
102
103+ // whether or not the request succeeds, `len` seems to be the app's preferred
104+ // buffer fill size; remember it.
105+ parser->m_lastBufferRequestSize = len;
106 if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)
107 || parser->m_buffer == NULL) {
108 #ifdef XML_CONTEXT_BYTES
109--
1102.40.0
111
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0011.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0011.patch
deleted file mode 100644
index 800aaff544..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0011.patch
+++ /dev/null
@@ -1,89 +0,0 @@
1From 3d8141d26a3b01ff948e00956cb0723a89dadf7f Mon Sep 17 00:00:00 2001
2From: Snild Dolkow <snild@sony.com>
3Date: Mon, 20 Nov 2023 16:11:24 +0100
4Subject: [PATCH] Bypass partial token heuristic when nearing full buffer
5
6...instead of only when approaching the maximum buffer size INT/2+1.
7
8We'd like to give applications a chance to finish parsing a large token
9before buffer reallocation, in case the reallocation fails.
10
11By bypassing the reparse deferral heuristic when getting close to the
12filling the buffer, we give them this chance -- if the whole token is
13present in the buffer, it will be parsed at that time.
14
15This may come at the cost of some extra reparse attempts. For a token
16of n bytes, these extra parses cause us to scan over a maximum of
172n bytes (... + n/8 + n/4 + n/2 + n). Therefore, parsing of big tokens
18remains O(n) in regard how many bytes we scan in attempts to parse. The
19cost in reality is lower than that, since the reparses that happen due
20to the bypass will affect m_partialTokenBytesBefore, delaying the next
21ratio-based reparse. Furthermore, only the first token that "breaks
22through" a buffer ceiling takes that extra reparse attempt; subsequent
23large tokens will only bypass the heuristic if they manage to hit the
24new buffer ceiling.
25
26Note that this cost analysis depends on the assumption that Expat grows
27its buffer by doubling it (or, more generally, grows it exponentially).
28If this changes, the cost of this bypass may increase. Hopefully, this
29would be caught by test_big_tokens_take_linear_time or the new test.
30
31The bypass logic assumes that the application uses a consistent fill.
32If the app increases its fill size, it may miss the bypass (and the
33normal heuristic will apply). If the app decreases its fill size, the
34bypass may be hit multiple times for the same buffer size. The very
35worst case would be to always fill half of the remaining buffer space,
36in which case parsing of a large n-byte token becomes O(n log n).
37
38As an added bonus, the new test case should be faster than the old one,
39since it doesn't have to go all the way to 1GiB to check the behavior.
40
41Finally, this change necessitated a small modification to two existing
42tests related to reparse deferral. These tests are testing the deferral
43enabled setting, and assume that reparsing will not happen for any other
44reason. By pre-growing the buffer, we make sure that this new deferral
45does not affect those test cases.
46
47CVE: CVE-2023-52425
48
49Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/3d8141d26a3b01ff948e00956cb0723a89dadf7f]
50
51Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
52---
53 lib/xmlparse.c | 16 ++++++++--------
54 1 file changed, 8 insertions(+), 8 deletions(-)
55
56diff --git a/lib/xmlparse.c b/lib/xmlparse.c
57index 32c57f6..2830c1e 100644
58--- a/lib/xmlparse.c
59+++ b/lib/xmlparse.c
60@@ -978,18 +978,18 @@ callProcessor(XML_Parser parser, const char *start, const char *end,
61 // Heuristic: don't try to parse a partial token again until the amount of
62 // available data has increased significantly.
63 const size_t had_before = parser->m_partialTokenBytesBefore;
64- // ...but *do* try anyway if we're close to reaching the max buffer size.
65- size_t close_to_maxbuf = INT_MAX / 2 + (INT_MAX & 1); // round up
66+ // ...but *do* try anyway if we're close to causing a reallocation.
67+ size_t available_buffer
68+ = EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
69 #if XML_CONTEXT_BYTES > 0
70- // subtract XML_CONTEXT_BYTES, but don't go below zero
71- close_to_maxbuf -= EXPAT_MIN(close_to_maxbuf, XML_CONTEXT_BYTES);
72+ available_buffer -= EXPAT_MIN(available_buffer, XML_CONTEXT_BYTES);
73 #endif
74- // subtract the last buffer fill size, but don't go below zero
75+ available_buffer
76+ += EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd);
77 // m_lastBufferRequestSize is never assigned a value < 0, so the cast is ok
78- close_to_maxbuf
79- -= EXPAT_MIN(close_to_maxbuf, (size_t)parser->m_lastBufferRequestSize);
80 const bool enough
81- = (have_now >= 2 * had_before) || (have_now > close_to_maxbuf);
82+ = (have_now >= 2 * had_before)
83+ || ((size_t)parser->m_lastBufferRequestSize > available_buffer);
84
85 if (! enough) {
86 *endPtr = start; // callers may expect this to be set
87--
882.40.0
89
diff --git a/meta/recipes-core/expat/expat/CVE-2023-52425-0012.patch b/meta/recipes-core/expat/expat/CVE-2023-52425-0012.patch
deleted file mode 100644
index 8693e9449e..0000000000
--- a/meta/recipes-core/expat/expat/CVE-2023-52425-0012.patch
+++ /dev/null
@@ -1,87 +0,0 @@
1From 119ae277abaabd4d17b2e64300fec712ef403b28 Mon Sep 17 00:00:00 2001
2From: Snild Dolkow <snild@sony.com>
3Date: Thu, 28 Sep 2023 18:26:19 +0200
4Subject: [PATCH] Grow buffer based on current size Until now, the buffer size
5 to grow to has been calculated based on the distance from the current parse
6 position to the end of the buffer. This means that the size of any
7 already-parsed data was not considered, leading to inconsistent buffer
8 growth.
9
10There was also a special case in XML_Parse() when XML_CONTEXT_BYTES was
11zero, where the buffer size would be set to twice the incoming string
12length. This patch replaces this with an XML_GetBuffer() call.
13
14Growing the buffer based on its total size makes its growth consistent.
15
16The commit includes a test that checks that we can reach the max buffer
17size (usually INT_MAX/2 + 1) regardless of previously parsed content.
18
19GitHub CI couldn't allocate the full 1GiB with MinGW/wine32, though it
20works locally with the same compiler and wine version. As a workaround,
21the test tries to malloc 1GiB, and reduces `maxbuf` to 512MiB in case
22of failure.
23
24CVE: CVE-2023-52425
25
26Upstream-Status: Backport [https://github.com/libexpat/libexpat/commit/119ae277abaabd4d17b2e64300fec712ef403b28]
27
28Signed-off-by: Meenali Gupta <meenali.gupta@windriver.com>
29---
30 lib/xmlparse.c | 33 ++++++++++++++++-----------------
31 1 file changed, 16 insertions(+), 17 deletions(-)
32
33diff --git a/lib/xmlparse.c b/lib/xmlparse.c
34index 2830c1e..81f9bb3 100644
35--- a/lib/xmlparse.c
36+++ b/lib/xmlparse.c
37@@ -1961,23 +1961,22 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
38 &parser->m_position);
39 nLeftOver = s + len - end;
40 if (nLeftOver) {
41- if (parser->m_buffer == NULL
42- || nLeftOver > parser->m_bufferLim - parser->m_buffer) {
43- /* avoid _signed_ integer overflow */
44- char *temp = NULL;
45- const int bytesToAllocate = (int)((unsigned)len * 2U);
46- if (bytesToAllocate > 0) {
47- temp = (char *)REALLOC(parser, parser->m_buffer, bytesToAllocate);
48- }
49- if (temp == NULL) {
50- parser->m_errorCode = XML_ERROR_NO_MEMORY;
51- parser->m_eventPtr = parser->m_eventEndPtr = NULL;
52- parser->m_processor = errorProcessor;
53- return XML_STATUS_ERROR;
54- }
55- parser->m_buffer = temp;
56- parser->m_bufferLim = parser->m_buffer + bytesToAllocate;
57+ // Back up and restore the parsing status to avoid XML_ERROR_SUSPENDED
58+ // (and XML_ERROR_FINISHED) from XML_GetBuffer.
59+ const enum XML_Parsing originalStatus = parser->m_parsingStatus.parsing;
60+ parser->m_parsingStatus.parsing = XML_PARSING;
61+ void *const temp = XML_GetBuffer(parser, nLeftOver);
62+ parser->m_parsingStatus.parsing = originalStatus;
63+ if (temp == NULL) {
64+ // NOTE: parser->m_errorCode has already been set by XML_GetBuffer().
65+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
66+ parser->m_processor = errorProcessor;
67+ return XML_STATUS_ERROR;
68 }
69+ // Since we know that the buffer was empty and XML_CONTEXT_BYTES is 0, we
70+ // don't have any data to preserve, and can copy straight into the start
71+ // of the buffer rather than the GetBuffer return pointer (which may be
72+ // pointing further into the allocated buffer).
73 memcpy(parser->m_buffer, end, nLeftOver);
74 }
75 parser->m_bufferPtr = parser->m_buffer;
76@@ -2135,7 +2134,7 @@ XML_GetBuffer(XML_Parser parser, int len) {
77 } else {
78 char *newBuf;
79 int bufferSize
80- = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferPtr);
81+ = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer);
82 if (bufferSize == 0)
83 bufferSize = INIT_BUFFER_SIZE;
84 do {
85--
862.40.0
87
diff --git a/meta/recipes-core/expat/expat_2.5.0.bb b/meta/recipes-core/expat/expat_2.5.0.bb
index b7b5cce925..31e989cfe2 100644
--- a/meta/recipes-core/expat/expat_2.5.0.bb
+++ b/meta/recipes-core/expat/expat_2.5.0.bb
@@ -22,18 +22,6 @@ SRC_URI = "https://github.com/libexpat/libexpat/releases/download/R_${VERSION_TA
22 file://CVE-2023-52426-009.patch \ 22 file://CVE-2023-52426-009.patch \
23 file://CVE-2023-52426-010.patch \ 23 file://CVE-2023-52426-010.patch \
24 file://CVE-2023-52426-011.patch \ 24 file://CVE-2023-52426-011.patch \
25 file://CVE-2023-52425-0001.patch \
26 file://CVE-2023-52425-0002.patch \
27 file://CVE-2023-52425-0003.patch \
28 file://CVE-2023-52425-0004.patch \
29 file://CVE-2023-52425-0005.patch \
30 file://CVE-2023-52425-0006.patch \
31 file://CVE-2023-52425-0007.patch \
32 file://CVE-2023-52425-0008.patch \
33 file://CVE-2023-52425-0009.patch \
34 file://CVE-2023-52425-0010.patch \
35 file://CVE-2023-52425-0011.patch \
36 file://CVE-2023-52425-0012.patch \
37 " 25 "
38 26
39UPSTREAM_CHECK_URI = "https://github.com/libexpat/libexpat/releases/" 27UPSTREAM_CHECK_URI = "https://github.com/libexpat/libexpat/releases/"