[sfnt] Streamline POST format 2.0 handing.

To reduce memory allocations, we read an entire Pascal-string buffer
and convert it to a C-string buffer.  We also reject tables with
Postscript glyph names exceeding 63 bytes.

* src/sfnt/ttpost.c (load_format20): Implement it.
(load_post_names): Check the minimal POST table size.
(load_format25, tt_face_free_ps_names): Updated accordingly.
This commit is contained in:
Alexei Podtelezhnikov 2021-05-03 22:40:16 -04:00
parent ec95f9c921
commit 66630d882c
2 changed files with 62 additions and 61 deletions

View File

@ -1,4 +1,16 @@
2021-04-25 Alexei Podtelezhnikov <apodtele@gmail.com>
2021-05-03 Alexei Podtelezhnikov <apodtele@gmail.com>
[sfnt] Streamline POST format 2.0 handing.
To reduce memory allocations, we read an entire Pascal-string buffer
and convert it to a C-string buffer. We also reject tables with
Postscript glyph names exceeding 63 bytes.
* src/sfnt/ttpost.c (load_format20): Implement it.
(load_post_names): Check the minimal POST table size.
(load_format25, tt_face_free_ps_names): Updated accordingly.
2021-05-02 Alexei Podtelezhnikov <apodtele@gmail.com>
[bdf,pcf] Avoid memory zeroing (contd.).

View File

@ -158,7 +158,7 @@
static FT_Error
load_format_20( TT_Face face,
FT_Stream stream,
FT_ULong post_limit )
FT_ULong post_len )
{
FT_Memory memory = stream->memory;
FT_Error error;
@ -168,6 +168,7 @@
FT_UShort* glyph_indices = NULL;
FT_Char** name_strings = NULL;
FT_Byte* strings = NULL;
if ( FT_READ_USHORT( num_glyphs ) )
@ -179,7 +180,8 @@
/* There already exist fonts which have more than 32768 glyph names */
/* in this table, so the test for this threshold has been dropped. */
if ( num_glyphs > face->max_profile.numGlyphs )
if ( num_glyphs > face->max_profile.numGlyphs ||
num_glyphs * 2UL > post_len - 2 )
{
error = FT_THROW( Invalid_File_Format );
goto Exit;
@ -190,8 +192,8 @@
FT_Int n;
if ( FT_QNEW_ARRAY ( glyph_indices, num_glyphs ) ||
FT_FRAME_ENTER( num_glyphs * 2L ) )
if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
FT_FRAME_ENTER( num_glyphs * 2L ) )
goto Fail;
for ( n = 0; n < num_glyphs; n++ )
@ -223,60 +225,56 @@
}
/* now load the name strings */
if ( num_names )
{
FT_UShort n;
FT_ULong p;
if ( FT_QNEW_ARRAY( name_strings, num_names ) )
post_len -= num_glyphs * 2UL + 2;
if ( FT_QALLOC( strings, post_len + 1 ) ||
FT_STREAM_READ( strings, post_len ) ||
FT_QNEW_ARRAY( name_strings, num_names ) )
goto Fail;
for ( n = 0; n < num_names; n++ )
/* convert from Pascal- to C-strings and set pointers */
for ( p = 0, n = 0; p < post_len && n < num_names; n++ )
{
FT_UInt len;
FT_UInt len = strings[p];
if ( FT_STREAM_POS() >= post_limit )
break;
else
if ( len > 63U )
{
FT_TRACE6(( "load_format_20: %ld byte left in post table\n",
post_limit - FT_STREAM_POS() ));
if ( FT_READ_BYTE( len ) )
goto Fail1;
error = FT_THROW( Invalid_File_Format );
goto Fail;
}
if ( len > post_limit ||
FT_STREAM_POS() > post_limit - len )
{
FT_Int d = (FT_Int)post_limit - (FT_Int)FT_STREAM_POS();
FT_ERROR(( "load_format_20:"
" exceeding string length (%d),"
" truncating at end of post table (%d byte left)\n",
len, d ));
len = (FT_UInt)FT_MAX( 0, d );
}
if ( FT_QNEW_ARRAY( name_strings[n], len + 1 ) ||
FT_STREAM_READ( name_strings[n], len ) )
goto Fail1;
name_strings[n][len] = '\0';
strings[p] = 0;
name_strings[n] = (FT_Char*)strings + p + 1;
p += len + 1;
}
strings[post_len] = 0;
/* deal with missing or insufficient string data */
if ( n < num_names )
{
if ( post_len == 0 )
{
/* fake empty string */
if ( FT_QREALLOC( strings, 1, 2 ) )
goto Fail;
post_len = 1;
strings[post_len] = 0;
}
FT_ERROR(( "load_format_20:"
" all entries in post table are already parsed,"
" using NULL names for gid %d - %d\n",
n, num_names - 1 ));
for ( ; n < num_names; n++ )
if ( FT_QNEW_ARRAY( name_strings[n], 1 ) )
goto Fail1;
else
name_strings[n][0] = '\0';
name_strings[n] = (FT_Char*)strings + post_len;
}
}
@ -292,17 +290,9 @@
}
return FT_Err_Ok;
Fail1:
{
FT_UShort n;
for ( n = 0; n < num_names; n++ )
FT_FREE( name_strings[n] );
}
Fail:
FT_FREE( name_strings );
FT_FREE( strings );
FT_FREE( glyph_indices );
Exit:
@ -313,7 +303,7 @@
static FT_Error
load_format_25( TT_Face face,
FT_Stream stream,
FT_ULong post_limit )
FT_ULong post_len )
{
FT_Memory memory = stream->memory;
FT_Error error;
@ -321,7 +311,7 @@
FT_Int num_glyphs;
FT_Char* offset_table = NULL;
FT_UNUSED( post_limit );
FT_UNUSED( post_len );
if ( FT_READ_USHORT( num_glyphs ) )
@ -384,7 +374,6 @@
FT_Error error;
FT_Fixed format;
FT_ULong post_len;
FT_ULong post_limit;
/* get a stream for the face's resource */
@ -395,8 +384,6 @@
if ( error )
goto Exit;
post_limit = FT_STREAM_POS() + post_len;
format = face->postscript.FormatType;
/* go to beginning of subtable */
@ -404,10 +391,10 @@
goto Exit;
/* now read postscript table */
if ( format == 0x00020000L )
error = load_format_20( face, stream, post_limit );
else if ( format == 0x00025000L )
error = load_format_25( face, stream, post_limit );
if ( format == 0x00020000L && post_len >= 34 )
error = load_format_20( face, stream, post_len - 32 );
else if ( format == 0x00025000L && post_len >= 34 )
error = load_format_25( face, stream, post_len - 32 );
else
error = FT_THROW( Invalid_File_Format );
@ -433,17 +420,19 @@
if ( format == 0x00020000L )
{
TT_Post_20 table = &names->names.format_20;
FT_UShort n;
FT_FREE( table->glyph_indices );
table->num_glyphs = 0;
for ( n = 0; n < table->num_names; n++ )
FT_FREE( table->glyph_names[n] );
if ( table->num_names )
{
table->glyph_names[0]--;
FT_FREE( table->glyph_names[0] );
FT_FREE( table->glyph_names );
table->num_names = 0;
FT_FREE( table->glyph_names );
table->num_names = 0;
}
}
else if ( format == 0x00025000L )
{