1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=751 The following crashes due to two different heap-based buffer overreads can be observed in an ASAN build of the standard Graphite2 gr2FontTest utility (git trunk), triggered with the following command: $ ./gr2fonttest /path/to/file -auto While we have seen the crashes to occur with six unique call stacks, eventually the OOB reads happen at two code locations: graphite2::GlyphCache::Loader::Loader (graphite/src/GlyphCache.cpp:306:38) and graphite2::GlyphCache::Loader::read_glyph (graphite/src/GlyphCache.cpp:398:27). Below you can see the ASAN reports of crashes in both functions: --- cut --- ================================================================= ==26347==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60c00000bf40 at pc 0x00000055445d bp 0x7ffe231e8130 sp 0x7ffe231e8128 READ of size 1 at 0x60c00000bf40 thread T0 #0 0x55445c in unsigned long be::_peek<1>(unsigned char const*) graphite/src/./inc/Endian.h:77:73 #1 0x5543c8 in unsigned long be::_peek<2>(unsigned char const*) graphite/src/./inc/Endian.h:50:43 #2 0x551eab in unsigned short be::read<unsigned short>(unsigned char const*&) graphite/src/./inc/Endian.h:60:23 #3 0x562a66 in graphite2::GlyphCache::Loader::read_glyph(unsigned short, graphite2::GlyphFace&, int*) const graphite/src/GlyphCache.cpp:398:27 #4 0x560481 in graphite2::GlyphCache::GlyphCache(graphite2::Face const&, unsigned int) graphite/src/GlyphCache.cpp:142:37 #5 0x54bb13 in graphite2::Face::readGlyphs(unsigned int) graphite/src/Face.cpp:98:29 #6 0x56fb34 in (anonymous namespace)::load_face(graphite2::Face&, unsigned int) graphite/src/gr_face.cpp:54:14 #7 0x56f644 in gr_make_face_with_ops graphite/src/gr_face.cpp:89:16 #8 0x571980 in gr_make_file_face graphite/src/gr_face.cpp:242:23 #9 0x4ecf13 in Parameters::testFileFont() const (graphite/gr2fonttest/gr2fonttest+0x4ecf13) #10 0x4f0387 in main (graphite/gr2fonttest/gr2fonttest+0x4f0387) 0x60c00000bf40 is located 0 bytes to the right of 128-byte region [0x60c00000bec0,0x60c00000bf40) allocated by thread T0 here: #0 0x4b85b8 in malloc llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:40 #1 0x55dc0b in graphite2::FileFace::get_table_fn(void const*, unsigned int, unsigned long*) graphite/src/FileFace.cpp:94:11 #2 0x54f8b1 in graphite2::Face::Table::Table(graphite2::Face const&, graphite2::TtfUtil::Tag, unsigned int) graphite/src/Face.cpp:280:36 #3 0x567867 in graphite2::GlyphCache::Loader::Loader(graphite2::Face const&, bool) graphite/src/GlyphCache.cpp:268:24 #4 0x55ef50 in graphite2::GlyphCache::GlyphCache(graphite2::Face const&, unsigned int) graphite/src/GlyphCache.cpp:118:21 #5 0x54bb13 in graphite2::Face::readGlyphs(unsigned int) graphite/src/Face.cpp:98:29 #6 0x56fb34 in (anonymous namespace)::load_face(graphite2::Face&, unsigned int) graphite/src/gr_face.cpp:54:14 #7 0x56f644 in gr_make_face_with_ops graphite/src/gr_face.cpp:89:16 #8 0x571980 in gr_make_file_face graphite/src/gr_face.cpp:242:23 #9 0x4ecf13 in Parameters::testFileFont() const (graphite/gr2fonttest/gr2fonttest+0x4ecf13) #10 0x4f0387 in main (graphite/gr2fonttest/gr2fonttest+0x4f0387) 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: 0x0c187fff9790: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c187fff97a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c187fff97b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c187fff97c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c187fff97d0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00 =>0x0c187fff97e0: 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa 0x0c187fff97f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 0x0c187fff9800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c187fff9810: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c187fff9820: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c187fff9830: 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 ==26347==ABORTING --- cut --- --- cut --- ================================================================= ==26561==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000efb7 at pc 0x00000055445d bp 0x7ffc518d4260 sp 0x7ffc518d4258 READ of size 1 at 0x60200000efb7 thread T0 #0 0x55445c in unsigned long be::_peek<1>(unsigned char const*) graphite/src/./inc/Endian.h:77:73 #1 0x5543c8 in unsigned long be::_peek<2>(unsigned char const*) graphite/src/./inc/Endian.h:50:43 #2 0x554358 in unsigned long be::_peek<4>(unsigned char const*) graphite/src/./inc/Endian.h:50:43 #3 0x551d6b in unsigned int be::read<unsigned int>(unsigned char const*&) graphite/src/./inc/Endian.h:60:23 #4 0x5685a5 in graphite2::GlyphCache::Loader::Loader(graphite2::Face const&, bool) graphite/src/GlyphCache.cpp:306:38 #5 0x55ef50 in graphite2::GlyphCache::GlyphCache(graphite2::Face const&, unsigned int) graphite/src/GlyphCache.cpp:118:21 #6 0x54bb13 in graphite2::Face::readGlyphs(unsigned int) graphite/src/Face.cpp:98:29 #7 0x56fb34 in (anonymous namespace)::load_face(graphite2::Face&, unsigned int) graphite/src/gr_face.cpp:54:14 #8 0x56f644 in gr_make_face_with_ops graphite/src/gr_face.cpp:89:16 #9 0x571980 in gr_make_file_face graphite/src/gr_face.cpp:242:23 #10 0x4ecf13 in Parameters::testFileFont() const (graphite/gr2fonttest/gr2fonttest+0x4ecf13) #11 0x4f0387 in main (graphite/gr2fonttest/gr2fonttest+0x4f0387) 0x60200000efb7 is located 0 bytes to the right of 7-byte region [0x60200000efb0,0x60200000efb7) allocated by thread T0 here: #0 0x4b85b8 in malloc llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:40 #1 0x55dc0b in graphite2::FileFace::get_table_fn(void const*, unsigned int, unsigned long*) graphite/src/FileFace.cpp:94:11 #2 0x54f8b1 in graphite2::Face::Table::Table(graphite2::Face const&, graphite2::TtfUtil::Tag, unsigned int) graphite/src/Face.cpp:280:36 #3 0x567867 in graphite2::GlyphCache::Loader::Loader(graphite2::Face const&, bool) graphite/src/GlyphCache.cpp:268:24 #4 0x55ef50 in graphite2::GlyphCache::GlyphCache(graphite2::Face const&, unsigned int) graphite/src/GlyphCache.cpp:118:21 #5 0x54bb13 in graphite2::Face::readGlyphs(unsigned int) graphite/src/Face.cpp:98:29 #6 0x56fb34 in (anonymous namespace)::load_face(graphite2::Face&, unsigned int) graphite/src/gr_face.cpp:54:14 #7 0x56f644 in gr_make_face_with_ops graphite/src/gr_face.cpp:89:16 #8 0x571980 in gr_make_file_face graphite/src/gr_face.cpp:242:23 #9 0x4ecf13 in Parameters::testFileFont() const (graphite/gr2fonttest/gr2fonttest+0x4ecf13) #10 0x4f0387 in main (graphite/gr2fonttest/gr2fonttest+0x4f0387) 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: 0x0c047fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c047fff9df0: fa fa fa fa fa fa[07]fa fa fa 06 fa fa fa 00 04 0x0c047fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9e30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff9e40: 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 ==26561==ABORTING --- cut --- The bug was reported at https://bugzilla.mozilla.org/show_bug.cgi?id=1252406. Attached is an archive with three font files per each unique crash (in terms of stack trace). There are two directories with reproducers for the graphite2::GlyphCache::Loader::read_glyph crash and four directories with reproducers for graphite2::GlyphCache::Loader::Loader. Proof of Concept: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39860.zip |