[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.
This commit is contained in:
Werner Lemberg 2019-10-08 11:12:18 +02:00
parent 1167bff3e9
commit 5a1a79c0e8
3 changed files with 102 additions and 74 deletions

View File

@ -1,6 +1,28 @@
2019-10-08 Werner Lemberg <wl@gnu.org>
[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 <wl@gnu.org>
* src/sfnt/sfwoff2 (reconstruct_glyf): Fix reallocation.
* src/sfnt/sfwoff2.c (reconstruct_glyf): Fix reallocation.
Reported as

View File

@ -176,38 +176,6 @@ FT_BEGIN_HEADER
} WOFF2_HeaderRec, *WOFF2_Header;
/**************************************************************************
*
* @struct:
* WOFF2_InfoRec
*
* @description:
* Metadata for WOFF2 font that may be required for reconstruction of
* sfnt tables.
*
* @fields:
* header_checksum ::
* Checksum of SFNT offset table.
*
* num_glyphs ::
* Number of glyphs in the font.
*
* num_hmetrics ::
* `numberOfHMetrics` field in the 'hhea' table.
*
* x_mins ::
* `xMin` values of glyph bounding box.
*/
typedef struct WOFF2_InfoRec_
{
FT_ULong header_checksum;
FT_UShort num_glyphs;
FT_UShort num_hmetrics;
FT_Short* x_mins;
} WOFF2_InfoRec, *WOFF2_Info;
/**************************************************************************
*
* @struct:
@ -236,6 +204,51 @@ FT_BEGIN_HEADER
} WOFF2_TableRec, *WOFF2_Table;
/**************************************************************************
*
* @struct:
* WOFF2_InfoRec
*
* @description:
* Metadata for WOFF2 font that may be required for reconstruction of
* sfnt tables.
*
* @fields:
* header_checksum ::
* Checksum of SFNT offset table.
*
* num_glyphs ::
* Number of glyphs in the font.
*
* num_hmetrics ::
* `numberOfHMetrics` field in the 'hhea' table.
*
* 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_
{
FT_ULong header_checksum;
FT_UShort num_glyphs;
FT_UShort num_hmetrics;
FT_Short* x_mins;
WOFF2_Table glyf_table;
WOFF2_Table loca_table;
WOFF2_Table head_table;
} WOFF2_InfoRec, *WOFF2_Info;
/**************************************************************************
*
* @struct:

View File

@ -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,29 +1500,25 @@
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 );
}
/* 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;