mirror of https://github.com/freetype/freetype
[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 ::
|
* stream ::
|
||||||
* The data stream.
|
* The data stream.
|
||||||
*
|
*
|
||||||
* size ::
|
|
||||||
* The size of the table holding the data.
|
|
||||||
*
|
|
||||||
* @Output:
|
* @Output:
|
||||||
* point_cnt ::
|
* point_cnt ::
|
||||||
* The number of points read. A zero value means that
|
* The number of points read. A zero value means that
|
||||||
|
@ -144,12 +141,11 @@
|
||||||
*/
|
*/
|
||||||
static FT_UShort*
|
static FT_UShort*
|
||||||
ft_var_readpackedpoints( FT_Stream stream,
|
ft_var_readpackedpoints( FT_Stream stream,
|
||||||
FT_ULong size,
|
|
||||||
FT_UInt *point_cnt )
|
FT_UInt *point_cnt )
|
||||||
{
|
{
|
||||||
FT_UShort *points = NULL;
|
FT_UShort *points = NULL;
|
||||||
FT_UInt n;
|
FT_UInt n;
|
||||||
FT_UInt runcnt;
|
FT_UInt runcnt, cnt;
|
||||||
FT_UInt i, j;
|
FT_UInt i, j;
|
||||||
FT_UShort first;
|
FT_UShort first;
|
||||||
FT_Byte* p;
|
FT_Byte* p;
|
||||||
|
@ -170,59 +166,60 @@
|
||||||
n |= FT_GET_BYTE();
|
n |= FT_GET_BYTE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( n > size )
|
if ( FT_QNEW_ARRAY( points, n ) )
|
||||||
{
|
|
||||||
FT_TRACE1(( "ft_var_readpackedpoints: number of points too large\n" ));
|
|
||||||
return NULL;
|
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;
|
p = stream->cursor;
|
||||||
first = 0;
|
first = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
while ( i < n )
|
while ( i < n )
|
||||||
{
|
{
|
||||||
|
if ( p >= stream->limit )
|
||||||
|
goto Fail;
|
||||||
|
|
||||||
runcnt = FT_NEXT_BYTE( p );
|
runcnt = FT_NEXT_BYTE( p );
|
||||||
if ( runcnt & GX_PT_POINTS_ARE_WORDS )
|
cnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK;
|
||||||
{
|
|
||||||
runcnt &= GX_PT_POINT_RUN_COUNT_MASK;
|
|
||||||
first += FT_NEXT_USHORT( p );
|
|
||||||
points[i++] = first;
|
|
||||||
|
|
||||||
/* first point not included in run count */
|
/* first point not included in run count */
|
||||||
for ( j = 0; j < runcnt; j++ )
|
cnt++;
|
||||||
|
if ( i + cnt > n )
|
||||||
|
cnt = n - i;
|
||||||
|
|
||||||
|
if ( runcnt & GX_PT_POINTS_ARE_WORDS )
|
||||||
|
{
|
||||||
|
if ( p + 2 * cnt > stream->limit )
|
||||||
|
goto Fail;
|
||||||
|
|
||||||
|
for ( j = 0; j < cnt; j++ )
|
||||||
{
|
{
|
||||||
first += FT_NEXT_USHORT( p );
|
first += FT_NEXT_USHORT( p );
|
||||||
points[i++] = first;
|
points[i++] = first;
|
||||||
if ( i >= n )
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
first += FT_NEXT_BYTE( p );
|
if ( p + cnt > stream->limit )
|
||||||
points[i++] = first;
|
goto Fail;
|
||||||
|
|
||||||
for ( j = 0; j < runcnt; j++ )
|
for ( j = 0; j < cnt; j++ )
|
||||||
{
|
{
|
||||||
first += FT_NEXT_BYTE( p );
|
first += FT_NEXT_BYTE( p );
|
||||||
points[i++] = first;
|
points[i++] = first;
|
||||||
if ( i >= n )
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->cursor = p;
|
stream->cursor = p;
|
||||||
|
|
||||||
|
*point_cnt = n;
|
||||||
|
|
||||||
return points;
|
return points;
|
||||||
|
|
||||||
|
Fail:
|
||||||
|
FT_TRACE1(( "ft_var_readpackedpoints: invalid table\n" ));
|
||||||
|
|
||||||
|
FT_FREE( points );
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -244,9 +241,6 @@
|
||||||
* stream ::
|
* stream ::
|
||||||
* The data stream.
|
* The data stream.
|
||||||
*
|
*
|
||||||
* size ::
|
|
||||||
* The size of the table holding the data.
|
|
||||||
*
|
|
||||||
* delta_cnt ::
|
* delta_cnt ::
|
||||||
* The number of deltas to be read.
|
* The number of deltas to be read.
|
||||||
*
|
*
|
||||||
|
@ -262,13 +256,11 @@
|
||||||
*/
|
*/
|
||||||
static FT_Fixed*
|
static FT_Fixed*
|
||||||
ft_var_readpackeddeltas( FT_Stream stream,
|
ft_var_readpackeddeltas( FT_Stream stream,
|
||||||
FT_ULong size,
|
|
||||||
FT_UInt delta_cnt )
|
FT_UInt delta_cnt )
|
||||||
{
|
{
|
||||||
FT_Fixed *deltas = NULL;
|
FT_Fixed *deltas = NULL;
|
||||||
FT_UInt runcnt, cnt;
|
FT_UInt runcnt, cnt;
|
||||||
FT_UInt i, j;
|
FT_UInt i, j;
|
||||||
FT_UInt bytes_used;
|
|
||||||
FT_Byte* p;
|
FT_Byte* p;
|
||||||
FT_Memory memory = stream->memory;
|
FT_Memory memory = stream->memory;
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
|
@ -279,62 +271,42 @@
|
||||||
|
|
||||||
p = stream->cursor;
|
p = stream->cursor;
|
||||||
i = 0;
|
i = 0;
|
||||||
bytes_used = 0;
|
while ( i < delta_cnt )
|
||||||
|
|
||||||
while ( i < delta_cnt && bytes_used < size )
|
|
||||||
{
|
{
|
||||||
|
if ( p >= stream->limit )
|
||||||
|
{
|
||||||
|
goto Fail;
|
||||||
|
}
|
||||||
|
|
||||||
runcnt = FT_NEXT_BYTE( p );
|
runcnt = FT_NEXT_BYTE( p );
|
||||||
cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK;
|
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 )
|
if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
|
||||||
{
|
{
|
||||||
/* `cnt` + 1 zeroes get added */
|
for ( j = 0; j < cnt; j++ )
|
||||||
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
|
|
||||||
deltas[i++] = 0;
|
deltas[i++] = 0;
|
||||||
}
|
}
|
||||||
else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
|
else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
|
||||||
{
|
{
|
||||||
/* `cnt` + 1 shorts from the stack */
|
if ( p + 2 * cnt > stream->limit )
|
||||||
bytes_used += 2 * ( cnt + 1 );
|
|
||||||
if ( bytes_used > size )
|
|
||||||
{
|
|
||||||
FT_TRACE1(( "ft_var_readpackeddeltas:"
|
|
||||||
" number of short deltas too large\n" ));
|
|
||||||
goto Fail;
|
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 ) );
|
deltas[i++] = FT_intToFixed( FT_NEXT_SHORT( p ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* `cnt` + 1 signed bytes from the stack */
|
if ( p + cnt > stream->limit )
|
||||||
bytes_used += cnt + 1;
|
|
||||||
if ( bytes_used > size )
|
|
||||||
{
|
|
||||||
FT_TRACE1(( "ft_var_readpackeddeltas:"
|
|
||||||
" number of byte deltas too large\n" ));
|
|
||||||
goto Fail;
|
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 ) );
|
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;
|
stream->cursor = p;
|
||||||
|
@ -342,6 +314,8 @@
|
||||||
return deltas;
|
return deltas;
|
||||||
|
|
||||||
Fail:
|
Fail:
|
||||||
|
FT_TRACE1(( "ft_var_readpackeddeltas: invalid table\n" ));
|
||||||
|
|
||||||
FT_FREE( deltas );
|
FT_FREE( deltas );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -3612,9 +3586,8 @@
|
||||||
|
|
||||||
FT_Stream_SeekSet( stream, offsetToData );
|
FT_Stream_SeekSet( stream, offsetToData );
|
||||||
|
|
||||||
sharedpoints = ft_var_readpackedpoints( stream,
|
sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
|
||||||
table_len,
|
|
||||||
&spoint_count );
|
|
||||||
offsetToData = FT_Stream_FTell( stream );
|
offsetToData = FT_Stream_FTell( stream );
|
||||||
|
|
||||||
FT_Stream_SeekSet( stream, here );
|
FT_Stream_SeekSet( stream, here );
|
||||||
|
@ -3688,9 +3661,7 @@
|
||||||
|
|
||||||
if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
|
if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
|
||||||
{
|
{
|
||||||
localpoints = ft_var_readpackedpoints( stream,
|
localpoints = ft_var_readpackedpoints( stream, &point_count );
|
||||||
table_len,
|
|
||||||
&point_count );
|
|
||||||
points = localpoints;
|
points = localpoints;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -3701,7 +3672,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
deltas = ft_var_readpackeddeltas( stream,
|
deltas = ft_var_readpackeddeltas( stream,
|
||||||
table_len,
|
|
||||||
point_count == 0 ? face->cvt_size
|
point_count == 0 ? face->cvt_size
|
||||||
: point_count );
|
: point_count );
|
||||||
|
|
||||||
|
@ -4150,9 +4120,8 @@
|
||||||
|
|
||||||
FT_Stream_SeekSet( stream, offsetToData );
|
FT_Stream_SeekSet( stream, offsetToData );
|
||||||
|
|
||||||
sharedpoints = ft_var_readpackedpoints( stream,
|
sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
|
||||||
blend->gvar_size,
|
|
||||||
&spoint_count );
|
|
||||||
offsetToData = FT_Stream_FTell( stream );
|
offsetToData = FT_Stream_FTell( stream );
|
||||||
|
|
||||||
FT_Stream_SeekSet( stream, here );
|
FT_Stream_SeekSet( stream, here );
|
||||||
|
@ -4236,9 +4205,7 @@
|
||||||
|
|
||||||
if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
|
if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
|
||||||
{
|
{
|
||||||
localpoints = ft_var_readpackedpoints( stream,
|
localpoints = ft_var_readpackedpoints( stream, &point_count );
|
||||||
blend->gvar_size,
|
|
||||||
&point_count );
|
|
||||||
points = localpoints;
|
points = localpoints;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -4248,11 +4215,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
deltas_x = ft_var_readpackeddeltas( stream,
|
deltas_x = ft_var_readpackeddeltas( stream,
|
||||||
blend->gvar_size,
|
|
||||||
point_count == 0 ? n_points
|
point_count == 0 ? n_points
|
||||||
: point_count );
|
: point_count );
|
||||||
deltas_y = ft_var_readpackeddeltas( stream,
|
deltas_y = ft_var_readpackeddeltas( stream,
|
||||||
blend->gvar_size,
|
|
||||||
point_count == 0 ? n_points
|
point_count == 0 ? n_points
|
||||||
: point_count );
|
: point_count );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue