[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.
This commit is contained in:
Jany Belluz 2021-11-04 11:07:43 +00:00 committed by Werner Lemberg
parent 9ed5332fe6
commit fc55291b1c
1 changed files with 39 additions and 14 deletions

View File

@ -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;
}