diff --git a/ChangeLog b/ChangeLog index 2b3307d5..7c5f0178 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2010-09-19 suzuki toshiya + + [sfnt] Prevent overrunning in `post' table parser. + + * src/sfnt/ttpost.c (load_post_names): Get the length of + `post' table and pass the limit of `post' table to + load_format_20() and load_format_25(). + (load_format_20): Stop the parsing when we reached at the + limit of `post' table. If more glyph names are required, + they are filled by NULL names. See Savannah bug #31040. + 2010-09-17 suzuki toshiya [truetype] Don't duplicate size->twilight structure to be freed. diff --git a/src/sfnt/ttpost.c b/src/sfnt/ttpost.c index aa0bf1ec..5059fd55 100644 --- a/src/sfnt/ttpost.c +++ b/src/sfnt/ttpost.c @@ -153,7 +153,8 @@ static FT_Error load_format_20( TT_Face face, - FT_Stream stream ) + FT_Stream stream, + FT_ULong post_limit ) { FT_Memory memory = stream->memory; FT_Error error; @@ -230,8 +231,29 @@ FT_UInt len; - if ( FT_READ_BYTE ( len ) || - FT_NEW_ARRAY( name_strings[n], len + 1 ) || + FT_TRACE7(( "load_format_20: %d byte left in post table\n", + post_limit - FT_STREAM_POS() )); + + if ( FT_STREAM_POS() >= post_limit ) + { + FT_ERROR(( "load_format_20:" + " all entries in post table is already parsed," + " put NULL name for gid=%d\n", n )); + len = 0; + } + else if ( FT_READ_BYTE( len ) ) + goto Fail1; + + if ( len > 0 && FT_STREAM_POS() + len > post_limit ) + { + FT_ERROR(( "load_format_20:" + " too large string length (%d)" + " truncate at the end of post table (%d byte left)\n", + len, post_limit - FT_STREAM_POS() )); + len = FT_MAX( 0, post_limit - FT_STREAM_POS() ); + } + + if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) || FT_STREAM_READ ( name_strings[n], len ) ) goto Fail1; @@ -271,7 +293,8 @@ static FT_Error load_format_25( TT_Face face, - FT_Stream stream ) + FT_Stream stream, + FT_ULong post_limit ) { FT_Memory memory = stream->memory; FT_Error error; @@ -338,16 +361,19 @@ FT_Stream stream; FT_Error error; FT_Fixed format; + FT_ULong post_len, post_limit; /* get a stream for the face's resource */ stream = face->root.stream; /* seek to the beginning of the PS names table */ - error = face->goto_table( face, TTAG_post, stream, 0 ); + error = face->goto_table( face, TTAG_post, stream, &post_len ); if ( error ) goto Exit; + post_limit = FT_STREAM_POS() + post_len; + format = face->postscript.FormatType; /* go to beginning of subtable */ @@ -356,9 +382,9 @@ /* now read postscript table */ if ( format == 0x00020000L ) - error = load_format_20( face, stream ); + error = load_format_20( face, stream, post_limit ); else if ( format == 0x00028000L ) - error = load_format_25( face, stream ); + error = load_format_25( face, stream, post_limit ); else error = SFNT_Err_Invalid_File_Format;