From f126ee26e79ccc34a1e44f510a9a1c7252be38d1 Mon Sep 17 00:00:00 2001 From: David Turner Date: Sun, 6 Jan 2002 10:13:40 +0000 Subject: [PATCH] the TrueType glyph loader is now much more paranoid, this avoids unpleasant overwrites in the case of invalid glyph data (found in the output of buggy font converters) the computation of auto-hinted stem widths has been modified to avoid certain color fringes in LCD-decimation rendering (a.k.a. "ClearType") --- ChangeLog | 10 +++++ src/autohint/ahhint.c | 3 ++ src/truetype/ttgload.c | 92 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 97 insertions(+), 8 deletions(-) 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 */