ref: 5a1a79c0e8de8e886cc347ad22801982e8298a06
parent: 1167bff3e9a6302687667c6134673e4b3fd13636
author: Werner Lemberg <[email protected]>
date: Tue Oct 8 07:12:18 EDT 2019
[woff2] Fix SFNT table checks. Also reduce number of SFNT table lookups. Reported as https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=18065 * include/freetype/internal/wofftypes.h (WOFF2_InfoRec): Add fields `glyf_table', `loca_table', and `head_table'. * src/sfnt/sfwoff2.c (reconstruct_glyf): Update signature. Use table pointers in `info' parameter. (get_x_mins): Check `maxp_table' Use table pointers in `info' parameter. (reconstruct_font): Use and set table pointers in `info' parameter. Fix check for `glyf' and `loca' tables. Update call to `reconstruct_glyf'. (woff2_open_font): Updated.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,28 @@
+2019-10-08 Werner Lemberg <[email protected]>
+
+ [woff2] Fix SFNT table checks.
+
+ Also reduce number of SFNT table lookups.
+
+ Reported as
+
+ https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=18065
+
+ * include/freetype/internal/wofftypes.h (WOFF2_InfoRec): Add fields
+ `glyf_table', `loca_table', and `head_table'.
+
+ * src/sfnt/sfwoff2.c (reconstruct_glyf): Update signature.
+ Use table pointers in `info' parameter.
+ (get_x_mins): Check `maxp_table'
+ Use table pointers in `info' parameter.
+ (reconstruct_font): Use and set table pointers in `info' parameter.
+ Fix check for `glyf' and `loca' tables.
+ Update call to `reconstruct_glyf'.
+ (woff2_open_font): Updated.
+
2019-10-06 Werner Lemberg <[email protected]>
- * src/sfnt/sfwoff2 (reconstruct_glyf): Fix reallocation.
+ * src/sfnt/sfwoff2.c (reconstruct_glyf): Fix reallocation.
Reported as
--- a/include/freetype/internal/wofftypes.h
+++ b/include/freetype/internal/wofftypes.h
@@ -179,6 +179,34 @@
/**************************************************************************
*
* @struct:
+ * WOFF2_TableRec
+ *
+ * @description:
+ * This structure describes a given table of a WOFF2 font.
+ *
+ * @fields:
+ * See
+ *
+ * https://www.w3.org/TR/WOFF2/#table_dir_format
+ */
+ typedef struct WOFF2_TableRec_
+ {
+ FT_Byte FlagByte; /* table type and flags */
+ FT_ULong Tag; /* table file offset */
+ FT_ULong dst_length; /* uncompressed table length */
+ FT_ULong TransformLength; /* transformed length */
+
+ FT_ULong flags; /* calculated flags */
+ FT_ULong src_offset; /* compressed table offset */
+ FT_ULong src_length; /* compressed table length */
+ FT_ULong dst_offset; /* uncompressed table offset */
+
+ } WOFF2_TableRec, *WOFF2_Table;
+
+
+ /**************************************************************************
+ *
+ * @struct:
* WOFF2_InfoRec
*
* @description:
@@ -197,6 +225,15 @@
*
* x_mins ::
* `xMin` values of glyph bounding box.
+ *
+ * glyf_table ::
+ * A pointer to the `glyf' table record.
+ *
+ * loca_table ::
+ * A pointer to the `loca' table record.
+ *
+ * head_table ::
+ * A pointer to the `head' table record.
*/
typedef struct WOFF2_InfoRec_
{
@@ -205,35 +242,11 @@
FT_UShort num_hmetrics;
FT_Short* x_mins;
- } WOFF2_InfoRec, *WOFF2_Info;
+ WOFF2_Table glyf_table;
+ WOFF2_Table loca_table;
+ WOFF2_Table head_table;
-
- /**************************************************************************
- *
- * @struct:
- * WOFF2_TableRec
- *
- * @description:
- * This structure describes a given table of a WOFF2 font.
- *
- * @fields:
- * See
- *
- * https://www.w3.org/TR/WOFF2/#table_dir_format
- */
- typedef struct WOFF2_TableRec_
- {
- FT_Byte FlagByte; /* table type and flags */
- FT_ULong Tag; /* table file offset */
- FT_ULong dst_length; /* uncompressed table length */
- FT_ULong TransformLength; /* transformed length */
-
- FT_ULong flags; /* calculated flags */
- FT_ULong src_offset; /* compressed table offset */
- FT_ULong src_length; /* compressed table length */
- FT_ULong dst_offset; /* uncompressed table offset */
-
- } WOFF2_TableRec, *WOFF2_Table;
+ } WOFF2_InfoRec, *WOFF2_Info;
/**************************************************************************
--- a/src/sfnt/sfwoff2.c
+++ b/src/sfnt/sfwoff2.c
@@ -827,9 +827,7 @@
static FT_Error
reconstruct_glyf( FT_Stream stream,
- WOFF2_Table glyf_table,
FT_ULong* glyf_checksum,
- WOFF2_Table loca_table,
FT_ULong* loca_checksum,
FT_Byte** sfnt_bytes,
FT_ULong* sfnt_size,
@@ -887,11 +885,11 @@
/* index_format = 1 => Long version `loca'. */
expected_loca_length = ( index_format ? 4 : 2 ) *
( (FT_ULong)num_glyphs + 1 );
- if ( loca_table->dst_length != expected_loca_length )
+ if ( info->loca_table->dst_length != expected_loca_length )
goto Fail;
offset = ( 2 + num_substreams ) * 4;
- if ( offset > glyf_table->TransformLength )
+ if ( offset > info->glyf_table->TransformLength )
goto Fail;
for ( i = 0; i < num_substreams; ++i )
@@ -901,7 +899,7 @@
if ( FT_READ_ULONG( substream_size ) )
goto Fail;
- if ( substream_size > glyf_table->TransformLength - offset )
+ if ( substream_size > info->glyf_table->TransformLength - offset )
goto Fail;
substreams[i].start = pos + offset;
@@ -1196,11 +1194,11 @@
info->x_mins[i] = x_min;
}
- glyf_table->dst_length = dest_offset - glyf_table->dst_offset;
- loca_table->dst_offset = dest_offset;
+ info->glyf_table->dst_length = dest_offset - info->glyf_table->dst_offset;
+ info->loca_table->dst_offset = dest_offset;
/* `loca[n]' will be equal to the length of the `glyf' table. */
- loca_values[num_glyphs] = glyf_table->dst_length;
+ loca_values[num_glyphs] = info->glyf_table->dst_length;
if ( store_loca( loca_values,
num_glyphs + 1,
@@ -1212,11 +1210,11 @@
memory ) )
goto Fail;
- loca_table->dst_length = dest_offset - loca_table->dst_offset;
+ info->loca_table->dst_length = dest_offset - info->loca_table->dst_offset;
FT_TRACE4(( " loca table info:\n" ));
- FT_TRACE4(( " dst_offset = %lu\n", loca_table->dst_offset ));
- FT_TRACE4(( " dst_length = %lu\n", loca_table->dst_length ));
+ FT_TRACE4(( " dst_offset = %lu\n", info->loca_table->dst_offset ));
+ FT_TRACE4(( " dst_length = %lu\n", info->loca_table->dst_length ));
FT_TRACE4(( " checksum = %09x\n", *loca_checksum ));
/* Set pointer `sfnt_bytes' to its correct value. */
@@ -1265,16 +1263,16 @@
FT_Error error = FT_Err_Ok;
FT_ULong offset_size;
- const WOFF2_Table glyf_table = find_table( tables, num_tables,
- TTAG_glyf );
- const WOFF2_Table loca_table = find_table( tables, num_tables,
- TTAG_loca );
- const WOFF2_Table maxp_table = find_table( tables, num_tables,
- TTAG_maxp );
- const WOFF2_Table head_table = find_table( tables, num_tables,
- TTAG_head );
+ const WOFF2_Table maxp_table = find_table( tables, num_tables,
+ TTAG_maxp );
+ if ( !maxp_table )
+ {
+ FT_ERROR(( "`maxp' table is missing.\n" ));
+ return FT_THROW( Invalid_Table );
+ }
+
/* Read `numGlyphs' field from `maxp' table. */
if ( FT_STREAM_SEEK( maxp_table->src_offset ) && FT_STREAM_SKIP( 8 ) )
return error;
@@ -1285,7 +1283,8 @@
info->num_glyphs = num_glyphs;
/* Read `indexToLocFormat' field from `head' table. */
- if ( FT_STREAM_SEEK( head_table->src_offset ) && FT_STREAM_SKIP( 50 ) )
+ if ( FT_STREAM_SEEK( info->head_table->src_offset ) &&
+ FT_STREAM_SKIP( 50 ) )
return error;
if ( FT_READ_USHORT( index_format ) )
@@ -1297,7 +1296,7 @@
if ( FT_NEW_ARRAY( info->x_mins, num_glyphs ) )
return error;
- loca_offset = loca_table->src_offset;
+ loca_offset = info->loca_table->src_offset;
for ( i = 0; i < num_glyphs; ++i )
{
@@ -1320,7 +1319,7 @@
glyf_offset = glyf_offset << 1;
}
- glyf_offset += glyf_table->src_offset;
+ glyf_offset += info->glyf_table->src_offset;
if ( FT_STREAM_SEEK( glyf_offset ) && FT_STREAM_SKIP( 2 ) )
return error;
@@ -1501,19 +1500,15 @@
FT_ULong font_checksum = info->header_checksum;
FT_Bool is_glyf_xform = FALSE;
- FT_ULong table_entry_offset = 12;
- WOFF2_Table head_table;
+ FT_ULong table_entry_offset = 12;
+
/* A few table checks before reconstruction. */
/* `glyf' must be present with `loca'. */
- const WOFF2_Table glyf_table = find_table( indices, num_tables,
- TTAG_glyf );
- const WOFF2_Table loca_table = find_table( indices, num_tables,
- TTAG_loca );
+ info->glyf_table = find_table( indices, num_tables, TTAG_glyf );
+ info->loca_table = find_table( indices, num_tables, TTAG_loca );
-
- if ( ( !glyf_table && loca_table ) ||
- ( !loca_table && glyf_table ) )
+ if ( !( info->glyf_table && info->loca_table ) )
{
FT_ERROR(( "Both `glyph' and `loca' tables must be present.\n" ));
return FT_THROW( Invalid_Table );
@@ -1520,10 +1515,10 @@
}
/* Both `glyf' and `loca' must have same transformation. */
- if ( glyf_table != NULL )
+ if ( info->glyf_table != NULL )
{
- if ( ( glyf_table->flags & WOFF2_FLAGS_TRANSFORM ) !=
- ( loca_table->flags & WOFF2_FLAGS_TRANSFORM ) )
+ if ( ( info->glyf_table->flags & WOFF2_FLAGS_TRANSFORM ) !=
+ ( info->loca_table->flags & WOFF2_FLAGS_TRANSFORM ) )
{
FT_ERROR(( "Transformation mismatch"
" between `glyf' and `loca' table." ));
@@ -1605,9 +1600,7 @@
table.dst_offset = dest_offset;
if ( reconstruct_glyf( stream,
- &table,
&checksum,
- loca_table,
&loca_checksum,
&sfnt,
sfnt_size,
@@ -1677,17 +1670,17 @@
}
/* Update `head' checkSumAdjustment. */
- head_table = find_table( indices, num_tables, TTAG_head );
- if ( !head_table )
+ info->head_table = find_table( indices, num_tables, TTAG_head );
+ if ( !info->head_table )
{
FT_ERROR(( "`head' table is missing.\n" ));
goto Fail;
}
- if ( head_table->dst_length < 12 )
+ if ( info->head_table->dst_length < 12 )
goto Fail;
- buf_cursor = sfnt + head_table->dst_offset + 8;
+ buf_cursor = sfnt + info->head_table->dst_offset + 8;
font_checksum = 0xB1B0AFBA - font_checksum;
WRITE_ULONG( buf_cursor, font_checksum );
@@ -1734,7 +1727,7 @@
FT_Int face_index;
WOFF2_HeaderRec woff2;
- WOFF2_InfoRec info = { 0, 0, 0, NULL };
+ WOFF2_InfoRec info = { 0, 0, 0, NULL, NULL, NULL, NULL };
WOFF2_Table tables = NULL;
WOFF2_Table* indices = NULL;
WOFF2_Table* temp_indices = NULL;