MessageFormat::getFormats misallocates memory and lead to write past allocated buffer

Description

When MessageFormat::getFormats allocates memory, this code is used:

t->formatAliasesCapacity = (argTypeCount<10) ? 10 : argTypeCount;
Format** a = (Format**)
uprv_malloc(sizeof(Format*) * formatAliasesCapacity);

As we see, the memory allocated is based on argTypeCount, or 10 if it's less then 10. But argTypeCount seems to be not the number of actual formats in the pattern but the number of format types. So, in pattern like:

"{1}{2}{3}{1}{2}{3}{1}{2}{3}{1}{2}{3}"

argTypeCount will be 4. However, when running getFormats, it will actually try to fill out 12 elements, as there are 12 actual format arguments in the pattern. Thus, it will overwrite allocated buffer on the 11th element. This can be easily seen in the attached example file under valgrind, where it produces:

==83216== Invalid write of size 8
==83216== at 0x12E35: icu_56::MessageFormat::getFormats(int&) const (in /Users/smalyshev/brew/Cellar/icu4c/56.1/lib/libicui18n.56.1.dylib)
==83216== by 0x100000D4E: main (icu_getformats.cpp:29)
==83216== Address 0x100017180 is 0 bytes after a block of size 80 alloc'd
==83216== at 0x66AB: malloc (in /Users/smalyshev/brew/Cellar/valgrind/3.10.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==83216== by 0x12DFB: icu_56::MessageFormat::getFormats(int&) const (in /Users/smalyshev/brew/Cellar/icu4c/56.1/lib/libicui18n.56.1.dylib)
==83216== by 0x100000D4E: main (icu_getformats.cpp:29)

As we can see, allocated memory is 8*10 but the code tries to write more (actually, the returned count is 42 for the example).
This may lead to serious problems - and in applications allowing external formats controlled by others, may lead to security issues.

Status

Assignee

Nebojša Ćirić

Reporter

TracBot

Labels

Reviewer

None

Time Needed

Hours

Start date

None

Components

Fix versions

Priority

medium