diff --git a/ChangeLog b/ChangeLog index 3c231f078..50e8012b7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,81 @@ +2004-08-16 Werner Lemberg + + * src/otlayout/otlgpos.c (otl_gpos_lookup1_validate, + otl_gpos_lookup2_validate, otl_gpos_lookup3_validate, + otl_gpos_lookup4_validate, otl_gpos_lookup5_validate, + otl_gpos_lookup6_validate, otl_gpos_lookup9_validate, + otl_gpos_validate): Update + function arguments. + (otl_gpos_lookup7_validate, otl_gpos_lookup8_validate): Update + function arguments. + Handle NULL offsets correctly. + Check sequence and lookup indices for format 3. + (otl_pos_rule_validate, otl_chain_pos_rule_validate): Add argument + to pass lookup count. + Check sequence and glyph indices. + (otl_gpos_subtable_validate): Update function arguments. + Update callers. + + * src/otlayout/otlgpos.h: Updated. + + * src/otlayout/otlgsub.c (otl_gsub_lookup1_validate, + otl_gsub_lookup3_validate, otl_gsub_lookup8_validate): Update + function arguments. + Add glyph index checks. + (otl_sequence_validate, otl_alternate_set_validate, + otl_ligature_validate): Add argument to pass glyph count. + Update callers. + Add glyph index check. + (otl_gsub_lookup2_validate, otl_gsub_lookup4_validate): Update + function arguments. + (otl_ligature_set_validate): Add argument to pass glyph count. + Update caller. + (otl_sub_class_rule_validate, + otl_sub_class_rule_set_validate): Removed. + (otl_sub_rule_validate, otl_chain_sub_rule_validate): Add argument + to pass lookup count. + Update callers. + Add lookup index check. + (otl_sub_rule_set_validate, otl_chain_sub_rule_set_validate): Add + argument to pass lookup count. + Update callers. + (otl_gsub_lookup5_validate): Update function arguments. + Handle NULL offsets correctly. + Don't call otl_sub_class_rule_set_validate but + otl_sub_rule_set_validate. + Check sequence and lookup indices for format 3. + (otl_gsub_lookup6_validate): Update function arguments. + Handle NULL offsets correctly. + Check sequence and lookup indices for format 3. + (otl_gsub_lookup7_validate, otl_gsub_validate): Update function + arguments. + + * src/otlayout/otlgsub.h: Updated. + + * src/otlayout/otlbase.c (otl_base_validate): Handle NULL offsets + correctly. + + * src/otlayout/otlcommn.c (otl_class_definition_validate): Fix + compiler warning. + (otl_coverage_get_first, otl_coverage_get_last): New functions. + (otl_lookup_validate): Add arguments to pass lookup and glyph + counts. + Update callers. + (otl_lookup_list_validate): Add argument to pass glyph count. + Update callers. + + * src/otlayout/otlcommn.h: Updated. + + * src/otlayout/otljstf.c (otl_jstf_extender_validate, + otl_jstf_max_validate, otl_jstf_script_validate, + otl_jstf_priority_validate, otl_jstf_lang_validate): Add parameter + to validate glyph indices. + Update callers. + (otl_jstf_validate): Add parameter which specifies number of glyphs + in font. + + * src/otlayout/otljstf.h: Updated. + 2004-08-15 Werner Lemberg * src/otlayout/otlgpos.c (otl_liga_mark2_validate): Add parameter diff --git a/src/otlayout/otlayout.h b/src/otlayout/otlayout.h index ff1bdcd66..21988f390 100644 --- a/src/otlayout/otlayout.h +++ b/src/otlayout/otlayout.h @@ -189,6 +189,8 @@ OTL_BEGIN_HEADER } OTL_ValidatorRec; typedef void (*OTL_ValidateFunc)( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ); OTL_API( void ) diff --git a/src/otlayout/otlbase.c b/src/otlayout/otlbase.c index 753004de9..2fe242667 100644 --- a/src/otlayout/otlbase.c +++ b/src/otlayout/otlbase.c @@ -208,6 +208,7 @@ OTL_Validator valid ) { OTL_Bytes p = table; + OTL_UInt val; OTL_CHECK( 6 ); @@ -215,8 +216,15 @@ if ( OTL_NEXT_ULONG( p ) != 0x10000UL ) OTL_INVALID_DATA; - otl_axis_table_validate( table + OTL_NEXT_USHORT( p ), valid ); - otl_axis_table_validate( table + OTL_NEXT_USHORT( p ), valid ); + /* validate horizontal axis table */ + val = OTL_NEXT_USHORT( p ); + if ( val ) + otl_axis_table_validate( table + val, valid ); + + /* validate vertical axis table */ + val = OTL_NEXT_USHORT( p ); + if ( val ) + otl_axis_table_validate( table + val, valid ); } diff --git a/src/otlayout/otlcommn.c b/src/otlayout/otlcommn.c index 0f802c49a..802266e17 100644 --- a/src/otlayout/otlcommn.c +++ b/src/otlayout/otlcommn.c @@ -86,6 +86,47 @@ } + OTL_LOCALDEF( OTL_UInt ) + otl_coverage_get_first( OTL_Bytes table ) + { + OTL_Bytes p = table; + + + p += 4; /* skip format and count */ + + return OTL_NEXT_USHORT( p ); + } + + + OTL_LOCALDEF( OTL_UInt ) + otl_coverage_get_last( OTL_Bytes table ) + { + OTL_Bytes p = table; + OTL_UInt format = OTL_NEXT_USHORT( p ); + OTL_UInt count = OTL_NEXT_USHORT( p ); + OTL_UInt result; + + + switch ( format ) + { + case 1: + p += ( count - 1 ) * 2; + result = OTL_NEXT_USHORT( p ); + break; + + case 2: + p += ( count - 1 ) * 6 + 2; + result = OTL_NEXT_USHORT( p ); + break; + + default: + ; + } + + return result; + } + + OTL_LOCALDEF( OTL_UInt ) otl_coverage_get_count( OTL_Bytes table ) { @@ -215,14 +256,15 @@ { case 1: { - OTL_UInt num_glyphs, start = OTL_NEXT_USHORT( p ); + OTL_UInt num_glyphs; + p += 2; /* skip start_glyph */ + OTL_CHECK( 2 ); num_glyphs = OTL_NEXT_USHORT( p ); OTL_CHECK( num_glyphs * 2 ); - } break; @@ -442,6 +484,8 @@ otl_lookup_validate( OTL_Bytes table, OTL_UInt type_count, OTL_ValidateFunc* type_funcs, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -463,7 +507,8 @@ /* scan subtables */ for ( ; num_subtables > 0; num_subtables-- ) - validate( table + OTL_NEXT_USHORT( p ), valid ); + validate( table + OTL_NEXT_USHORT( p ), lookup_count, glyph_count, + valid ); } @@ -511,10 +556,11 @@ otl_lookup_list_validate( OTL_Bytes table, OTL_UInt type_count, OTL_ValidateFunc* type_funcs, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; - OTL_UInt num_lookups; + OTL_UInt num_lookups, count; OTL_CHECK( 2 ); @@ -522,9 +568,10 @@ OTL_CHECK( 2 * num_lookups ); /* scan lookup records */ - for ( ; num_lookups > 0; num_lookups-- ) + for ( count = num_lookups; count > 0; count-- ) otl_lookup_validate( table + OTL_NEXT_USHORT( p ), - type_count, type_funcs, valid ); + type_count, type_funcs, + num_lookups, glyph_count, valid ); } diff --git a/src/otlayout/otlcommn.h b/src/otlayout/otlcommn.h index 5af75b984..de8e7477d 100644 --- a/src/otlayout/otlcommn.h +++ b/src/otlayout/otlcommn.h @@ -37,6 +37,14 @@ OTL_BEGIN_HEADER otl_coverage_validate( OTL_Bytes table, OTL_Validator valid ); + /* return first covered glyph */ + OTL_LOCAL( OTL_UInt ) + otl_coverage_get_first( OTL_Bytes table ); + + /* return last covered glyph */ + OTL_LOCAL( OTL_UInt ) + otl_coverage_get_last( OTL_Bytes table ); + /* return number of covered glyphs */ OTL_LOCAL( OTL_UInt ) otl_coverage_get_count( OTL_Bytes table ); @@ -116,6 +124,8 @@ OTL_BEGIN_HEADER otl_lookup_validate( OTL_Bytes table, OTL_UInt type_count, OTL_ValidateFunc* type_funcs, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ); /* return number of sub-tables in a lookup */ @@ -143,6 +153,7 @@ OTL_BEGIN_HEADER otl_lookup_list_validate( OTL_Bytes table, OTL_UInt type_count, OTL_ValidateFunc* type_funcs, + OTL_UInt glyph_count, OTL_Validator valid ); #if 0 diff --git a/src/otlayout/otlgpos.c b/src/otlayout/otlgpos.c index d76a4c69c..f3de23788 100644 --- a/src/otlayout/otlgpos.c +++ b/src/otlayout/otlgpos.c @@ -173,11 +173,16 @@ static void otl_gpos_lookup1_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( lookup_count ); + OTL_UNUSED( glyph_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -270,11 +275,16 @@ static void otl_gpos_lookup2_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( lookup_count ); + OTL_UNUSED( glyph_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -354,11 +364,16 @@ static void otl_gpos_lookup3_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( lookup_count ); + OTL_UNUSED( glyph_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -430,11 +445,16 @@ static void otl_gpos_lookup4_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( lookup_count ); + OTL_UNUSED( glyph_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -466,6 +486,7 @@ } } + /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -529,11 +550,16 @@ static void otl_gpos_lookup5_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( lookup_count ); + OTL_UNUSED( glyph_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -576,11 +602,16 @@ static void otl_gpos_lookup6_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( lookup_count ); + OTL_UNUSED( glyph_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -623,6 +654,7 @@ /* used for both format 1 and 2 */ static void otl_pos_rule_validate( OTL_Bytes table, + OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -638,7 +670,14 @@ OTL_CHECK( ( num_glyphs - 1 ) * 2 + num_pos * 4 ); - /* XXX: check pos lookups */ + for ( ; num_pos > 0; num_pos-- ) + { + if ( OTL_NEXT_USHORT( p ) >= num_glyphs ) + OTL_INVALID_DATA; + + if ( OTL_NEXT_USHORT( p ) >= lookup_count ) + OTL_INVALID_DATA; + } /* no need to check glyph indices/classes used as input for this */ /* context rule since even invalid glyph indices/classes return a */ @@ -649,6 +688,7 @@ /* used for both format 1 and 2 */ static void otl_pos_rule_set_validate( OTL_Bytes table, + OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -662,17 +702,22 @@ /* scan posrule records */ for ( ; num_posrules > 0; num_posrules-- ) - otl_pos_rule_validate( table + OTL_NEXT_USHORT( p ), valid ); + otl_pos_rule_validate( table + OTL_NEXT_USHORT( p ), lookup_count, + valid ); } static void otl_gpos_lookup7_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( glyph_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -693,7 +738,8 @@ /* scan posrule set records */ for ( ; num_posrule_sets > 0; num_posrule_sets-- ) - otl_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ), valid ); + otl_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ), + lookup_count, valid ); } break; @@ -714,13 +760,19 @@ /* scan pos class set rules */ for ( ; num_posclass_sets > 0; num_posclass_sets-- ) - otl_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ), valid ); + { + OTL_UInt offset = OTL_NEXT_USHORT( p ); + + + if ( offset ) + otl_pos_rule_set_validate( table + offset, lookup_count, valid ); + } } break; case 3: { - OTL_UInt num_glyphs, num_pos; + OTL_UInt num_glyphs, num_pos, count; OTL_CHECK( 4 ); @@ -729,10 +781,17 @@ OTL_CHECK( num_glyphs * 2 + num_pos * 4 ); - for ( ; num_glyphs > 0; num_glyphs-- ) + for ( count = num_glyphs; count > 0; count-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); - /* XXX: check pos lookups */ + for ( ; num_pos > 0; num_pos-- ) + { + if ( OTL_NEXT_USHORT( p ) >= num_glyphs ) + OTL_INVALID_DATA; + + if ( OTL_NEXT_USHORT( p ) >= lookup_count ) + OTL_INVALID_DATA; + } } break; @@ -753,6 +812,7 @@ /* used for both format 1 and 2 */ static void otl_chain_pos_rule_validate( OTL_Bytes table, + OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -780,37 +840,54 @@ num_pos = OTL_NEXT_USHORT( p ); OTL_CHECK( num_pos * 4 ); - /* XXX: check pos lookups */ + for ( ; num_pos > 0; num_pos-- ) + { + if ( OTL_NEXT_USHORT( p ) >= num_input_glyphs ) + OTL_INVALID_DATA; + + if ( OTL_NEXT_USHORT( p ) >= lookup_count ) + OTL_INVALID_DATA; + } + + /* no need to check glyph indices/classes used as input for this */ + /* context rule since even invalid glyph indices/classes return a */ + /* meaningful result */ } /* used for both format 1 and 2 */ static void otl_chain_pos_rule_set_validate( OTL_Bytes table, + OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; - OTL_UInt count; + OTL_UInt num_chain_subrules; OTL_CHECK( 2 ); - count = OTL_NEXT_USHORT( p ); + num_chain_subrules = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * count ); + OTL_CHECK( num_chain_subrules * 2 ); /* scan chain pos rule records */ - for ( ; count > 0; count-- ) - otl_chain_pos_rule_validate( table + OTL_NEXT_USHORT( p ), valid ); + for ( ; num_chain_subrules > 0; num_chain_subrules-- ) + otl_chain_pos_rule_validate( table + OTL_NEXT_USHORT( p ), + lookup_count, valid ); } static void otl_gpos_lookup8_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( glyph_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -832,7 +909,7 @@ /* scan chain pos ruleset records */ for ( ; num_chain_pos_rulesets > 0; num_chain_pos_rulesets-- ) otl_chain_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ), - valid ); + lookup_count, valid ); } break; @@ -859,33 +936,39 @@ /* scan chainpos class set records */ for ( ; num_chainpos_class_sets > 0; num_chainpos_class_sets-- ) - otl_chain_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ), - valid ); + { + OTL_UInt offset = OTL_NEXT_USHORT( p ); + + + if ( offset ) + otl_chain_pos_rule_set_validate( table + offset, lookup_count, + valid ); + } } break; case 3: { OTL_UInt num_backtrack_glyphs, num_input_glyphs; - OTL_UInt num_lookahead_glyphs, num_pos; + OTL_UInt num_lookahead_glyphs, num_pos, count; OTL_CHECK( 2 ); - num_backtrack_glyphs = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_backtrack_glyphs + 2 ); + num_backtrack_glyphs = OTL_NEXT_USHORT( p ); + OTL_CHECK( num_backtrack_glyphs * 2 + 2 ); for ( ; num_backtrack_glyphs > 0; num_backtrack_glyphs-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); num_input_glyphs = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_input_glyphs + 2 ); + OTL_CHECK( num_input_glyphs * 2 + 2 ); - for ( ; num_input_glyphs > 0; num_input_glyphs-- ) + for ( count = num_input_glyphs; count > 0; count-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); num_lookahead_glyphs = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_lookahead_glyphs + 2 ); + OTL_CHECK( num_lookahead_glyphs * 2 + 2 ); for ( ; num_lookahead_glyphs > 0; num_lookahead_glyphs-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); @@ -893,7 +976,14 @@ num_pos = OTL_NEXT_USHORT( p ); OTL_CHECK( num_pos * 4 ); - /* XXX: check pos lookups */ + for ( ; num_pos > 0; num_pos-- ) + { + if ( OTL_NEXT_USHORT( p ) >= num_input_glyphs ) + OTL_INVALID_DATA; + + if ( OTL_NEXT_USHORT( p ) >= lookup_count ) + OTL_INVALID_DATA; + } } break; @@ -913,6 +1003,8 @@ static void otl_gpos_lookup9_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -937,7 +1029,7 @@ OTL_INVALID_DATA; validate = otl_gpos_validate_funcs[lookup_type - 1]; - validate( table + lookup_offset, valid ); + validate( table + lookup_offset, lookup_count, glyph_count, valid ); } break; @@ -963,9 +1055,11 @@ OTL_LOCALDEF( void ) otl_gpos_subtable_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ) { - otl_lookup_list_validate( table, 9, otl_gpos_validate_funcs, valid ); + otl_lookup_list_validate( table, 9, otl_gpos_validate_funcs, + glyph_count, valid ); } @@ -979,6 +1073,7 @@ OTL_LOCALDEF( void ) otl_gpos_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -994,7 +1089,7 @@ features = OTL_NEXT_USHORT( p ); lookups = OTL_NEXT_USHORT( p ); - otl_gpos_subtable_validate( table + lookups, valid ); + otl_gpos_subtable_validate( table + lookups, glyph_count, valid ); otl_feature_list_validate( table + features, table + lookups, valid ); otl_script_list_validate( table + scripts, table + features, valid ); } diff --git a/src/otlayout/otlgpos.h b/src/otlayout/otlgpos.h index b117eb886..42b88745e 100644 --- a/src/otlayout/otlgpos.h +++ b/src/otlayout/otlgpos.h @@ -26,10 +26,12 @@ OTL_BEGIN_HEADER OTL_LOCAL( void ) otl_gpos_subtable_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ); OTL_LOCAL( void ) otl_gpos_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ); diff --git a/src/otlayout/otlgsub.c b/src/otlayout/otlgsub.c index b85d350dd..5a6b820b9 100644 --- a/src/otlayout/otlgsub.c +++ b/src/otlayout/otlgsub.c @@ -57,11 +57,15 @@ static void otl_gsub_lookup1_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( lookup_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -69,12 +73,26 @@ switch ( format ) { case 1: - OTL_CHECK( 4 ); + { + OTL_Bytes coverage; + OTL_Int delta; + OTL_Long idx; - otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); - /* skip delta glyph ID */ + OTL_CHECK( 4 ); + coverage = table + OTL_NEXT_USHORT( p ); + delta = OTL_NEXT_SHORT( p ); + otl_coverage_validate( coverage, valid ); + + idx = otl_coverage_get_first( coverage ) + delta; + if ( idx < 0 ) + OTL_INVALID_DATA; + + idx = otl_coverage_get_last( coverage ) + delta; + if ( (OTL_UInt)idx >= glyph_count ) + OTL_INVALID_DATA; + } break; case 2: @@ -88,11 +106,11 @@ otl_coverage_validate( table + coverage, valid ); - OTL_CHECK( 2 * num_glyphs ); + OTL_CHECK( num_glyphs * 2 ); - /* We don't check that there are at most `num_glyphs' */ - /* elements in the coverage table. This is delayed */ - /* to the lookup function. */ + for ( ; num_glyphs > 0; num_glyphs-- ) + if ( OTL_NEXT_USHORT( p ) >= glyph_count ) + OTL_INVALID_DATA; } break; @@ -198,6 +216,7 @@ static void otl_sequence_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -207,22 +226,28 @@ OTL_CHECK( 2 ); num_glyphs = OTL_NEXT_USHORT( p ); - /* XXX: according to the spec, `num_glyphs' should be > 0; */ - /* we can deal with these cases pretty well, however */ + /* according to the specification, `num_glyphs' should be > 0; */ + /* we can deal with these cases pretty well, however */ - OTL_CHECK( 2 * num_glyphs ); + OTL_CHECK( num_glyphs * 2 ); - /* XXX: check glyph indices */ + for ( ; num_glyphs > 0; num_glyphs-- ) + if ( OTL_NEXT_USHORT( p ) >= glyph_count ) + OTL_INVALID_DATA; } static void otl_gsub_lookup2_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( lookup_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -243,7 +268,8 @@ /* scan sequence records */ for ( ; num_sequences > 0; num_sequences-- ) - otl_sequence_validate( table + OTL_NEXT_USHORT( p ), valid ); + otl_sequence_validate( table + OTL_NEXT_USHORT( p ), glyph_count, + valid ); } break; @@ -329,28 +355,35 @@ static void otl_alternate_set_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; - OTL_UInt count; + OTL_UInt num_glyphs; OTL_CHECK( 2 ); - count = OTL_NEXT_USHORT( p ); + num_glyphs = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * count ); + OTL_CHECK( num_glyphs * 2 ); - /* XXX: check glyph indices */ + for ( ; num_glyphs > 0; num_glyphs-- ) + if ( OTL_NEXT_USHORT( p ) >= glyph_count ) + OTL_INVALID_DATA; } static void otl_gsub_lookup3_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( lookup_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -367,11 +400,12 @@ otl_coverage_validate( table + coverage, valid ); - OTL_CHECK( 2 * num_alternate_sets ); + OTL_CHECK( num_alternate_sets * 2 ); /* scan alternate set records */ for ( ; num_alternate_sets > 0; num_alternate_sets-- ) - otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ), valid ); + otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ), + glyph_count, valid ); } break; @@ -442,6 +476,7 @@ static void otl_ligature_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -455,14 +490,19 @@ if ( num_components == 0 ) OTL_INVALID_DATA; - OTL_CHECK( 2 * ( num_components - 1 ) ); + num_components--; - /* XXX: check glyph indices */ + OTL_CHECK( num_components * 2 ); + + for ( ; num_components > 0; num_components-- ) + if ( OTL_NEXT_USHORT( p ) >= glyph_count ) + OTL_INVALID_DATA; } static void otl_ligature_set_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -472,21 +512,26 @@ OTL_CHECK( 2 ); num_ligatures = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_ligatures ); + OTL_CHECK( num_ligatures * 2 ); /* scan ligature records */ for ( ; num_ligatures > 0; num_ligatures-- ) - otl_ligature_validate( table + OTL_NEXT_USHORT( p ), valid ); + otl_ligature_validate( table + OTL_NEXT_USHORT( p ), glyph_count, + valid ); } static void otl_gsub_lookup4_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( lookup_count); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -503,11 +548,12 @@ otl_coverage_validate( table + coverage, valid ); - OTL_CHECK( 2 * num_ligsets ); + OTL_CHECK( num_ligsets * 2 ); /* scan ligature set records */ for ( ; num_ligsets > 0; num_ligsets-- ) - otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ), valid ); + otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ), + glyph_count, valid ); } break; @@ -525,8 +571,10 @@ /*************************************************************************/ /*************************************************************************/ + /* used for both format 1 and 2 */ static void otl_sub_rule_validate( OTL_Bytes table, + OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -542,12 +590,25 @@ OTL_CHECK( ( num_glyphs - 1 ) * 2 + num_subst * 4 ); - /* XXX: check glyph indices and subst lookups */ + for ( ; num_subst > 0; num_subst-- ) + { + if ( OTL_NEXT_USHORT( p ) >= num_glyphs ) + OTL_INVALID_DATA; + + if ( OTL_NEXT_USHORT( p ) >= lookup_count ) + OTL_INVALID_DATA; + } + + /* no need to check glyph indices/classes used as input for this */ + /* context rule since even invalid glyph indices/classes return a */ + /* meaningful result */ } + /* used for both format 1 and 2 */ static void otl_sub_rule_set_validate( OTL_Bytes table, + OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -557,64 +618,26 @@ OTL_CHECK( 2 ); num_subrules = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_subrules ); - - /* scan sub rule records */ - for ( ; num_subrules > 0; num_subrules-- ) - otl_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid ); - } - - - static void - otl_sub_class_rule_validate( OTL_Bytes table, - OTL_Validator valid ) - { - OTL_Bytes p = table; - OTL_UInt num_glyphs, num_subst; - - - OTL_CHECK( 4 ); - num_glyphs = OTL_NEXT_USHORT( p ); - num_subst = OTL_NEXT_USHORT( p ); - - if ( num_glyphs == 0 ) - OTL_INVALID_DATA; - - OTL_CHECK( ( num_glyphs - 1 ) * 2 + num_subst * 4 ); - - /* XXX: check subst lookups */ - - /* no need to check glyph indices used as input for this context */ - /* rule since even invalid glyph indices return a meaningful result */ - } - - - static void - otl_sub_class_rule_set_validate( OTL_Bytes table, - OTL_Validator valid ) - { - OTL_Bytes p = table; - OTL_UInt num_subrules; - - - OTL_CHECK( 2 ); - num_subrules = OTL_NEXT_USHORT( p ); - - OTL_CHECK( 2 * num_subrules ); + OTL_CHECK( num_subrules * 2 ); /* scan subrule records */ for ( ; num_subrules > 0; num_subrules-- ) - otl_sub_class_rule_validate( table + OTL_NEXT_USHORT( p ), valid ); + otl_sub_rule_validate( table + OTL_NEXT_USHORT( p ), lookup_count, + valid ); } static void otl_gsub_lookup5_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( glyph_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -631,11 +654,12 @@ otl_coverage_validate( table + coverage, valid ); - OTL_CHECK( 2 * num_subrulesets ); + OTL_CHECK( num_subrulesets * 2 ); /* scan subrule set records */ for ( ; num_subrulesets > 0; num_subrulesets-- ) - otl_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ), valid ); + otl_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ), + lookup_count, valid ); } break; @@ -652,30 +676,42 @@ otl_coverage_validate( table + coverage, valid ); otl_class_definition_validate( table + class_def, valid ); - OTL_CHECK( 2 * num_subclass_sets ); + OTL_CHECK( num_subclass_sets * 2 ); /* scan subclass set records */ for ( ; num_subclass_sets > 0; num_subclass_sets-- ) - otl_sub_class_rule_set_validate( table + OTL_NEXT_USHORT( p ), - valid ); + { + OTL_UInt offset = OTL_NEXT_USHORT( p ); + + + if ( offset ) + otl_sub_rule_set_validate( table + offset, lookup_count, valid ); + } } break; case 3: { - OTL_UInt num_glyphs, num_subst; + OTL_UInt num_glyphs, num_subst, count; OTL_CHECK( 4 ); num_glyphs = OTL_NEXT_USHORT( p ); num_subst = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_glyphs + 4 * num_subst ); + OTL_CHECK( num_glyphs * 2 + num_subst * 4 ); - for ( ; num_glyphs > 0; num_glyphs-- ) + for ( count = num_glyphs; count > 0; count-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); - /* XXX: check subst lookups */ + for ( ; num_subst > 0; num_subst-- ) + { + if ( OTL_NEXT_USHORT( p ) >= num_glyphs ) + OTL_INVALID_DATA; + + if ( OTL_NEXT_USHORT( p ) >= lookup_count ) + OTL_INVALID_DATA; + } } break; @@ -696,6 +732,7 @@ /* used for both format 1 and 2 */ static void otl_chain_sub_rule_validate( OTL_Bytes table, + OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -706,33 +743,42 @@ OTL_CHECK( 2 ); num_backtrack_glyphs = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_backtrack_glyphs + 2 ); - p += 2 * num_backtrack_glyphs; + OTL_CHECK( num_backtrack_glyphs * 2 + 2 ); + p += num_backtrack_glyphs * 2; num_input_glyphs = OTL_NEXT_USHORT( p ); if ( num_input_glyphs == 0 ) OTL_INVALID_DATA; - OTL_CHECK( 2 * num_input_glyphs ); - p += 2 * ( num_input_glyphs - 1 ); + OTL_CHECK( num_input_glyphs * 2 ); + p += ( num_input_glyphs - 1 ) * 2; num_lookahead_glyphs = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_lookahead_glyphs + 2 ); - p += 2 * num_lookahead_glyphs; + OTL_CHECK( num_lookahead_glyphs * 2 + 2 ); + p += num_lookahead_glyphs * 2; num_subst = OTL_NEXT_USHORT( p ); - OTL_CHECK( 4 * num_subst ); + OTL_CHECK( num_subst * 4 ); - /* XXX: check subst lookups */ + for ( ; num_subst > 0; num_subst-- ) + { + if ( OTL_NEXT_USHORT( p ) >= num_input_glyphs ) + OTL_INVALID_DATA; - /* no need to check glyph indices used as input for this context */ - /* rule since even invalid glyph indices return a meaningful result */ + if ( OTL_NEXT_USHORT( p ) >= lookup_count ) + OTL_INVALID_DATA; + } + + /* no need to check glyph indices/classes used as input for this */ + /* context rule since even invalid glyph indices/classes return a */ + /* meaningful result */ } /* used for both format 1 and 2 */ static void otl_chain_sub_rule_set_validate( OTL_Bytes table, + OTL_UInt lookup_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -742,21 +788,26 @@ OTL_CHECK( 2 ); num_chain_subrules = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_chain_subrules ); + OTL_CHECK( num_chain_subrules * 2 ); - /* scan chain subrule records */ + /* scan chain subst rule records */ for ( ; num_chain_subrules > 0; num_chain_subrules-- ) - otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid ); + otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), + lookup_count, valid ); } static void otl_gsub_lookup6_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; OTL_UInt format; + OTL_UNUSED( glyph_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -773,12 +824,12 @@ otl_coverage_validate( table + coverage, valid ); - OTL_CHECK( 2 * num_chain_subrulesets ); + OTL_CHECK( num_chain_subrulesets * 2 ); /* scan chain subrule set records */ for ( ; num_chain_subrulesets > 0; num_chain_subrulesets-- ) otl_chain_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ), - valid ); + lookup_count, valid ); } break; @@ -801,37 +852,43 @@ otl_class_definition_validate( table + input_class, valid ); otl_class_definition_validate( table + ahead_class, valid ); - OTL_CHECK( 2 * num_chain_subclass_sets ); + OTL_CHECK( num_chain_subclass_sets * 2 ); /* scan chain subclass set records */ for ( ; num_chain_subclass_sets > 0; num_chain_subclass_sets-- ) - otl_chain_sub_rule_set_validate( table + OTL_NEXT_USHORT( p ), - valid ); + { + OTL_UInt offset = OTL_NEXT_USHORT( p ); + + + if ( offset ) + otl_chain_sub_rule_set_validate( table + offset, lookup_count, + valid ); + } } break; case 3: { OTL_UInt num_backtrack_glyphs, num_input_glyphs; - OTL_UInt num_lookahead_glyphs, num_subst; + OTL_UInt num_lookahead_glyphs, num_subst, count; OTL_CHECK( 2 ); num_backtrack_glyphs = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_backtrack_glyphs + 2 ); + OTL_CHECK( num_backtrack_glyphs * 2 + 2 ); for ( ; num_backtrack_glyphs > 0; num_backtrack_glyphs-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); num_input_glyphs = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_input_glyphs + 2 ); + OTL_CHECK( num_input_glyphs * 2 + 2 ); - for ( ; num_input_glyphs > 0; num_input_glyphs-- ) + for ( count = num_input_glyphs; count > 0; count-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); num_lookahead_glyphs = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_lookahead_glyphs + 2 ); + OTL_CHECK( num_lookahead_glyphs * 2 + 2 ); for ( ; num_lookahead_glyphs > 0; num_lookahead_glyphs-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); @@ -839,7 +896,14 @@ num_subst = OTL_NEXT_USHORT( p ); OTL_CHECK( num_subst * 4 ); - /* XXX: check subst lookups */ + for ( ; num_subst > 0; num_subst-- ) + { + if ( OTL_NEXT_USHORT( p ) >= num_input_glyphs ) + OTL_INVALID_DATA; + + if ( OTL_NEXT_USHORT( p ) >= lookup_count ) + OTL_INVALID_DATA; + } } break; @@ -859,6 +923,8 @@ static void otl_gsub_lookup7_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -883,7 +949,7 @@ OTL_INVALID_DATA; validate = otl_gsub_validate_funcs[lookup_type - 1]; - validate( table + lookup_offset, valid ); + validate( table + lookup_offset, lookup_count, glyph_count, valid ); } break; @@ -903,12 +969,16 @@ static void otl_gsub_lookup8_validate( OTL_Bytes table, + OTL_UInt lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table, coverage; OTL_UInt format; OTL_UInt num_backtrack_glyphs, num_lookahead_glyphs, num_glyphs; + OTL_UNUSED( lookup_count ); + OTL_CHECK( 2 ); format = OTL_NEXT_USHORT( p ); @@ -922,13 +992,13 @@ otl_coverage_validate( coverage, valid ); - OTL_CHECK( 2 * num_backtrack_glyphs + 2 ); + OTL_CHECK( num_backtrack_glyphs * 2 + 2 ); for ( ; num_backtrack_glyphs > 0; num_backtrack_glyphs-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); num_lookahead_glyphs = OTL_NEXT_USHORT( p ); - OTL_CHECK( 2 * num_lookahead_glyphs + 2 ); + OTL_CHECK( num_lookahead_glyphs * 2 + 2 ); for ( ; num_lookahead_glyphs > 0; num_lookahead_glyphs-- ) otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid ); @@ -937,9 +1007,12 @@ if ( num_glyphs != otl_coverage_get_count( coverage ) ) OTL_INVALID_DATA; - OTL_CHECK( 2 * num_glyphs ); + OTL_CHECK( num_glyphs * 2 ); + + for ( ; num_glyphs > 0; num_glyphs-- ) + if ( OTL_NEXT_USHORT( p ) >= glyph_count ) + OTL_INVALID_DATA; - /* XXX: check glyph indices */ break; default: @@ -971,6 +1044,7 @@ OTL_LOCALDEF( void ) otl_gsub_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -987,7 +1061,7 @@ lookups = OTL_NEXT_USHORT( p ); otl_lookup_list_validate( table + lookups, 8, otl_gsub_validate_funcs, - valid ); + glyph_count, valid ); otl_feature_list_validate( table + features, table + lookups, valid ); otl_script_list_validate( table + scripts, table + features, valid ); } diff --git a/src/otlayout/otlgsub.h b/src/otlayout/otlgsub.h index 46532c3cd..027d343eb 100644 --- a/src/otlayout/otlgsub.h +++ b/src/otlayout/otlgsub.h @@ -40,6 +40,7 @@ OTL_BEGIN_HEADER OTL_LOCAL( void ) otl_gsub_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ); diff --git a/src/otlayout/otljstf.c b/src/otlayout/otljstf.c index 01f06697a..3f07f7ff2 100644 --- a/src/otlayout/otljstf.c +++ b/src/otlayout/otljstf.c @@ -23,6 +23,7 @@ static void otl_jstf_extender_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -35,7 +36,9 @@ OTL_CHECK( num_glyphs * 2 ); - /* XXX: check glyph indices */ + for ( ; num_glyphs > 0; num_glyphs-- ) + if ( OTL_NEXT_USHORT( p ) >= glyph_count ) + OTL_INVALID_DATA; } @@ -63,6 +66,7 @@ static void otl_jstf_max_validate( OTL_Bytes table, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -76,7 +80,8 @@ /* scan subtable records */ for ( ; num_lookups > 0; num_lookups-- ) /* XXX: check lookup types? */ - otl_gpos_subtable_validate( table + OTL_NEXT_USHORT( p ), valid ); + otl_gpos_subtable_validate( table + OTL_NEXT_USHORT( p ), glyph_count, + valid ); } @@ -84,6 +89,7 @@ otl_jstf_priority_validate( OTL_Bytes table, OTL_UInt gsub_lookup_count, OTL_UInt gpos_lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -117,7 +123,7 @@ /* shrinkage JSTF max */ val = OTL_NEXT_USHORT( p ); if ( val ) - otl_jstf_max_validate( table + val, valid ); + otl_jstf_max_validate( table + val, glyph_count, valid ); /* extension GSUB enable/disable */ val = OTL_NEXT_USHORT( p ); @@ -144,7 +150,7 @@ /* extension JSTF max */ val = OTL_NEXT_USHORT( p ); if ( val ) - otl_jstf_max_validate( table + val, valid ); + otl_jstf_max_validate( table + val, glyph_count, valid ); } @@ -152,6 +158,7 @@ otl_jstf_lang_validate( OTL_Bytes table, OTL_UInt gsub_lookup_count, OTL_UInt gpos_lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -166,7 +173,7 @@ for ( ; num_priorities > 0; num_priorities-- ) otl_jstf_priority_validate( table + OTL_NEXT_USHORT( p ), gsub_lookup_count, gpos_lookup_count, - valid ); + glyph_count, valid ); } @@ -174,6 +181,7 @@ otl_jstf_script_validate( OTL_Bytes table, OTL_UInt gsub_lookup_count, OTL_UInt gpos_lookup_count, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -186,11 +194,12 @@ num_langsys = OTL_NEXT_USHORT( p ); if ( extender ) - otl_jstf_extender_validate( table + extender, valid ); + otl_jstf_extender_validate( table + extender, glyph_count, valid ); if ( default_lang ) otl_jstf_lang_validate( table + default_lang, - gsub_lookup_count, gpos_lookup_count, valid ); + gsub_lookup_count, gpos_lookup_count, + glyph_count, valid ); OTL_CHECK( 6 * num_langsys ); @@ -200,7 +209,8 @@ p += 4; /* skip tag */ otl_jstf_lang_validate( table + OTL_NEXT_USHORT( p ), - gsub_lookup_count, gpos_lookup_count, valid ); + gsub_lookup_count, gpos_lookup_count, + glyph_count, valid ); } } @@ -209,6 +219,7 @@ otl_jstf_validate( OTL_Bytes table, OTL_Bytes gsub, OTL_Bytes gpos, + OTL_UInt glyph_count, OTL_Validator valid ) { OTL_Bytes p = table; @@ -239,7 +250,8 @@ p += 4; /* skip tag */ otl_jstf_script_validate( table + OTL_NEXT_USHORT( p ), - gsub_lookup_count, gpos_lookup_count, valid ); + gsub_lookup_count, gpos_lookup_count, + glyph_count, valid ); } } diff --git a/src/otlayout/otljstf.h b/src/otlayout/otljstf.h index 16953bf35..e15e4aa7f 100644 --- a/src/otlayout/otljstf.h +++ b/src/otlayout/otljstf.h @@ -25,13 +25,14 @@ OTL_BEGIN_HEADER - /* validate JSTF table */ - /* GSUB and GPOS tables must already be validated; if table is */ - /* missing, set value to 0 */ + /* validate JSTF table */ + /* GSUB and GPOS tables should already be validated; */ + /* if missing, set corresponding argument to 0 */ OTL_LOCAL( void ) otl_jstf_validate( OTL_Bytes table, OTL_Bytes gsub, OTL_Bytes gpos, + OTL_UInt glyph_count, OTL_Validator valid );