We're updating the issue view to help you get more done. 

buffer underflow in u_charFromName

Description

It looks like u_charFromName() (unames.cpp) may be vulnerable to a buffer underflow when nameChoice == U_EXTENDED_CHAR_NAME. This function contains the code:

1 2 3 4 5 6 7 8 for (--i; lower[i] && lower[i] != '-'; --i) { } if (lower[i] == '-') { /* We've got a category. */ uint32_t cIdx; lower[i] = 0; …

Because the ‘lower’ buffer is not prefixed with a null byte, the for loop may read past the beginning of the ‘lower’ buffer on a 32 bit build. It appears that if the code in question encounters a ‘-‘ character preceding the ‘lower’ buffer, it may write a null byte at that position and then return a value based upon characters subsequent to that position (but still preceding the ‘lower’ buffer). Thus, depending on the stack layout some types of stack corruption and/or sniffing of stack memory may theoretically be possible on a 32 bit build. On a 64 bit build memory sniffing and corruption may also be theoretically possible, at a very large fixed address offset from 'buffer'.

One code path though this function with nameChoice == U_EXTENDED_CHAR_NAME comes from NameUnicodeTransliterator::handleTransliterate(). I was able to trigger a crash by modifying an existing unit test:

1 2 3 4 5 6 7 8 9 10 11 12 13 diff --git a/source/test/intltest/transtst.cpp b/source/test/intltest/transtst.cpp index c6e7b41..7107332 100644 --- a/source/test/intltest/transtst.cpp +++ b/source/test/intltest/transtst.cpp @@ -1277,7 +1277,7 @@ void TransliteratorTest::TestNameMap(void) { // Careful: CharsToUS will convert "\\N" => "N"; use "\\\\N" for \N expect(*uni2name, CharsToUnicodeString("\\u00A0abc\\u4E01\\u00B5\\u0A81\\uFFFD\\u0004\\u0009\\u0081\\uFFFF"), CharsToUnicodeString("\\\\N{NO-BREAK SPACE}abc\\\\N{CJK UNIFIED IDEOGRAPH-4E01}\\\\N{MICRO SIGN}\\\\N{GUJARATI SIGN CANDRABINDU}\\\\N{REPLACEMENT CHARACTER}\\\\N{<control-0004>}\\\\N{<control-0009>}\\\\N{<control-0081>}\\\\N{<noncharacter-FFFF>}")); - expect(*name2uni, UNICODE_STRING_SIMPLE("{\\N { NO-BREAK SPACE}abc\\N{ CJK UNIFIED IDEOGRAPH-4E01 }\\N{x\\N{MICRO SIGN}\\N{GUJARATI SIGN CANDRABINDU}\\N{REPLACEMENT CHARACTER}\\N{<control-0004>}\\N{<control-0009>}\\N{<control-0081>}\\N{<noncharacter-FFFF>}\\N{<control-0004>}\\N{"), + expect(*name2uni, UNICODE_STRING_SIMPLE("{\\N { <NO BREAK SPACE>}abc\\N{ CJK UNIFIED IDEOGRAPH-4E01 }\\N{x\\N{MICRO SIGN}\\N{GUJARATI SIGN CANDRABINDU}\\N{REPLACEMENT CHARACTER}\\N{<control-0004>}\\N{<control-0009>}\\N{<control-0081>}\\N{<noncharacter-FFFF>}\\N{<control-0004>}\\N{"), CharsToUnicodeString("{\\u00A0abc\\u4E01\\\\N{x\\u00B5\\u0A81\\uFFFD\\u0004\\u0009\\u0081\\uFFFF\\u0004\\\\N{")); delete uni2name;

This is the (crashing) output when I ran ‘make check’ from the test/intltest/ directory (on osx):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 DYLD_LIBRARY_PATH=../../lib:../../stubdata:../../tools/ctestfw:$DYLD_LIBRARY_PATH ./intltest ----------------------------------------------- IntlTest (C++) Test Suite for International Components for Unicode 53.1 Bits: 64, Byte order: Little endian, Chars: ASCII … TestFilterIDs { } OK: TestFilterIDs TestCaseMap { } OK: TestCaseMap TestNameMap { make: *** [check-local] Illegal instruction: 4

Environment

Status

Assignee

Markus Scherer

Reporter

TracBot

Time Needed

Hours

tracCc

pedberg

tracCreated

May 07, 2014, 10:30 PM

tracOwner

markus

tracProject

ICU4C

tracReporter

aaron.staple@f74d39fa044aa309

tracResolution

fixed

tracReviewer

pedberg

tracStatus

closed

tracWeeks

0.1

Components

Fix versions

Priority

major