[psaux] Guard and trace AFM kern data allocation.
Reported as https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=31543 * include/freetype/internal/fttrace.h: Add 'afmparse' trace component. * src/psaux/afmparse.c (FT_COMPONENT): Define. (afm_parse_track_kern, afm_parse_kern_pairs): Protect against allocations bombs. Add tracing. (afm_parse_kern_data): Don't allow multiple kern data sections.
This commit is contained in:
parent
5f485339be
commit
0d1c306e51
17
ChangeLog
17
ChangeLog
@ -1,3 +1,20 @@
|
||||
2021-05-25 Werner Lemberg <wl@gnu.org>
|
||||
|
||||
[psaux] Guard and trace AFM kern data allocation.
|
||||
|
||||
Reported as
|
||||
|
||||
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=31543
|
||||
|
||||
* include/freetype/internal/fttrace.h: Add 'afmparse' trace
|
||||
component.
|
||||
|
||||
* src/psaux/afmparse.c (FT_COMPONENT): Define.
|
||||
(afm_parse_track_kern, afm_parse_kern_pairs): Protect against
|
||||
allocations bombs.
|
||||
Add tracing.
|
||||
(afm_parse_kern_data): Don't allow multiple kern data sections.
|
||||
|
||||
2021-05-23 Alexei Podtelezhnikov <apodtele@gmail.com>
|
||||
|
||||
* meson.build (ft2_public_headers): Add missing `ftcid.h'.
|
||||
|
@ -83,6 +83,7 @@ FT_TRACE_DEF( t1objs )
|
||||
FT_TRACE_DEF( t1parse )
|
||||
|
||||
/* PostScript helper module `psaux' */
|
||||
FT_TRACE_DEF( afmparse )
|
||||
FT_TRACE_DEF( cffdecode )
|
||||
FT_TRACE_DEF( psconv )
|
||||
FT_TRACE_DEF( psobjs )
|
||||
|
@ -27,6 +27,16 @@
|
||||
#include "psauxerr.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* The macro FT_COMPONENT is used in trace mode. It is an implicit
|
||||
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
|
||||
* messages during execution.
|
||||
*/
|
||||
#undef FT_COMPONENT
|
||||
#define FT_COMPONENT afmparse
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* AFM_Stream
|
||||
@ -586,21 +596,38 @@
|
||||
static FT_Error
|
||||
afm_parse_track_kern( AFM_Parser parser )
|
||||
{
|
||||
AFM_FontInfo fi = parser->FontInfo;
|
||||
AFM_FontInfo fi = parser->FontInfo;
|
||||
AFM_Stream stream = parser->stream;
|
||||
AFM_TrackKern tk;
|
||||
char* key;
|
||||
FT_Offset len;
|
||||
int n = -1;
|
||||
FT_Int tmp;
|
||||
|
||||
char* key;
|
||||
FT_Offset len;
|
||||
int n = -1;
|
||||
FT_Int tmp;
|
||||
|
||||
|
||||
if ( afm_parser_read_int( parser, &tmp ) )
|
||||
goto Fail;
|
||||
|
||||
if ( tmp < 0 )
|
||||
{
|
||||
FT_ERROR(( "afm_parse_track_kern: invalid number of track kerns\n" ));
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
fi->NumTrackKern = (FT_UInt)tmp;
|
||||
FT_TRACE3(( "afm_parse_track_kern: %u track kern%s expected\n",
|
||||
fi->NumTrackKern,
|
||||
fi->NumTrackKern == 1 ? "" : "s" ));
|
||||
|
||||
/* Rough sanity check: The minimum line length of the `TrackKern` */
|
||||
/* command is 20 characters (including the EOL character). */
|
||||
if ( ( stream->limit - stream->cursor ) / 20 < fi->NumTrackKern )
|
||||
{
|
||||
FT_ERROR(( "afm_parse_track_kern:"
|
||||
" number of track kern entries exceeds stream size\n" ));
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
if ( fi->NumTrackKern )
|
||||
{
|
||||
@ -623,7 +650,10 @@
|
||||
n++;
|
||||
|
||||
if ( n >= (int)fi->NumTrackKern )
|
||||
goto Fail;
|
||||
{
|
||||
FT_ERROR(( "afm_parse_track_kern: too many track kern data\n" ));
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
tk = fi->TrackKerns + n;
|
||||
|
||||
@ -633,7 +663,12 @@
|
||||
shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
|
||||
shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
|
||||
if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
|
||||
{
|
||||
FT_ERROR(( "afm_parse_track_kern:"
|
||||
" insufficient number of parameters for entry %d\n",
|
||||
n ));
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
tk->degree = shared_vals[0].u.i;
|
||||
tk->min_ptsize = shared_vals[1].u.f;
|
||||
@ -646,7 +681,19 @@
|
||||
case AFM_TOKEN_ENDTRACKKERN:
|
||||
case AFM_TOKEN_ENDKERNDATA:
|
||||
case AFM_TOKEN_ENDFONTMETRICS:
|
||||
fi->NumTrackKern = (FT_UInt)( n + 1 );
|
||||
tmp = n + 1;
|
||||
if ( (FT_UInt)tmp != fi->NumTrackKern )
|
||||
{
|
||||
FT_TRACE1(( "afm_parse_track_kern: %s%d track kern entr%s seen\n",
|
||||
tmp == 0 ? "" : "only ",
|
||||
tmp,
|
||||
tmp == 1 ? "y" : "ies" ));
|
||||
fi->NumTrackKern = (FT_UInt)tmp;
|
||||
}
|
||||
else
|
||||
FT_TRACE3(( "afm_parse_track_kern: %d track kern entr%s seen\n",
|
||||
tmp,
|
||||
tmp == 1 ? "y" : "ies" ));
|
||||
return FT_Err_Ok;
|
||||
|
||||
case AFM_TOKEN_UNKNOWN:
|
||||
@ -690,7 +737,8 @@
|
||||
static FT_Error
|
||||
afm_parse_kern_pairs( AFM_Parser parser )
|
||||
{
|
||||
AFM_FontInfo fi = parser->FontInfo;
|
||||
AFM_FontInfo fi = parser->FontInfo;
|
||||
AFM_Stream stream = parser->stream;
|
||||
AFM_KernPair kp;
|
||||
char* key;
|
||||
FT_Offset len;
|
||||
@ -702,9 +750,25 @@
|
||||
goto Fail;
|
||||
|
||||
if ( tmp < 0 )
|
||||
{
|
||||
FT_ERROR(( "afm_parse_kern_pairs: invalid number of kern pairs\n" ));
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
fi->NumKernPair = (FT_UInt)tmp;
|
||||
FT_TRACE3(( "afm_parse_kern_pairs: %u kern pair%s expected\n",
|
||||
fi->NumKernPair,
|
||||
fi->NumKernPair == 1 ? "" : "s" ));
|
||||
|
||||
/* Rough sanity check: The minimum line length of the `KP`, */
|
||||
/* `KPH`,`KPX`, and `KPY` commands is 10 characters (including */
|
||||
/* the EOL character). */
|
||||
if ( ( stream->limit - stream->cursor ) / 10 < fi->NumKernPair )
|
||||
{
|
||||
FT_ERROR(( "afm_parse_kern_pairs:"
|
||||
" number of kern pairs exceeds stream size\n" ));
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
if ( fi->NumKernPair )
|
||||
{
|
||||
@ -734,7 +798,10 @@
|
||||
n++;
|
||||
|
||||
if ( n >= (int)fi->NumKernPair )
|
||||
{
|
||||
FT_ERROR(( "afm_parse_kern_pairs: too many kern pairs\n" ));
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
kp = fi->KernPairs + n;
|
||||
|
||||
@ -744,7 +811,12 @@
|
||||
shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
|
||||
r = afm_parser_read_vals( parser, shared_vals, 4 );
|
||||
if ( r < 3 )
|
||||
{
|
||||
FT_ERROR(( "afm_parse_kern_pairs:"
|
||||
" insufficient number of parameters for entry %d\n",
|
||||
n ));
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
/* index values can't be negative */
|
||||
kp->index1 = shared_vals[0].u.u;
|
||||
@ -766,7 +838,20 @@
|
||||
case AFM_TOKEN_ENDKERNPAIRS:
|
||||
case AFM_TOKEN_ENDKERNDATA:
|
||||
case AFM_TOKEN_ENDFONTMETRICS:
|
||||
fi->NumKernPair = (FT_UInt)( n + 1 );
|
||||
tmp = n + 1;
|
||||
if ( (FT_UInt)tmp != fi->NumKernPair )
|
||||
{
|
||||
FT_TRACE1(( "afm_parse_kern_pairs: %s%d kern pair%s seen\n",
|
||||
tmp == 0 ? "" : "only ",
|
||||
tmp,
|
||||
tmp == 1 ? "" : "s" ));
|
||||
fi->NumKernPair = (FT_UInt)tmp;
|
||||
}
|
||||
else
|
||||
FT_TRACE3(( "afm_parse_kern_pairs: %d kern pair%s seen\n",
|
||||
tmp,
|
||||
tmp == 1 ? "" : "s" ));
|
||||
|
||||
ft_qsort( fi->KernPairs, fi->NumKernPair,
|
||||
sizeof ( AFM_KernPairRec ),
|
||||
afm_compare_kern_pairs );
|
||||
@ -792,22 +877,43 @@
|
||||
char* key;
|
||||
FT_Offset len;
|
||||
|
||||
int have_trackkern = 0;
|
||||
int have_kernpairs = 0;
|
||||
|
||||
|
||||
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
|
||||
{
|
||||
switch ( afm_tokenize( key, len ) )
|
||||
{
|
||||
case AFM_TOKEN_STARTTRACKKERN:
|
||||
if ( have_trackkern )
|
||||
{
|
||||
FT_ERROR(( "afm_parse_kern_data:"
|
||||
" invalid second horizontal track kern section\n" ));
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
error = afm_parse_track_kern( parser );
|
||||
if ( error )
|
||||
return error;
|
||||
|
||||
have_trackkern = 1;
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_STARTKERNPAIRS:
|
||||
case AFM_TOKEN_STARTKERNPAIRS0:
|
||||
if ( have_kernpairs )
|
||||
{
|
||||
FT_ERROR(( "afm_parse_kern_data:"
|
||||
" invalid second horizontal kern pair section\n" ));
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
error = afm_parse_kern_pairs( parser );
|
||||
if ( error )
|
||||
return error;
|
||||
|
||||
have_kernpairs = 1;
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_ENDKERNDATA:
|
||||
|
Loading…
Reference in New Issue
Block a user