From fc55291b1cbc145da166614f3d7726389ab44a2c Mon Sep 17 00:00:00 2001 From: Jany Belluz Date: Thu, 4 Nov 2021 11:07:43 +0000 Subject: [PATCH] [truetype] Fix handling of packed deltas in Variation Fonts. * src/truetype/ttgxvar (ft_var_readpackeddeltas): Don't expect the number of bytes used to encode the deltas to be higher than the number of encoded values. The specification allows a very compact encoding; for example, a list of 200 zeros can be encoded with just a couple of bytes. We now count the consumed bytes to make sure to not read more than expected. --- src/truetype/ttgxvar.c | 53 +++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c index e4da8105b..48b79efa1 100644 --- a/src/truetype/ttgxvar.c +++ b/src/truetype/ttgxvar.c @@ -264,55 +264,80 @@ FT_Fixed *deltas = NULL; FT_UInt runcnt, cnt; FT_UInt i, j; + FT_UInt bytes_used; FT_Memory memory = stream->memory; FT_Error error = FT_Err_Ok; FT_UNUSED( error ); - if ( delta_cnt > size ) - { - FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n" )); - return NULL; - } - if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) return NULL; - i = 0; - while ( i < delta_cnt ) + i = 0; + bytes_used = 0; + + while ( i < delta_cnt && bytes_used < size ) { runcnt = FT_GET_BYTE(); cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK; + bytes_used++; + if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) { - /* `runcnt' zeroes get added */ + /* `cnt` + 1 zeroes get added */ for ( j = 0; j <= cnt && i < delta_cnt; j++ ) deltas[i++] = 0; } else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) { - /* `runcnt' shorts from the stack */ + /* `cnt` + 1 shorts from the stack */ + bytes_used += 2 * ( cnt + 1 ); + if ( bytes_used > size ) + { + FT_TRACE1(( "ft_var_readpackeddeltas:" + " number of short deltas too large\n" )); + goto Fail; + } + for ( j = 0; j <= cnt && i < delta_cnt; j++ ) deltas[i++] = FT_intToFixed( FT_GET_SHORT() ); } else { - /* `runcnt' signed bytes from the stack */ + /* `cnt` + 1 signed bytes from the stack */ + bytes_used += cnt + 1; + if ( bytes_used > size ) + { + FT_TRACE1(( "ft_var_readpackeddeltas:" + " number of byte deltas too large\n" )); + goto Fail; + } + for ( j = 0; j <= cnt && i < delta_cnt; j++ ) deltas[i++] = FT_intToFixed( FT_GET_CHAR() ); } if ( j <= cnt ) { - /* bad format */ - FT_FREE( deltas ); - return NULL; + FT_TRACE1(( "ft_var_readpackeddeltas:" + " number of deltas too large\n" )); + goto Fail; } } + if ( i < delta_cnt ) + { + FT_TRACE1(( "ft_var_readpackeddeltas: not enough deltas\n" )); + goto Fail; + } + return deltas; + + Fail: + FT_FREE( deltas ); + return NULL; }