From 56b28bd292f873cf3f40714ad721d341d8bbb6df Mon Sep 17 00:00:00 2001 From: Markus Scherer Date: Wed, 4 May 2011 05:50:20 +0000 Subject: [PATCH] ICU-7848 make normalize-append restore the middle string section (the relevant suffix of the first string) when something goes wrong (especially C buffer overflow) X-SVN-Rev: 30014 --- icu4c/source/common/normalizer2.cpp | 49 +++++++++++++++++++------ icu4c/source/common/normalizer2impl.cpp | 37 ++++++++++++++----- icu4c/source/common/normalizer2impl.h | 6 +++ icu4c/source/test/cintltst/cnormtst.c | 42 ++++++++++++++++++++- 4 files changed, 112 insertions(+), 22 deletions(-) diff --git a/icu4c/source/common/normalizer2.cpp b/icu4c/source/common/normalizer2.cpp index fd0048c568..8c5fdb61d9 100644 --- a/icu4c/source/common/normalizer2.cpp +++ b/icu4c/source/common/normalizer2.cpp @@ -1,7 +1,7 @@ /* ******************************************************************************* * -* Copyright (C) 2009-2010, International Business Machines +* Copyright (C) 2009-2011, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* @@ -154,15 +154,24 @@ public: errorCode=U_ILLEGAL_ARGUMENT_ERROR; return first; } - ReorderingBuffer buffer(impl, first); - if(buffer.init(first.length()+second.length(), errorCode)) { - normalizeAndAppend(secondArray, secondArray+second.length(), doNormalize, - buffer, errorCode); + int32_t firstLength=first.length(); + UnicodeString safeMiddle; + { + ReorderingBuffer buffer(impl, first); + if(buffer.init(firstLength+second.length(), errorCode)) { + normalizeAndAppend(secondArray, secondArray+second.length(), doNormalize, + safeMiddle, buffer, errorCode); + } + } // The ReorderingBuffer destructor finalizes the first string. + if(U_FAILURE(errorCode)) { + // Restore the modified suffix of the first string. + first.replace(firstLength-safeMiddle.length(), 0x7fffffff, safeMiddle); } return first; } virtual void normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize, + UnicodeString &safeMiddle, ReorderingBuffer &buffer, UErrorCode &errorCode) const = 0; virtual UBool getDecomposition(UChar32 c, UnicodeString &decomposition) const { @@ -233,8 +242,9 @@ private: using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function. virtual void normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize, + UnicodeString &safeMiddle, ReorderingBuffer &buffer, UErrorCode &errorCode) const { - impl.decomposeAndAppend(src, limit, doNormalize, buffer, errorCode); + impl.decomposeAndAppend(src, limit, doNormalize, safeMiddle, buffer, errorCode); } virtual const UChar * spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const { @@ -263,8 +273,9 @@ private: using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function. virtual void normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize, + UnicodeString &safeMiddle, ReorderingBuffer &buffer, UErrorCode &errorCode) const { - impl.composeAndAppend(src, limit, doNormalize, onlyContiguous, buffer, errorCode); + impl.composeAndAppend(src, limit, doNormalize, onlyContiguous, safeMiddle, buffer, errorCode); } virtual UBool @@ -332,8 +343,9 @@ private: using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function. virtual void normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize, + UnicodeString &safeMiddle, ReorderingBuffer &buffer, UErrorCode &errorCode) const { - impl.makeFCDAndAppend(src, limit, doNormalize, buffer, errorCode); + impl.makeFCDAndAppend(src, limit, doNormalize, safeMiddle, buffer, errorCode); } virtual const UChar * spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const { @@ -693,16 +705,29 @@ normalizeSecondAndAppend(const UNormalizer2 *norm2, return 0; } UnicodeString firstString(first, firstLength, firstCapacity); + firstLength=firstString.length(); // In case it was -1. // secondLength==0: Nothing to do, and n2wi->normalizeAndAppend(NULL, NULL, buffer, ...) would crash. if(secondLength!=0) { const Normalizer2 *n2=(const Normalizer2 *)norm2; const Normalizer2WithImpl *n2wi=dynamic_cast(n2); if(n2wi!=NULL) { // Avoid duplicate argument checking and support NUL-terminated src. - ReorderingBuffer buffer(n2wi->impl, firstString); - if(buffer.init(firstLength+secondLength+1, *pErrorCode)) { // destCapacity>=-1 - n2wi->normalizeAndAppend(second, secondLength>=0 ? second+secondLength : NULL, - doNormalize, buffer, *pErrorCode); + UnicodeString safeMiddle; + { + ReorderingBuffer buffer(n2wi->impl, firstString); + if(buffer.init(firstLength+secondLength+1, *pErrorCode)) { // destCapacity>=-1 + n2wi->normalizeAndAppend(second, secondLength>=0 ? second+secondLength : NULL, + doNormalize, safeMiddle, buffer, *pErrorCode); + } + } // The ReorderingBuffer destructor finalizes firstString. + if(U_FAILURE(*pErrorCode) || firstString.length()>firstCapacity) { + // Restore the modified suffix of the first string. + // This does not restore first[] array contents between firstLength and firstCapacity. + // (That might be uninitialized memory, as far as we know.) + safeMiddle.extract(0, 0x7fffffff, first+firstLength-safeMiddle.length()); + if(firstLength + * still fits into a[] but the full result still overflows this capacity. + * (Let it modify the destination buffer before reallocating internally.) + */ + length=unorm2_append(n2, a, -1, 6, b, -1, &errorCode); + if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=LENGTHOF(expected)) { + log_err("unorm2_append(preflight) returned wrong length of %d\n", (int)length); + return; + } + /* Verify that the middle is unchanged or restored. (ICU ticket #7848) */ + if(a[0]!=0x61 || a[1]!=0x62 || a[2]!=0x63 || a[3]!=0x41 || a[4]!=0x327 || a[5]!=0) { + log_err("unorm2_append(overflow) modified the first string\n"); + return; + } + errorCode=U_ZERO_ERROR; + length=unorm2_append(n2, a, -1, LENGTHOF(a), b, -1, &errorCode); + if(U_FAILURE(errorCode) || length!=LENGTHOF(expected) || 0!=u_memcmp(a, expected, length)) { + log_err("unorm2_append(real) failed - %s, length %d\n", u_errorName(errorCode), (int)length); + return; + } +} + #endif /* #if !UCONFIG_NO_NORMALIZATION */