[truetype/GX] Read points and deltas more carefully.
Hopefully fixes newly introduced buffer overflows: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=70807 https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=70809 * src/truetype/ttgxvar.c (ft_var_readpacked{points,deltas}): Explicitly check stream frame limits and modify run counting.
This commit is contained in:
parent
104f85448d
commit
5e116bb0dc
@ -129,9 +129,6 @@
|
||||
* stream ::
|
||||
* The data stream.
|
||||
*
|
||||
* size ::
|
||||
* The size of the table holding the data.
|
||||
*
|
||||
* @Output:
|
||||
* point_cnt ::
|
||||
* The number of points read. A zero value means that
|
||||
@ -144,12 +141,11 @@
|
||||
*/
|
||||
static FT_UShort*
|
||||
ft_var_readpackedpoints( FT_Stream stream,
|
||||
FT_ULong size,
|
||||
FT_UInt *point_cnt )
|
||||
{
|
||||
FT_UShort *points = NULL;
|
||||
FT_UInt n;
|
||||
FT_UInt runcnt;
|
||||
FT_UInt runcnt, cnt;
|
||||
FT_UInt i, j;
|
||||
FT_UShort first;
|
||||
FT_Byte* p;
|
||||
@ -170,59 +166,60 @@
|
||||
n |= FT_GET_BYTE();
|
||||
}
|
||||
|
||||
if ( n > size )
|
||||
{
|
||||
FT_TRACE1(( "ft_var_readpackedpoints: number of points too large\n" ));
|
||||
if ( FT_QNEW_ARRAY( points, n ) )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* in the nested loops below we increase `i' twice; */
|
||||
/* it is faster to simply allocate one more slot */
|
||||
/* than to add another test within the loop */
|
||||
if ( FT_QNEW_ARRAY( points, n + 1 ) )
|
||||
return NULL;
|
||||
|
||||
*point_cnt = n;
|
||||
|
||||
p = stream->cursor;
|
||||
first = 0;
|
||||
i = 0;
|
||||
while ( i < n )
|
||||
{
|
||||
if ( p >= stream->limit )
|
||||
goto Fail;
|
||||
|
||||
runcnt = FT_NEXT_BYTE( p );
|
||||
cnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK;
|
||||
|
||||
/* first point not included in run count */
|
||||
cnt++;
|
||||
if ( i + cnt > n )
|
||||
cnt = n - i;
|
||||
|
||||
if ( runcnt & GX_PT_POINTS_ARE_WORDS )
|
||||
{
|
||||
runcnt &= GX_PT_POINT_RUN_COUNT_MASK;
|
||||
first += FT_NEXT_USHORT( p );
|
||||
points[i++] = first;
|
||||
if ( p + 2 * cnt > stream->limit )
|
||||
goto Fail;
|
||||
|
||||
/* first point not included in run count */
|
||||
for ( j = 0; j < runcnt; j++ )
|
||||
for ( j = 0; j < cnt; j++ )
|
||||
{
|
||||
first += FT_NEXT_USHORT( p );
|
||||
points[i++] = first;
|
||||
if ( i >= n )
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
first += FT_NEXT_BYTE( p );
|
||||
points[i++] = first;
|
||||
if ( p + cnt > stream->limit )
|
||||
goto Fail;
|
||||
|
||||
for ( j = 0; j < runcnt; j++ )
|
||||
for ( j = 0; j < cnt; j++ )
|
||||
{
|
||||
first += FT_NEXT_BYTE( p );
|
||||
points[i++] = first;
|
||||
if ( i >= n )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stream->cursor = p;
|
||||
|
||||
*point_cnt = n;
|
||||
|
||||
return points;
|
||||
|
||||
Fail:
|
||||
FT_TRACE1(( "ft_var_readpackedpoints: invalid table\n" ));
|
||||
|
||||
FT_FREE( points );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -244,9 +241,6 @@
|
||||
* stream ::
|
||||
* The data stream.
|
||||
*
|
||||
* size ::
|
||||
* The size of the table holding the data.
|
||||
*
|
||||
* delta_cnt ::
|
||||
* The number of deltas to be read.
|
||||
*
|
||||
@ -262,13 +256,11 @@
|
||||
*/
|
||||
static FT_Fixed*
|
||||
ft_var_readpackeddeltas( FT_Stream stream,
|
||||
FT_ULong size,
|
||||
FT_UInt delta_cnt )
|
||||
{
|
||||
FT_Fixed *deltas = NULL;
|
||||
FT_UInt runcnt, cnt;
|
||||
FT_UInt i, j;
|
||||
FT_UInt bytes_used;
|
||||
FT_Byte* p;
|
||||
FT_Memory memory = stream->memory;
|
||||
FT_Error error;
|
||||
@ -277,64 +269,44 @@
|
||||
if ( FT_QNEW_ARRAY( deltas, delta_cnt ) )
|
||||
return NULL;
|
||||
|
||||
p = stream->cursor;
|
||||
i = 0;
|
||||
bytes_used = 0;
|
||||
|
||||
while ( i < delta_cnt && bytes_used < size )
|
||||
p = stream->cursor;
|
||||
i = 0;
|
||||
while ( i < delta_cnt )
|
||||
{
|
||||
if ( p >= stream->limit )
|
||||
{
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
runcnt = FT_NEXT_BYTE( p );
|
||||
cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK;
|
||||
|
||||
bytes_used++;
|
||||
/* first point not included in run count */
|
||||
cnt++;
|
||||
if ( i + cnt > delta_cnt )
|
||||
cnt = delta_cnt - i;
|
||||
|
||||
if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
|
||||
{
|
||||
/* `cnt` + 1 zeroes get added */
|
||||
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
|
||||
for ( j = 0; j < cnt; j++ )
|
||||
deltas[i++] = 0;
|
||||
}
|
||||
else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
|
||||
{
|
||||
/* `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" ));
|
||||
if ( p + 2 * cnt > stream->limit )
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
|
||||
for ( j = 0; j < cnt; j++ )
|
||||
deltas[i++] = FT_intToFixed( FT_NEXT_SHORT( p ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* `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" ));
|
||||
if ( p + cnt > stream->limit )
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
|
||||
for ( j = 0; j < cnt; j++ )
|
||||
deltas[i++] = FT_intToFixed( FT_NEXT_CHAR( p ) );
|
||||
}
|
||||
|
||||
if ( j <= cnt )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
stream->cursor = p;
|
||||
@ -342,6 +314,8 @@
|
||||
return deltas;
|
||||
|
||||
Fail:
|
||||
FT_TRACE1(( "ft_var_readpackeddeltas: invalid table\n" ));
|
||||
|
||||
FT_FREE( deltas );
|
||||
return NULL;
|
||||
}
|
||||
@ -3612,9 +3586,8 @@
|
||||
|
||||
FT_Stream_SeekSet( stream, offsetToData );
|
||||
|
||||
sharedpoints = ft_var_readpackedpoints( stream,
|
||||
table_len,
|
||||
&spoint_count );
|
||||
sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
|
||||
|
||||
offsetToData = FT_Stream_FTell( stream );
|
||||
|
||||
FT_Stream_SeekSet( stream, here );
|
||||
@ -3688,9 +3661,7 @@
|
||||
|
||||
if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
|
||||
{
|
||||
localpoints = ft_var_readpackedpoints( stream,
|
||||
table_len,
|
||||
&point_count );
|
||||
localpoints = ft_var_readpackedpoints( stream, &point_count );
|
||||
points = localpoints;
|
||||
}
|
||||
else
|
||||
@ -3701,7 +3672,6 @@
|
||||
}
|
||||
|
||||
deltas = ft_var_readpackeddeltas( stream,
|
||||
table_len,
|
||||
point_count == 0 ? face->cvt_size
|
||||
: point_count );
|
||||
|
||||
@ -4150,9 +4120,8 @@
|
||||
|
||||
FT_Stream_SeekSet( stream, offsetToData );
|
||||
|
||||
sharedpoints = ft_var_readpackedpoints( stream,
|
||||
blend->gvar_size,
|
||||
&spoint_count );
|
||||
sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
|
||||
|
||||
offsetToData = FT_Stream_FTell( stream );
|
||||
|
||||
FT_Stream_SeekSet( stream, here );
|
||||
@ -4236,9 +4205,7 @@
|
||||
|
||||
if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
|
||||
{
|
||||
localpoints = ft_var_readpackedpoints( stream,
|
||||
blend->gvar_size,
|
||||
&point_count );
|
||||
localpoints = ft_var_readpackedpoints( stream, &point_count );
|
||||
points = localpoints;
|
||||
}
|
||||
else
|
||||
@ -4248,11 +4215,9 @@
|
||||
}
|
||||
|
||||
deltas_x = ft_var_readpackeddeltas( stream,
|
||||
blend->gvar_size,
|
||||
point_count == 0 ? n_points
|
||||
: point_count );
|
||||
deltas_y = ft_var_readpackeddeltas( stream,
|
||||
blend->gvar_size,
|
||||
point_count == 0 ? n_points
|
||||
: point_count );
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user