summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJany Belluz <jany.belluz@daltonmaag.com>2021-11-04 11:07:43 +0000
committerWerner Lemberg <wl@gnu.org>2021-11-05 13:53:45 +0100
commitfc55291b1cbc145da166614f3d7726389ab44a2c (patch)
tree9dbaf952d3b1e2b4f52437aad00a00187a529d1b
parent9ed5332fe632ada7de8fd345c9ef579b678c4042 (diff)
downloadfreetype2-fc55291b1cbc145da166614f3d7726389ab44a2c.tar.gz
[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.
-rw-r--r--src/truetype/ttgxvar.c53
1 files 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;
}