Graphite2 - NameTable::getName Multiple Heap-Based Out-of-Bounds Reads

2016-05-26 21:05:21

Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=756

We have encountered several different crashes in the graphite2::NameTable::getName method, observed in an ASAN build of the standard Graphite2 gr2FontTest utility (git trunk), triggered with the following command:

$ ./gr2fonttest -demand -cache /path/to/file

Below are three unique ASAN reports that we have triggered.

--- cut ---
==1191==ERROR: AddressSanitizer: SEGV on unknown address 0x61b000026b15 (pc 0x000000553c81 bp 0x7ffc0e24a820 sp 0x7ffc0e24a800 T0)
#0 0x553c80 in unsigned long be::_peek<1>(unsigned char const*) graphite/src/./inc/Endian.h:77:73
#1 0x553bd3 in unsigned long be::_peek<2>(unsigned char const*) graphite/src/./inc/Endian.h:50:16
#2 0x5516cb in unsigned short be::read<unsigned short>(unsigned char const*&) graphite/src/./inc/Endian.h:60:23
#3 0x59192b in graphite2::NameTable::getName(unsigned short&, unsigned short, gr_encform, unsigned int&) graphite/src/NameTable.cpp:157:24
#4 0x572e5c in gr_fref_label graphite/src/gr_features.cpp:97:12
#5 0x4eaec8 in Parameters::printFeatures(gr_face const*) const (graphite/gr2fonttest/gr2fonttest+0x4eaec8)
#6 0x4ed32b in Parameters::testFileFont() const (graphite/gr2fonttest/gr2fonttest+0x4ed32b)
#7 0x4f06c9 in main (graphite/gr2fonttest/gr2fonttest+0x4f06c9)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV graphite/src/./inc/Endian.h:77:73 in unsigned long be::_peek<1>(unsigned char const*)
==1191==ABORTING
--- cut ---

--- cut ---
==1199==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61b00001fb95 at pc 0x000000553c7d bp 0x7ffdebef2a70 sp 0x7ffdebef2a68
READ of size 1 at 0x61b00001fb95 thread T0
#0 0x553c7c in unsigned long be::_peek<1>(unsigned char const*) graphite/src/./inc/Endian.h:77:73
#1 0x553bd3 in unsigned long be::_peek<2>(unsigned char const*) graphite/src/./inc/Endian.h:50:16
#2 0x5516cb in unsigned short be::read<unsigned short>(unsigned char const*&) graphite/src/./inc/Endian.h:60:23
#3 0x59192b in graphite2::NameTable::getName(unsigned short&, unsigned short, gr_encform, unsigned int&) graphite/src/NameTable.cpp:157:24
#4 0x572e5c in gr_fref_label graphite/src/gr_features.cpp:97:12
#5 0x4eaec8 in Parameters::printFeatures(gr_face const*) const (graphite/gr2fonttest/gr2fonttest+0x4eaec8)
#6 0x4ed32b in Parameters::testFileFont() const (graphite/gr2fonttest/gr2fonttest+0x4ed32b)
#7 0x4f06c9 in main (graphite/gr2fonttest/gr2fonttest+0x4f06c9)

AddressSanitizer can not describe address in more detail (wild memory access suspected).
SUMMARY: AddressSanitizer: heap-buffer-overflow graphite/src/./inc/Endian.h:77:73 in unsigned long be::_peek<1>(unsigned char const*)
Shadow bytes around the buggy address:
0x0c367fffbf20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c367fffbf30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c367fffbf40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c367fffbf50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c367fffbf60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c367fffbf70: fa fa[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c367fffbf80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c367fffbf90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c367fffbfa0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c367fffbfb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c367fffbfc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==1199==ABORTING
--- cut ---

--- cut ---
==1315==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60400000db3a at pc 0x00000057d59d bp 0x7ffd01d33840 sp 0x7ffd01d33838
READ of size 2 at 0x60400000db3a thread T0
#0 0x57d59c in graphite2::_utf_codec<16>::get(unsigned short const*, signed char&) graphite/src/./inc/UtfCodec.h:97:27
#1 0x57d0a7 in graphite2::_utf_iterator<unsigned short const>::reference::operator unsigned int() const graphite/src/./inc/UtfCodec.h:173:74
#2 0x591d32 in graphite2::NameTable::getName(unsigned short&, unsigned short, gr_encform, unsigned int&) graphite/src/NameTable.cpp:173:18
#3 0x572e5c in gr_fref_label graphite/src/gr_features.cpp:97:12
#4 0x4eaec8 in Parameters::printFeatures(gr_face const*) const (graphite/gr2fonttest/gr2fonttest+0x4eaec8)
#5 0x4ed32b in Parameters::testFileFont() const (graphite/gr2fonttest/gr2fonttest+0x4ed32b)
#6 0x4f06c9 in main (graphite/gr2fonttest/gr2fonttest+0x4f06c9)

0x60400000db3a is located 0 bytes to the right of 42-byte region [0x60400000db10,0x60400000db3a)
allocated by thread T0 here:
#0 0x4b85b8 in malloc llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:40
#1 0x55a24a in unsigned short* graphite2::gralloc<unsigned short>(unsigned long) graphite/src/./inc/Main.h:88:28
#2 0x5916ef in graphite2::NameTable::getName(unsigned short&, unsigned short, gr_encform, unsigned int&) graphite/src/NameTable.cpp:147:37
#3 0x572e5c in gr_fref_label graphite/src/gr_features.cpp:97:12
#4 0x4eaec8 in Parameters::printFeatures(gr_face const*) const (graphite/gr2fonttest/gr2fonttest+0x4eaec8)
#5 0x4ed32b in Parameters::testFileFont() const (graphite/gr2fonttest/gr2fonttest+0x4ed32b)
#6 0x4f06c9 in main (graphite/gr2fonttest/gr2fonttest+0x4f06c9)

SUMMARY: AddressSanitizer: heap-buffer-overflow graphite/src/./inc/UtfCodec.h:97:27 in graphite2::_utf_codec<16>::get(unsigned short const*, signed char&)
Shadow bytes around the buggy address:
0x0c087fff9b10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9b20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9b30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9b40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c087fff9b50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c087fff9b60: fa fa 00 00 00 00 00[02]fa fa fd fd fd fd fd fd
0x0c087fff9b70: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fd
0x0c087fff9b80: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 00 00
0x0c087fff9b90: fa fa 00 00 00 00 00 fa fa fa fd fd fd fd fd fa
0x0c087fff9ba0: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fa
0x0c087fff9bb0: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==1315==ABORTING
--- cut ---

The bug was reported at https://bugzilla.mozilla.org/show_bug.cgi?id=1254497. Attached are three font files which reproduce the crashes.


Proof of Concept:
https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/sploits/39863.zip

Fixes

No fixes

In order to submit a new fix you need to be registered.