diff --git a/ChangeLog b/ChangeLog index ad8d3b539..21deaf45c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2002-01-05 David Turner + + * src/autohint/ahhint.c: modified computation of auto-hinted stem + widths, this avoids color fringes in "ClearType-like" rendering + + * src/truetype/ttgload.c: modified the TrueType loader to make it + more paranoid, this avoids nasty buffer overflows in the case of + invalid glyph data (as encountered in the output of some buggy + font converters..) + 2002-01-04 David Turner * README.UNX: added special README file for Unix users diff --git a/src/autohint/ahhint.c b/src/autohint/ahhint.c index 3b798b03a..1c212a0ff 100644 --- a/src/autohint/ahhint.c +++ b/src/autohint/ahhint.c @@ -139,6 +139,9 @@ else if ( dist < 128 ) dist = ( dist + 42 ) & -64; + else + /* XXX: round otherwise, prevent color fringes in LCD mode */ + dist = ( dist + 32 ) & -64; } } diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index 32cc4fb84..1db7c9614 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -237,8 +237,11 @@ FT_CALLBACK_DEF( FT_Error ) TT_Load_Glyph_Header( TT_Loader* loader ) { - FT_Stream stream = loader->stream; + FT_Stream stream = loader->stream; + FT_Int byte_len = loader->byte_len - 10; + if ( byte_len < 0 ) + return TT_Err_Invalid_Outline; loader->n_contours = GET_Short(); @@ -252,6 +255,7 @@ loader->bbox.xMax )); FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin, loader->bbox.yMax )); + loader->byte_len = byte_len; return TT_Err_Ok; } @@ -269,6 +273,7 @@ TT_GlyphSlot slot = (TT_GlyphSlot)load->glyph; FT_UShort n_ins; FT_Int n, n_points; + FT_Int byte_len = load->byte_len; /* reading the contours endpoints & number of points */ @@ -276,6 +281,10 @@ short* cur = gloader->current.outline.contours; short* limit = cur + n_contours; + /* check room for contours array + instructions count */ + byte_len -= 2*(n_contours+1); + if ( byte_len < 0 ) + goto Invalid_Outline; for ( ; cur < limit; cur++ ) cur[0] = GET_UShort(); @@ -288,7 +297,12 @@ if ( error ) goto Fail; + /* we'd better check the contours table right now */ outline = &gloader->current.outline; + + for ( cur = outline->contours + 1; cur < limit; cur++ ) + if ( cur[-1] >= cur[0] ) + goto Invalid_Outline; } /* reading the bytecode instructions */ @@ -306,7 +320,8 @@ goto Fail; } - if ( stream->cursor + n_ins > stream->limit ) + byte_len -= n_ins; + if ( byte_len < 0 ) { FT_TRACE0(( "ERROR: Instruction count mismatch!\n" )); error = TT_Err_Too_Many_Hints; @@ -330,24 +345,51 @@ stream->cursor += n_ins; /* reading the point tags */ - { FT_Byte* flag = (FT_Byte*)outline->tags; FT_Byte* limit = flag + n_points; FT_Byte c, count; - for ( ; flag < limit; flag++ ) + while ( flag < limit ) { - *flag = c = GET_Byte(); + if ( --byte_len < 0 ) + goto Invalid_Outline; + + *flag++ = c = GET_Byte(); if ( c & 8 ) { - for ( count = GET_Byte(); count > 0; count-- ) - *++flag = c; + if ( --byte_len < 0 ) + goto Invalid_Outline; + + count = GET_Byte(); + if ( flag + count > limit ) + goto Invalid_Outline; + + for ( ; count > 0; count-- ) + *flag++ = c; } } + + /* check that there is enough room to load the coordinates */ + for ( flag = (FT_Byte*)outline->tags; flag < limit; flag++ ) + { + if ( *flag & 2 ) + byte_len -= 1; + else if ( (*flag & 16) == 0 ) + byte_len -= 2; + + if ( *flag & 4 ) + byte_len -= 1; + else if ( (*flag & 32) == 0 ) + byte_len -= 2; + } + + if ( byte_len < 0 ) + goto Invalid_Outline; } + /* reading the X coordinates */ { @@ -411,8 +453,14 @@ outline->n_points = (FT_UShort)n_points; outline->n_contours = (FT_Short) n_contours; + load->byte_len = byte_len; + Fail: return error; + + Invalid_Outline: + error = TT_Err_Invalid_Outline; + goto Fail; } @@ -424,6 +472,7 @@ FT_GlyphLoader* gloader = loader->gloader; FT_SubGlyph* subglyph; FT_UInt num_subglyphs; + FT_Int byte_len = loader->byte_len; num_subglyphs = 0; @@ -438,6 +487,11 @@ if ( error ) goto Fail; + /* check room */ + byte_len -= 4; + if ( byte_len < 0 ) + goto Invalid_Composite; + subglyph = gloader->current.subglyphs + num_subglyphs; subglyph->arg1 = subglyph->arg2 = 0; @@ -445,6 +499,20 @@ subglyph->flags = GET_UShort(); subglyph->index = GET_UShort(); + /* check room */ + byte_len -= 2; + if ( subglyph->flags & ARGS_ARE_WORDS ) + byte_len -= 2; + if ( subglyph->flags & WE_HAVE_A_SCALE ) + byte_len -= 2; + else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) + byte_len -= 4; + else if ( subglyph->flags & WE_HAVE_A_2X2 ) + byte_len -= 8; + + if ( byte_len < 0 ) + goto Invalid_Composite; + /* read arguments */ if ( subglyph->flags & ARGS_ARE_WORDS ) { @@ -501,8 +569,14 @@ } #endif + loader->byte_len = byte_len; + Fail: return error; + + Invalid_Composite: + error = TT_Err_Invalid_Composite; + goto Fail; } @@ -749,8 +823,10 @@ goto Exit; } + loader->byte_len = (FT_Int) count; + +#if 0 /* temporary hack */ -#if 1 if ( count < 10 ) { /* This glyph is corrupted -- it does not have a complete header */