Gentoo Archives: gentoo-commits

From: Andreas Sturmlechner <asturm@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] repo/gentoo:master commit in: dev-libs/icu/, dev-libs/icu/files/
Date: Wed, 18 May 2022 11:13:10
Message-Id: 1652872373.3d3cad32d1310cafeeed46b374ef3120c0195ff7.asturm@gentoo
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 +}