1 |
commit: 3d3cad32d1310cafeeed46b374ef3120c0195ff7 |
2 |
Author: Andreas Sturmlechner <asturm <AT> gentoo <DOT> org> |
3 |
AuthorDate: Wed May 18 10:54:00 2022 +0000 |
4 |
Commit: Andreas Sturmlechner <asturm <AT> gentoo <DOT> org> |
5 |
CommitDate: Wed May 18 11:12:53 2022 +0000 |
6 |
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=3d3cad32 |
7 |
|
8 |
dev-libs/icu: Fix CVE-2022-1638 |
9 |
|
10 |
Bug: https://bugs.gentoo.org/843731 |
11 |
Package-Manager: Portage-3.0.30, Repoman-3.0.3 |
12 |
Signed-off-by: Andreas Sturmlechner <asturm <AT> gentoo.org> |
13 |
|
14 |
dev-libs/icu/files/icu-71.1-CVE-2022-1638.patch | 202 ++++++++++++++++++++++++ |
15 |
dev-libs/icu/icu-71.1-r1.ebuild | 154 ++++++++++++++++++ |
16 |
2 files changed, 356 insertions(+) |
17 |
|
18 |
diff --git a/dev-libs/icu/files/icu-71.1-CVE-2022-1638.patch b/dev-libs/icu/files/icu-71.1-CVE-2022-1638.patch |
19 |
new file mode 100644 |
20 |
index 000000000000..216ed7894473 |
21 |
--- /dev/null |
22 |
+++ b/dev-libs/icu/files/icu-71.1-CVE-2022-1638.patch |
23 |
@@ -0,0 +1,202 @@ |
24 |
+From e96e9410bde06962c211fa6f21c3d91263a90f86 Mon Sep 17 00:00:00 2001 |
25 |
+From: Frank Tang <ftang@××××××××.org> |
26 |
+Date: Fri, 29 Apr 2022 22:50:33 +0000 |
27 |
+Subject: [PATCH] ICU-22005 Fix int32 overflow in FormattedStringBuilder |
28 |
+ |
29 |
+See #2070 |
30 |
+--- |
31 |
+ .../i18n/formatted_string_builder.cpp | 55 +++++++++++++------ |
32 |
+ .../formatted_string_builder_test.cpp | 41 ++++++++++++++ |
33 |
+ 2 files changed, 79 insertions(+), 17 deletions(-) |
34 |
+ |
35 |
+diff --git a/i18n/formatted_string_builder.cpp b/i18n/formatted_string_builder.cpp |
36 |
+index 734078644b8..628fbea8711 100644 |
37 |
+--- a/i18n/formatted_string_builder.cpp |
38 |
++++ b/i18n/formatted_string_builder.cpp |
39 |
+@@ -6,6 +6,7 @@ |
40 |
+ #if !UCONFIG_NO_FORMATTING |
41 |
+ |
42 |
+ #include "formatted_string_builder.h" |
43 |
++#include "putilimp.h" |
44 |
+ #include "unicode/ustring.h" |
45 |
+ #include "unicode/utf16.h" |
46 |
+ #include "unicode/unum.h" // for UNumberFormatFields literals |
47 |
+@@ -197,6 +198,9 @@ FormattedStringBuilder::splice(int32_t startThis, int32_t endThis, const Unicod |
48 |
+ int32_t thisLength = endThis - startThis; |
49 |
+ int32_t otherLength = endOther - startOther; |
50 |
+ int32_t count = otherLength - thisLength; |
51 |
++ if (U_FAILURE(status)) { |
52 |
++ return count; |
53 |
++ } |
54 |
+ int32_t position; |
55 |
+ if (count > 0) { |
56 |
+ // Overall, chars need to be added. |
57 |
+@@ -221,6 +225,9 @@ int32_t FormattedStringBuilder::append(const FormattedStringBuilder &other, UErr |
58 |
+ |
59 |
+ int32_t |
60 |
+ FormattedStringBuilder::insert(int32_t index, const FormattedStringBuilder &other, UErrorCode &status) { |
61 |
++ if (U_FAILURE(status)) { |
62 |
++ return 0; |
63 |
++ } |
64 |
+ if (this == &other) { |
65 |
+ status = U_ILLEGAL_ARGUMENT_ERROR; |
66 |
+ return 0; |
67 |
+@@ -255,12 +262,18 @@ int32_t FormattedStringBuilder::prepareForInsert(int32_t index, int32_t count, U |
68 |
+ U_ASSERT(index >= 0); |
69 |
+ U_ASSERT(index <= fLength); |
70 |
+ U_ASSERT(count >= 0); |
71 |
++ U_ASSERT(fZero >= 0); |
72 |
++ U_ASSERT(fLength >= 0); |
73 |
++ U_ASSERT(getCapacity() - fZero >= fLength); |
74 |
++ if (U_FAILURE(status)) { |
75 |
++ return count; |
76 |
++ } |
77 |
+ if (index == 0 && fZero - count >= 0) { |
78 |
+ // Append to start |
79 |
+ fZero -= count; |
80 |
+ fLength += count; |
81 |
+ return fZero; |
82 |
+- } else if (index == fLength && fZero + fLength + count < getCapacity()) { |
83 |
++ } else if (index == fLength && count <= getCapacity() - fZero - fLength) { |
84 |
+ // Append to end |
85 |
+ fLength += count; |
86 |
+ return fZero + fLength - count; |
87 |
+@@ -275,18 +288,26 @@ int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t co |
88 |
+ int32_t oldZero = fZero; |
89 |
+ char16_t *oldChars = getCharPtr(); |
90 |
+ Field *oldFields = getFieldPtr(); |
91 |
+- if (fLength + count > oldCapacity) { |
92 |
+- if ((fLength + count) > INT32_MAX / 2) { |
93 |
+- // If we continue, then newCapacity will overflow int32_t in the next line. |
94 |
++ int32_t newLength; |
95 |
++ if (uprv_add32_overflow(fLength, count, &newLength)) { |
96 |
++ status = U_INPUT_TOO_LONG_ERROR; |
97 |
++ return -1; |
98 |
++ } |
99 |
++ int32_t newZero; |
100 |
++ if (newLength > oldCapacity) { |
101 |
++ if (newLength > INT32_MAX / 2) { |
102 |
++ // We do not support more than 1G char16_t in this code because |
103 |
++ // dealing with >2G *bytes* can cause subtle bugs. |
104 |
+ status = U_INPUT_TOO_LONG_ERROR; |
105 |
+ return -1; |
106 |
+ } |
107 |
+- int32_t newCapacity = (fLength + count) * 2; |
108 |
+- int32_t newZero = newCapacity / 2 - (fLength + count) / 2; |
109 |
++ // Keep newCapacity also to at most 1G char16_t. |
110 |
++ int32_t newCapacity = newLength * 2; |
111 |
++ newZero = (newCapacity - newLength) / 2; |
112 |
+ |
113 |
+ // C++ note: malloc appears in two places: here and in the assignment operator. |
114 |
+- auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * newCapacity)); |
115 |
+- auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * newCapacity)); |
116 |
++ auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * static_cast<size_t>(newCapacity))); |
117 |
++ auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * static_cast<size_t>(newCapacity))); |
118 |
+ if (newChars == nullptr || newFields == nullptr) { |
119 |
+ uprv_free(newChars); |
120 |
+ uprv_free(newFields); |
121 |
+@@ -315,10 +336,8 @@ int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t co |
122 |
+ fChars.heap.capacity = newCapacity; |
123 |
+ fFields.heap.ptr = newFields; |
124 |
+ fFields.heap.capacity = newCapacity; |
125 |
+- fZero = newZero; |
126 |
+- fLength += count; |
127 |
+ } else { |
128 |
+- int32_t newZero = oldCapacity / 2 - (fLength + count) / 2; |
129 |
++ newZero = (oldCapacity - newLength) / 2; |
130 |
+ |
131 |
+ // C++ note: memmove is required because src and dest may overlap. |
132 |
+ // First copy the entire string to the location of the prefix, and then move the suffix |
133 |
+@@ -331,18 +350,20 @@ int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t co |
134 |
+ uprv_memmove2(oldFields + newZero + index + count, |
135 |
+ oldFields + newZero + index, |
136 |
+ sizeof(Field) * (fLength - index)); |
137 |
+- |
138 |
+- fZero = newZero; |
139 |
+- fLength += count; |
140 |
+ } |
141 |
+- U_ASSERT((fZero + index) >= 0); |
142 |
++ fZero = newZero; |
143 |
++ fLength = newLength; |
144 |
+ return fZero + index; |
145 |
+ } |
146 |
+ |
147 |
+ int32_t FormattedStringBuilder::remove(int32_t index, int32_t count) { |
148 |
+- // TODO: Reset the heap here? (If the string after removal can fit on stack?) |
149 |
++ U_ASSERT(0 <= index); |
150 |
++ U_ASSERT(index <= fLength); |
151 |
++ U_ASSERT(count <= (fLength - index)); |
152 |
++ U_ASSERT(index <= getCapacity() - fZero); |
153 |
++ |
154 |
+ int32_t position = index + fZero; |
155 |
+- U_ASSERT(position >= 0); |
156 |
++ // TODO: Reset the heap here? (If the string after removal can fit on stack?) |
157 |
+ uprv_memmove2(getCharPtr() + position, |
158 |
+ getCharPtr() + position + count, |
159 |
+ sizeof(char16_t) * (fLength - index - count)); |
160 |
+diff --git a/test/intltest/formatted_string_builder_test.cpp b/test/intltest/formatted_string_builder_test.cpp |
161 |
+index 45721a320ac..57294e24856 100644 |
162 |
+--- a/test/intltest/formatted_string_builder_test.cpp |
163 |
++++ b/test/intltest/formatted_string_builder_test.cpp |
164 |
+@@ -22,6 +22,7 @@ class FormattedStringBuilderTest : public IntlTest { |
165 |
+ void testFields(); |
166 |
+ void testUnlimitedCapacity(); |
167 |
+ void testCodePoints(); |
168 |
++ void testInsertOverflow(); |
169 |
+ |
170 |
+ void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0) override; |
171 |
+ |
172 |
+@@ -50,6 +51,7 @@ void FormattedStringBuilderTest::runIndexedTest(int32_t index, UBool exec, const |
173 |
+ TESTCASE_AUTO(testFields); |
174 |
+ TESTCASE_AUTO(testUnlimitedCapacity); |
175 |
+ TESTCASE_AUTO(testCodePoints); |
176 |
++ TESTCASE_AUTO(testInsertOverflow); |
177 |
+ TESTCASE_AUTO_END; |
178 |
+ } |
179 |
+ |
180 |
+@@ -308,6 +310,45 @@ void FormattedStringBuilderTest::testCodePoints() { |
181 |
+ assertEquals("Code point count is 2", 2, nsb.codePointCount()); |
182 |
+ } |
183 |
+ |
184 |
++void FormattedStringBuilderTest::testInsertOverflow() { |
185 |
++ if (quick) return; |
186 |
++ // Setup the test fixture in sb, sb2, ustr. |
187 |
++ UErrorCode status = U_ZERO_ERROR; |
188 |
++ FormattedStringBuilder sb; |
189 |
++ int32_t data_length = INT32_MAX / 2; |
190 |
++ UnicodeString ustr(data_length, u'a', data_length); |
191 |
++ sb.append(ustr, kUndefinedField, status); |
192 |
++ assertSuccess("Setup the first FormattedStringBuilder", status); |
193 |
++ |
194 |
++ FormattedStringBuilder sb2; |
195 |
++ sb2.append(ustr, kUndefinedField, status); |
196 |
++ sb2.insert(0, ustr, 0, data_length / 2, kUndefinedField, status); |
197 |
++ sb2.writeTerminator(status); |
198 |
++ assertSuccess("Setup the second FormattedStringBuilder", status); |
199 |
++ |
200 |
++ ustr = sb2.toUnicodeString(); |
201 |
++ // Complete setting up the test fixture in sb, sb2 and ustr. |
202 |
++ |
203 |
++ // Test splice() of the second UnicodeString |
204 |
++ sb.splice(0, 1, ustr, 1, ustr.length(), |
205 |
++ kUndefinedField, status); |
206 |
++ assertEquals( |
207 |
++ "splice() long text should not crash but return U_INPUT_TOO_LONG_ERROR", |
208 |
++ U_INPUT_TOO_LONG_ERROR, status); |
209 |
++ |
210 |
++ // Test sb.insert() of the first FormattedStringBuilder with the second one. |
211 |
++ sb.insert(0, sb2, status); |
212 |
++ assertEquals( |
213 |
++ "insert() long FormattedStringBuilder should not crash but return " |
214 |
++ "U_INPUT_TOO_LONG_ERROR", U_INPUT_TOO_LONG_ERROR, status); |
215 |
++ |
216 |
++ // Test sb.insert() of the first FormattedStringBuilder with UnicodeString. |
217 |
++ sb.insert(0, ustr, 0, ustr.length(), kUndefinedField, status); |
218 |
++ assertEquals( |
219 |
++ "insert() long UnicodeString should not crash but return " |
220 |
++ "U_INPUT_TOO_LONG_ERROR", U_INPUT_TOO_LONG_ERROR, status); |
221 |
++} |
222 |
++ |
223 |
+ void FormattedStringBuilderTest::assertEqualsImpl(const UnicodeString &a, const FormattedStringBuilder &b) { |
224 |
+ // TODO: Why won't this compile without the IntlTest:: qualifier? |
225 |
+ IntlTest::assertEquals("Lengths should be the same", a.length(), b.length()); |
226 |
|
227 |
diff --git a/dev-libs/icu/icu-71.1-r1.ebuild b/dev-libs/icu/icu-71.1-r1.ebuild |
228 |
new file mode 100644 |
229 |
index 000000000000..584c243c2e41 |
230 |
--- /dev/null |
231 |
+++ b/dev-libs/icu/icu-71.1-r1.ebuild |
232 |
@@ -0,0 +1,154 @@ |
233 |
+# Copyright 1999-2022 Gentoo Authors |
234 |
+# Distributed under the terms of the GNU General Public License v2 |
235 |
+ |
236 |
+EAPI=8 |
237 |
+ |
238 |
+# Please bump with dev-libs/icu-layoutex |
239 |
+ |
240 |
+PYTHON_COMPAT=( python3_{8..10} ) |
241 |
+VERIFY_SIG_OPENPGP_KEY_PATH="${BROOT}"/usr/share/openpgp-keys/icu.asc |
242 |
+inherit autotools flag-o-matic multilib-minimal python-any-r1 toolchain-funcs verify-sig |
243 |
+ |
244 |
+DESCRIPTION="International Components for Unicode" |
245 |
+HOMEPAGE="https://icu.unicode.org/" |
246 |
+SRC_URI="https://github.com/unicode-org/icu/releases/download/release-${PV//./-}/icu4c-${PV//./_}-src.tgz" |
247 |
+SRC_URI+=" verify-sig? ( https://github.com/unicode-org/icu/releases/download/release-${PV//./-}/icu4c-${PV//./_}-src.tgz.asc )" |
248 |
+S="${WORKDIR}/${PN}/source" |
249 |
+ |
250 |
+LICENSE="BSD" |
251 |
+SLOT="0/${PV}" |
252 |
+KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~loong ~m68k ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86 ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris ~x86-winnt" |
253 |
+IUSE="debug doc examples static-libs test" |
254 |
+RESTRICT="!test? ( test )" |
255 |
+ |
256 |
+BDEPEND="${PYTHON_DEPS} |
257 |
+ sys-devel/autoconf-archive |
258 |
+ virtual/pkgconfig |
259 |
+ doc? ( app-doc/doxygen[dot] ) |
260 |
+ verify-sig? ( sec-keys/openpgp-keys-icu ) |
261 |
+" |
262 |
+ |
263 |
+MULTILIB_CHOST_TOOLS=( |
264 |
+ /usr/bin/icu-config |
265 |
+) |
266 |
+ |
267 |
+PATCHES=( |
268 |
+ "${FILESDIR}/${PN}-65.1-remove-bashisms.patch" |
269 |
+ "${FILESDIR}/${PN}-64.2-darwin.patch" |
270 |
+ "${FILESDIR}/${PN}-68.1-nonunicode.patch" |
271 |
+ "${FILESDIR}/${P}-CVE-2022-1638.patch" # bug 843731 |
272 |
+) |
273 |
+ |
274 |
+src_prepare() { |
275 |
+ default |
276 |
+ |
277 |
+ # Disable renaming as it assumes stable ABI and that consumers |
278 |
+ # won't use unofficial APIs. We need this despite the configure argument. |
279 |
+ sed -i \ |
280 |
+ -e "s/#define U_DISABLE_RENAMING 0/#define U_DISABLE_RENAMING 1/" \ |
281 |
+ common/unicode/uconfig.h || die |
282 |
+ |
283 |
+ # Fix linking of icudata |
284 |
+ sed -i \ |
285 |
+ -e "s:LDFLAGSICUDT=-nodefaultlibs -nostdlib:LDFLAGSICUDT=:" \ |
286 |
+ config/mh-linux || die |
287 |
+ |
288 |
+ # Append doxygen configuration to configure |
289 |
+ sed -i \ |
290 |
+ -e 's:icudefs.mk:icudefs.mk Doxyfile:' \ |
291 |
+ configure.ac || die |
292 |
+ |
293 |
+ eautoreconf |
294 |
+} |
295 |
+ |
296 |
+src_configure() { |
297 |
+ # ICU tries to append -std=c++11 without this, so as of 71.1, |
298 |
+ # despite GCC 9+ using c++14 (or gnu++14) and GCC 11+ using gnu++17, |
299 |
+ # we still need this. |
300 |
+ append-cxxflags -std=c++14 |
301 |
+ |
302 |
+ if tc-is-cross-compiler; then |
303 |
+ mkdir "${WORKDIR}"/host || die |
304 |
+ pushd "${WORKDIR}"/host >/dev/null || die |
305 |
+ |
306 |
+ CFLAGS="" CXXFLAGS="" ASFLAGS="" LDFLAGS="" \ |
307 |
+ CC="$(tc-getBUILD_CC)" CXX="$(tc-getBUILD_CXX)" AR="$(tc-getBUILD_AR)" \ |
308 |
+ RANLIB="$(tc-getBUILD_RANLIB)" LD="$(tc-getBUILD_LD)" \ |
309 |
+ "${S}"/configure --disable-renaming --disable-debug \ |
310 |
+ --disable-samples --enable-static || die |
311 |
+ emake |
312 |
+ |
313 |
+ popd >/dev/null || die |
314 |
+ fi |
315 |
+ |
316 |
+ multilib-minimal_src_configure |
317 |
+} |
318 |
+ |
319 |
+multilib_src_configure() { |
320 |
+ local myeconfargs=( |
321 |
+ --disable-renaming |
322 |
+ --disable-samples |
323 |
+ --disable-layoutex |
324 |
+ $(use_enable debug) |
325 |
+ $(use_enable static-libs static) |
326 |
+ $(use_enable test tests) |
327 |
+ $(multilib_native_use_enable examples samples) |
328 |
+ ) |
329 |
+ |
330 |
+ tc-is-cross-compiler && myeconfargs+=( |
331 |
+ --with-cross-build="${WORKDIR}"/host |
332 |
+ ) |
333 |
+ |
334 |
+ # Work around cross-endian testing failures with LTO #757681 |
335 |
+ if tc-is-cross-compiler && is-flagq '-flto*' ; then |
336 |
+ myeconfargs+=( --disable-strict ) |
337 |
+ fi |
338 |
+ |
339 |
+ # ICU tries to use clang by default |
340 |
+ tc-export CC CXX |
341 |
+ |
342 |
+ # Make sure we configure with the same shell as we run icu-config |
343 |
+ # with, or ECHO_N, ECHO_T and ECHO_C will be wrongly defined |
344 |
+ export CONFIG_SHELL="${EPREFIX}/bin/sh" |
345 |
+ # Probably have no /bin/sh in prefix-chain |
346 |
+ [[ -x ${CONFIG_SHELL} ]] || CONFIG_SHELL="${BASH}" |
347 |
+ |
348 |
+ ECONF_SOURCE="${S}" econf "${myeconfargs[@]}" |
349 |
+} |
350 |
+ |
351 |
+multilib_src_compile() { |
352 |
+ default |
353 |
+ |
354 |
+ if multilib_is_native_abi && use doc; then |
355 |
+ doxygen -u Doxyfile || die |
356 |
+ doxygen Doxyfile || die |
357 |
+ fi |
358 |
+} |
359 |
+ |
360 |
+multilib_src_test() { |
361 |
+ # INTLTEST_OPTS: intltest options |
362 |
+ # -e: Exhaustive testing |
363 |
+ # -l: Reporting of memory leaks |
364 |
+ # -v: Increased verbosity |
365 |
+ # IOTEST_OPTS: iotest options |
366 |
+ # -e: Exhaustive testing |
367 |
+ # -v: Increased verbosity |
368 |
+ # CINTLTST_OPTS: cintltst options |
369 |
+ # -e: Exhaustive testing |
370 |
+ # -v: Increased verbosity |
371 |
+ emake -j1 VERBOSE="1" check |
372 |
+} |
373 |
+ |
374 |
+multilib_src_install() { |
375 |
+ default |
376 |
+ |
377 |
+ if multilib_is_native_abi && use doc; then |
378 |
+ docinto html |
379 |
+ dodoc -r doc/html/* |
380 |
+ fi |
381 |
+} |
382 |
+ |
383 |
+multilib_src_install_all() { |
384 |
+ local HTML_DOCS=( ../readme.html ) |
385 |
+ einstalldocs |
386 |
+} |