From b069a590a9c9e6f06f4d1d5c16df732bd6483536 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Sat, 26 Mar 2016 08:00:07 +0100 Subject: [PATCH] [pfr] Robustify bitmap strike handling (#47514). We did a binary search for a charcode without ensuring that the searched data is ordered. Validating the order is now done lazily, this is, the first access to a bitmap glyph triggers the order check in the corresponding bitmap strike. * src/pfr/pfrtypes.h (PFR_BitmapFlags): New values `PFR_BITMAP_VALID_CHARCODES' and `PFR_BITMAP_CHARCODES_VALIDATED'. * src/pfr/pfrsbit.c (pfr_lookup_bitmap_data): Make `flags' argument a pointer. Handle new PFR_BITMAP_XXX flags. (pfr_slot_load_bitmap): Updated. --- ChangeLog | 18 +++++++++++- src/pfr/pfrsbit.c | 71 ++++++++++++++++++++++++++++++++++++++-------- src/pfr/pfrtypes.h | 4 +++ 3 files changed, 80 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 91063ce27..33c18b940 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,20 @@ -2016-03-25 Werner Lemberg +2016-03-26 Werner Lemberg + + [pfr] Robustify bitmap strike handling (#47514). + + We did a binary search for a charcode without ensuring that the + searched data is ordered. Validating the order is now done lazily, + this is, the first access to a bitmap glyph triggers the order check + in the corresponding bitmap strike. + + * src/pfr/pfrtypes.h (PFR_BitmapFlags): New values + `PFR_BITMAP_VALID_CHARCODES' and `PFR_BITMAP_CHARCODES_VALIDATED'. + + * src/pfr/pfrsbit.c (pfr_lookup_bitmap_data): Make `flags' argument + a pointer. Handle new PFR_BITMAP_XXX flags. + (pfr_slot_load_bitmap): Updated. + +2016-03-26 Werner Lemberg [pfr] Fix handling of compound glyphs. diff --git a/src/pfr/pfrsbit.c b/src/pfr/pfrsbit.c index 9bc5d41d1..d2715937f 100644 --- a/src/pfr/pfrsbit.c +++ b/src/pfr/pfrsbit.c @@ -277,24 +277,76 @@ pfr_lookup_bitmap_data( FT_Byte* base, FT_Byte* limit, FT_UInt count, - FT_UInt flags, + FT_UInt* flags, FT_UInt char_code, FT_ULong* found_offset, FT_ULong* found_size ) { FT_UInt left, right, char_len; - FT_Bool two = FT_BOOL( flags & PFR_BITMAP_2BYTE_CHARCODE ); + FT_Bool two = FT_BOOL( *flags & PFR_BITMAP_2BYTE_CHARCODE ); FT_Byte* buff; char_len = 4; if ( two ) char_len += 1; - if ( flags & PFR_BITMAP_2BYTE_SIZE ) + if ( *flags & PFR_BITMAP_2BYTE_SIZE ) char_len += 1; - if ( flags & PFR_BITMAP_3BYTE_OFFSET ) + if ( *flags & PFR_BITMAP_3BYTE_OFFSET ) char_len += 1; + if ( !( *flags & PFR_BITMAP_CHARCODES_VALIDATED ) ) + { + FT_Byte* p; + FT_Byte* lim; + FT_UInt code; + FT_Long prev_code; + + + *flags |= PFR_BITMAP_VALID_CHARCODES; + prev_code = -1; + lim = base + count * char_len; + + if ( lim > limit ) + { + FT_TRACE0(( "pfr_lookup_bitmap_data:" + " number of bitmap records too large,\n" + " " + " thus ignoring all bitmaps in this strike\n" )); + *flags &= ~PFR_BITMAP_VALID_CHARCODES; + } + else + { + /* check whether records are sorted by code */ + for ( p = base; p < lim; p += char_len ) + { + if ( two ) + code = FT_PEEK_USHORT( p ); + else + code = *p; + + if ( code <= prev_code ) + { + FT_TRACE0(( "pfr_lookup_bitmap_data:" + " bitmap records are not sorted,\n" + " " + " thus ignoring all bitmaps in this strike\n" )); + *flags &= ~PFR_BITMAP_VALID_CHARCODES; + break; + } + + prev_code = code; + } + } + + *flags |= PFR_BITMAP_CHARCODES_VALIDATED; + } + + /* ignore bitmaps in case table is not valid */ + /* (this might be sanitized, but PFR is dead...) */ + if ( !( *flags & PFR_BITMAP_VALID_CHARCODES ) ) + goto Fail; + left = 0; right = count; @@ -306,11 +358,6 @@ middle = ( left + right ) >> 1; buff = base + middle * char_len; - /* check that we are not outside of the table -- */ - /* this is possible with broken fonts... */ - if ( buff + char_len > limit ) - goto Fail; - if ( two ) code = PFR_NEXT_USHORT( buff ); else @@ -332,12 +379,12 @@ return; Found_It: - if ( flags & PFR_BITMAP_2BYTE_SIZE ) + if ( *flags & PFR_BITMAP_2BYTE_SIZE ) *found_size = PFR_NEXT_USHORT( buff ); else *found_size = PFR_NEXT_BYTE( buff ); - if ( flags & PFR_BITMAP_3BYTE_OFFSET ) + if ( *flags & PFR_BITMAP_3BYTE_OFFSET ) *found_offset = PFR_NEXT_ULONG( buff ); else *found_offset = PFR_NEXT_USHORT( buff ); @@ -588,7 +635,7 @@ pfr_lookup_bitmap_data( stream->cursor, stream->limit, strike->num_bitmaps, - strike->flags, + &strike->flags, character->char_code, &gps_offset, &gps_size ); diff --git a/src/pfr/pfrtypes.h b/src/pfr/pfrtypes.h index 09649b9d8..24ca4d375 100644 --- a/src/pfr/pfrtypes.h +++ b/src/pfr/pfrtypes.h @@ -121,6 +121,10 @@ FT_BEGIN_HEADER typedef enum PFR_BitmapFlags_ { + /* not part of the specification but used for implementation */ + PFR_BITMAP_VALID_CHARCODES = 0x80, + PFR_BITMAP_CHARCODES_VALIDATED = 0x40, + PFR_BITMAP_3BYTE_OFFSET = 4, PFR_BITMAP_2BYTE_SIZE = 2, PFR_BITMAP_2BYTE_CHARCODE = 1