Fri 28 Feb 2014 02:00:53 AM UTC, comment #5:
The problem is triggered by a charstring with too many stem hints.
In the original font, asan_stack-oob_704686_9216_cov_3502053733_sigsegv2.ttf,
the problem occurs with glyph 15364. There are 150 stem hints.
Many incidental errors also occur:
"cff_index_access_element: offset to next entry ..."
"tt_face_build_cmaps: unsupported cmap sub-table ..."
In the second font, ftbench_oob_stack_sigsegv.otf, there are 1,000,000 stem hints in glyph 47.
The error is correctly detected, but the program flow after the error is incorrect. The simplest fix is to return early from cf2_hintmap_build() when there is an invalid hint mask.
|
Wed 26 Feb 2014 05:06:52 PM UTC, comment #3:
Yes, I am pretty sure that's the right font. It's strange you have difficulty reproducing it, as the bitCount variable is clearly larger than the maximum legal value of 96 in the source code I referred to.
Anyway, here: http://j00ru.vexillium.org/dump/ftbench_oob_stack_sigsegv.otf you can find another font which crosses the stack buffer boundary not by just a few bits, but enough to reach the top of the stack and generate a SIGSEGV exception in a regular ftbench build:
--- cut ---
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7721bce in cf2_hintmap_build (hintmap=0x7fffffff7150, hStemHintArray=0x7fffffffd3b0, vStemHintArray=0x7fffffffd370,
hintMask=0x7fffffff7120, hintOrigin=0, initialMap=0 '\000')
at freetype2/src/cff/cf2hints.c:820
820 if ( maskByte & *maskPtr )
(gdb) where
#0 0x00007ffff7721bce in cf2_hintmap_build (hintmap=0x7fffffff7150, hStemHintArray=0x7fffffffd3b0, vStemHintArray=0x7fffffffd370,
hintMask=0x7fffffff7120, hintOrigin=0, initialMap=0 '\000')
at freetype2/src/cff/cf2hints.c:820
#1 0x00007ffff77249bd in cf2_interpT2CharString (font=0x60e5c0, buf=0x7fffffffd620, callbacks=0x60e628, translation=0x7fffffffd5d0,
doingSeac=0 '\000', curX=0, curY=0, width=0x7fffffffd5cc)
at freetype2/src/cff/cf2intrp.c:1201
#2 0x00007ffff771febe in cf2_getGlyphOutline (font=0x60e5c0, charstring=0x7fffffffd620, transform=0x7fffffffd650,
glyphWidth=0x7fffffffd64c) at freetype2/src/cff/cf2font.c:461
#3 0x00007ffff77205b1 in cf2_decoder_parse_charstrings (decoder=0x7fffffffd770,
charstring_base=0x7ffff6604df8 "\024PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001PP\001P"..., charstring_len=3000007) at freetype2/src/cff/cf2ft.c:369
#4 0x00007ffff771d8e9 in cff_slot_load (glyph=0x60c9e0, size=0x60cc40, glyph_index=47, load_flags=0)
at freetype2/src/cff/cffgload.c:2840
#5 0x00007ffff7716013 in cff_glyph_load (cffslot=0x60c9e0, cffsize=0x60cc40, glyph_index=47, load_flags=0)
at freetype2/src/cff/cffdrivr.c:185
#6 0x00007ffff76e6659 in FT_Load_Glyph (face=0x60a8e0, glyph_index=47, load_flags=0)
at freetype2/src/base/ftobjs.c:726
#7 0x0000000000401acb in test_load (timer=0x7fffffffe0a0, face=0x60a8e0, user_data=0x0)
at freetype2-demos/src/ftbench.c:249
#8 0x00000000004019f7 in benchmark (face=0x60a8e0, test=0x7fffffffe0f0, max_iter=0, max_time=2)
at freetype2-demos/src/ftbench.c:216
#9 0x0000000000402fd8 in main (argc=1, argv=0x7fffffffe270)
at freetype2-demos/src/ftbench.c:1020
(gdb) x/10i $rip
=> 0x7ffff7721bce <cf2_hintmap_build+493>: movzbl (%rax),%eax
0x7ffff7721bd1 <cf2_hintmap_build+496>: and -0x21(%rbp),%al
0x7ffff7721bd4 <cf2_hintmap_build+499>: test %al,%al
0x7ffff7721bd6 <cf2_hintmap_build+501>: je 0x7ffff7721cd9 <cf2_hintmap_build+760>
0x7ffff7721bdc <cf2_hintmap_build+507>: mov -0xb8(%rbp),%rax
0x7ffff7721be3 <cf2_hintmap_build+514>: mov 0x1c(%rax),%r8d
0x7ffff7721be7 <cf2_hintmap_build+518>: mov -0xd4(%rbp),%edi
0x7ffff7721bed <cf2_hintmap_build+524>: mov -0x30(%rbp),%rcx
0x7ffff7721bf1 <cf2_hintmap_build+528>: mov -0x20(%rbp),%rdx
0x7ffff7721bf5 <cf2_hintmap_build+532>: mov -0xc0(%rbp),%rsi
(gdb) x/10wx $rax
0x7ffffffff000: Cannot access memory at address 0x7ffffffff000
--- cut ---
I hope that helps, let me know if you have any luck with reproduction.
|
Tue 25 Feb 2014 08:43:38 PM UTC, original submission:
Tested on Ubuntu AMD64 with upstream FreeType2 and FreeType2-demos, reproduced with ./ftbench <file>.
This is a critical vulnerability in the CFF Rasterizer code recently contributed by Adobe, leading to potential arbitrary code execution in the context of the FreeType2 library client. It will require a CVE identifier and most likely a new stable library release.
I would like to ask you to keep the bug private until a new release is out.
Report:
==31664==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff76853d70 at pc 0x6d2d74 bp 0x7fff768537f0 sp 0x7fff768537e8
READ of size 1 at 0x7fff76853d70 thread T0
#0 0x6d2d73 in cf2_hintmap_build freetype2/src/cff/cf2hints.c:820
#1 0x6b85ab in cf2_interpT2CharString freetype2/src/cff/cf2intrp.c:1201
#2 0x6ae390 in cf2_getGlyphOutline freetype2/src/cff/cf2font.c:461
#3 0x6aafa6 in cf2_decoder_parse_charstrings freetype2/src/cff/cf2ft.c:369
#4 0x6a134c in cff_slot_load freetype2/src/cff/cffgload.c:2840
#5 0x66b8b0 in cff_glyph_load freetype2/src/cff/cffdrivr.c:185
#6 0x4a28e2 in FT_Load_Glyph freetype2/src/base/ftobjs.c:726
#7 0x492475 in test_load freetype2-demos/src/ftbench.c:249
#8 0x4930e7 in benchmark freetype2-demos/src/ftbench.c:216
#9 0x48f692 in main freetype2-demos/src/ftbench.c:1020
Address 0x7fff76853d70 is located in stack of thread T0 at offset 304 in frame
#0 0x6d1c8f in cf2_hintmap_build freetype2/src/cff/cf2hints.c:754
This frame has 20 object(s):
[32, 40) 'hintmap.addr'
[64, 72) 'hStemHintArray.addr'
[96, 104) 'vStemHintArray.addr'
[128, 136) 'hintMask.addr'
[160, 164) 'hintOrigin.addr'
[176, 177) 'initialMap.addr'
[192, 200) 'maskPtr'
[224, 232) 'font'
[256, 304) 'tempHintMask' <== Memory access at offset 304 overflows this variable
[336, 344) 'bitCount'
[368, 376) 'i'
[400, 401) 'maskByte'
[416, 448) 'dummy'
[480, 512) 'bottomHintEdge'
[544, 576) 'topHintEdge'
[608, 640) 'edge62'
[672, 704) 'invalid'
[736, 768) 'bottomHintEdge77'
[800, 832) 'topHintEdge78'
[864, 872) 'stemhint'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions are supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow freetype2/src/cff/cf2hints.c:820 cf2_hintmap_build
Shadow bytes around the buggy address:
0x10006ed02750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006ed02760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006ed02770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10006ed02780: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 f2 f2 f2
0x10006ed02790: 00 f2 f2 f2 00 f2 f2 f2 00 f2 f2 f2 04 f2 01 f2
=>0x10006ed027a0: 00 f2 f2 f2 00 f2 f2 f2 00 00 00 00 00 00[f2]f2
0x10006ed027b0: f2 f2 00 f2 f2 f2 00 f2 f2 f2 01 f2 00 00 00 00
0x10006ed027c0: f2 f2 f2 f2 00 00 00 00 f2 f2 f2 f2 00 00 00 00
0x10006ed027d0: f2 f2 f2 f2 00 00 00 00 f2 f2 f2 f2 00 00 00 00
0x10006ed027e0: f2 f2 f2 f2 00 00 00 00 f2 f2 f2 f2 00 00 00 00
0x10006ed027f0: f2 f2 f2 f2 00 f3 f3 f3 00 00 00 00 00 00 00 00
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: [31==31664==ABORTING
Root cause: no implementation for the "TODO" comment below.
--- src/cff/cf2hints.c ---
794: /* use the hStem hints only, which are first in the mask */
795: /* TODO: compare this to cffhintmaskGetBitCount */
796: bitCount = cf2_arrstack_size( hStemHintArray );
--- cut ---
|