Thu 13 Nov 2014 09:56:56 AM UTC, original submission:
FreeType 2.5.3 supports embedded bitmaps in SFNT-based fonts, in one of the three standard graphics formats (PNG), while JPEG and TIFF are not yet supported. Such bitmaps can be found in the Apple-defined "sbix" tables (see https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6sbix.html), which in the PNG case is internally handled in FreeType by the "Load_SBit_Png" function implemented in freetype/src/sfnt/pngshim.c.
In addition to bitmap data itself, additional glyph information such as width, height, bit depth etc. is obtained from corresponding PNG headers (specifically, IHDR) and used to initialize internal FT structures:
194: png_uint_32 imgWidth, imgHeight;
195:
196: int bitdepth, color_type, interlace;
...
247: png_get_IHDR( png, info,
248: &imgWidth, &imgHeight,
249: &bitdepth, &color_type, &interlace,
250: NULL, NULL );
...
258: if ( populate_map_and_metrics )
259: {
260: FT_Long size;
261:
262:
263: metrics->width = (FT_Int)imgWidth;
264: metrics->height = (FT_Int)imgHeight;
265:
266: map->width = metrics->width;
267: map->rows = metrics->height;
268: map->pixel_mode = FT_PIXEL_MODE_BGRA;
269: map->pitch = map->width * 4;
270: map->num_grays = 256;
More importantly, these sizes are further used with no bounds checks, in order to calculate the overall buffer size for the PNG data:
272: size = map->rows * map->pitch;
273:
274: error = ft_glyphslot_alloc_bitmap( slot, size );
The bitmap pixels are subsequently loaded into the buffer:
349: for ( i = 0; i < (FT_Int)imgHeight; i++ )
350: rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4;
351:
352: png_read_image( png, rows );
Now, since PNG supports very large images (the width and height fields in IHDR are 32-bit wide) and the "Load_SBit_Png" function blindly trusts the loaded dimensions, it is possible to overflow the "map->rows * map->pitch" expression, thus under-allocating the resulting buffer and later causing a heap-based buffer overflow.
Attached please find a font file (poc.ttf) with a valid embedded PNG file of width=65535 and height=16385, which causes "map->pitch" to become 262140, and "size" to become (uint32)(262140 * 16385) = (uint32)4295163900 = 196604. Since over 4GB of data is attempted to be loaded into a very small buffer, the sample triggers a SIGSEGV signal, or the following AddressSanitizer report.
In order to reproduce, run: $ ftview 150 /path/to/poc.ttf
=================================================================
==21730== ERROR: AddressSanitizer: unknown-crash on address 0xf57cf800 at pc 0xf6121ce0 bp 0xffba2718 sp 0xffba22f8
WRITE of size 262140 at 0xf57cf800 thread T0
#0 0xf6121cdf (/usr/lib32/libasan.so.0+0xdcdf)
#1 0xf5b60ea1 (/lib/i386-linux-gnu/libpng12.so.0+0x9ea1)
#2 0xf5b681f7 (/lib/i386-linux-gnu/libpng12.so.0+0x111f7)
#3 0xf5b68669 (/lib/i386-linux-gnu/libpng12.so.0+0x11669)
#4 0xf60460a3 in Load_SBit_Png freetype2/src/sfnt/pngshim.c:352
#5 0xf604c768 in tt_face_load_sbix_image freetype2/src/sfnt/ttsbit.c:1320
#6 0xf604cb8e in tt_face_load_sbit_image freetype2/src/sfnt/ttsbit.c:1395
#7 0xf5f621b6 in load_sbit_image freetype2/src/truetype/ttgload.c:2036
#8 0xf5f633a6 in TT_Load_Glyph freetype2/src/truetype/ttgload.c:2360
#9 0xf5f539f9 in tt_glyph_load freetype2/src/truetype/ttdriver.c:404
#10 0xf5f188f3 in FT_Load_Glyph freetype2/src/base/ftobjs.c:726
#11 0xf60a315e in ftc_basic_family_load_glyph freetype2/src/cache/ftcbasic.c:173
#12 0xf60a0937 in FTC_INode_New freetype2/src/cache/ftcimage.c:79
#13 0xf60a09eb in ftc_inode_new freetype2/src/cache/ftcimage.c:102
#14 0xf609e4ff in FTC_Cache_NewNode freetype2/src/cache/ftccache.c:461
#15 0xf60a5115 in FTC_ImageCache_LookupScaler freetype2/src/cache/ftcbasic.c:389
#16 0x8059ca0 in FTDemo_Index_To_Bitmap ft2demos-2.5.3/src/ftcommon.c:859
#17 0x8059e42 in FTDemo_Draw_Index ft2demos-2.5.3/src/ftcommon.c:892
#18 0x804bcce in Render_All ft2demos-2.5.3/src/ftview.c:493
#19 0x80540c4 in main ft2demos-2.5.3/src/ftview.c:1974
0xf57ff7fc is located 0 bytes to the right of 196604-byte region [0xf57cf800,0xf57ff7fc)
allocated by thread T0 here:
#0 0xf612a854 (/usr/lib32/libasan.so.0+0x16854)
#1 0xf5f0f387 in ft_alloc freetype2/builds/unix/ftsystem.c:102
#2 0xf5f37304 in ft_mem_qalloc freetype2/src/base/ftutil.c:76
#3 0xf5f3716e in ft_mem_alloc freetype2/src/base/ftutil.c:55
#4 0xf5f1637e in ft_glyphslot_alloc_bitmap freetype2/src/base/ftobjs.c:332
#5 0xf6045d27 in Load_SBit_Png freetype2/src/sfnt/pngshim.c:274
#6 0xf604c768 in tt_face_load_sbix_image freetype2/src/sfnt/ttsbit.c:1320
#7 0xf604cb8e in tt_face_load_sbit_image freetype2/src/sfnt/ttsbit.c:1395
#8 0xf5f621b6 in load_sbit_image freetype2/src/truetype/ttgload.c:2036
#9 0xf5f633a6 in TT_Load_Glyph freetype2/src/truetype/ttgload.c:2360
#10 0xf5f539f9 in tt_glyph_load freetype2/src/truetype/ttdriver.c:404
#11 0xf5f188f3 in FT_Load_Glyph freetype2/src/base/ftobjs.c:726
#12 0xf60a315e in ftc_basic_family_load_glyph freetype2/src/cache/ftcbasic.c:173
#13 0xf60a0937 in FTC_INode_New freetype2/src/cache/ftcimage.c:79
#14 0xf60a09eb in ftc_inode_new freetype2/src/cache/ftcimage.c:102
#15 0xf609e4ff in FTC_Cache_NewNode freetype2/src/cache/ftccache.c:461
#16 0xf60a5115 in FTC_ImageCache_LookupScaler freetype2/src/cache/ftcbasic.c:389
#17 0x8059ca0 in FTDemo_Index_To_Bitmap ft2demos-2.5.3/src/ftcommon.c:859
#18 0x8059e42 in FTDemo_Draw_Index ft2demos-2.5.3/src/ftcommon.c:892
#19 0x804bcce in Render_All ft2demos-2.5.3/src/ftview.c:493
#20 0x80540c4 in main ft2demos-2.5.3/src/ftview.c:1974
SUMMARY: AddressSanitizer: unknown-crash ??:0 ??
Shadow bytes around the buggy address:
0x3eaf9eb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x3eaf9ec0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x3eaf9ed0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x3eaf9ee0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x3eaf9ef0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x3eaf9f00:[00]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x3eaf9f10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x3eaf9f20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x3eaf9f30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x3eaf9f40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x3eaf9f50: 00 00 00 00 00 00 00 00 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 righ 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
ASan internal: fe
==21730== ABORTING
|