[cff] 32bit integer overflow run-time errors 1/2 (#46149).

This commit handles the old engine.

* src/cff/cffgload.c: Include FT_INTERNAL_CALC_H.
(cff_decoder_parse_charstrings): Use OVERFLOW_ADD_LONG and
OVERFLOW_SUB_LONG where needed.

* src/cff/cffparse.c: Include FT_INTERNAL_CALC_H.
(power_ten_limits): New static array.
(do_fixed): Use it to prevent multiplication overflow.
(cff_parser_run): Use OVERFLOW_ADD_LONG.
This commit is contained in:
Werner Lemberg 2017-05-30 22:35:41 +02:00
parent 0e7b9f864f
commit 9b710cd56e
3 changed files with 161 additions and 89 deletions

View File

@ -1,3 +1,18 @@
2017-05-30 Werner Lemberg <wl@gnu.org>
[cff] 32bit integer overflow run-time errors 1/2 (#46149).
This commit handles the old engine.
* src/cff/cffgload.c: Include FT_INTERNAL_CALC_H.
(cff_decoder_parse_charstrings): Use OVERFLOW_ADD_LONG and
OVERFLOW_SUB_LONG where needed.
* src/cff/cffparse.c: Include FT_INTERNAL_CALC_H.
(power_ten_limits): New static array.
(do_fixed): Use it to prevent multiplication overflow.
(cff_parser_run): Use OVERFLOW_ADD_LONG.
2017-05-30 Werner Lemberg <wl@gnu.org>
[psaux] Correctly handle sequences of multiple number signs.

View File

@ -20,6 +20,7 @@
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_SFNT_H
#include FT_INTERNAL_CALC_H
#include FT_OUTLINE_H
#include FT_CFF_DRIVER_H
@ -1450,8 +1451,8 @@
cff_builder_close_contour( builder );
builder->path_begun = 0;
x += args[-2];
y += args[-1];
x = OVERFLOW_ADD_LONG( x, args[-2] );
y = OVERFLOW_ADD_LONG( y, args[-1] );
args = stack;
break;
@ -1460,7 +1461,7 @@
cff_builder_close_contour( builder );
builder->path_begun = 0;
y += args[-1];
y = OVERFLOW_ADD_LONG( y, args[-1] );
args = stack;
break;
@ -1469,7 +1470,7 @@
cff_builder_close_contour( builder );
builder->path_begun = 0;
x += args[-1];
x = OVERFLOW_ADD_LONG( x, args[-1] );
args = stack;
break;
@ -1486,8 +1487,8 @@
args -= num_args & ~1;
while ( args < decoder->top )
{
x += args[0];
y += args[1];
x = OVERFLOW_ADD_LONG( x, args[0] );
y = OVERFLOW_ADD_LONG( y, args[1] );
cff_builder_add_point( builder, x, y, 1 );
args += 2;
}
@ -1519,9 +1520,9 @@
while ( args < decoder->top )
{
if ( phase )
x += args[0];
x = OVERFLOW_ADD_LONG( x, args[0] );
else
y += args[0];
y = OVERFLOW_ADD_LONG( y, args[0] );
if ( cff_builder_add_point1( builder, x, y ) )
goto Fail;
@ -1552,15 +1553,18 @@
args -= nargs;
while ( args < decoder->top )
{
x += args[0];
y += args[1];
x = OVERFLOW_ADD_LONG( x, args[0] );
y = OVERFLOW_ADD_LONG( y, args[1] );
cff_builder_add_point( builder, x, y, 0 );
x += args[2];
y += args[3];
x = OVERFLOW_ADD_LONG( x, args[2] );
y = OVERFLOW_ADD_LONG( y, args[3] );
cff_builder_add_point( builder, x, y, 0 );
x += args[4];
y += args[5];
x = OVERFLOW_ADD_LONG( x, args[4] );
y = OVERFLOW_ADD_LONG( y, args[5] );
cff_builder_add_point( builder, x, y, 1 );
args += 6;
}
args = stack;
@ -1589,7 +1593,7 @@
if ( nargs & 1 )
{
x += args[0];
x = OVERFLOW_ADD_LONG( x, args[0] );
args++;
nargs--;
}
@ -1599,13 +1603,16 @@
while ( args < decoder->top )
{
y += args[0];
y = OVERFLOW_ADD_LONG( y, args[0] );
cff_builder_add_point( builder, x, y, 0 );
x += args[1];
y += args[2];
x = OVERFLOW_ADD_LONG( x, args[1] );
y = OVERFLOW_ADD_LONG( y, args[2] );
cff_builder_add_point( builder, x, y, 0 );
y += args[3];
y = OVERFLOW_ADD_LONG( y, args[3] );
cff_builder_add_point( builder, x, y, 1 );
args += 4;
}
args = stack;
@ -1633,7 +1640,7 @@
args -= nargs;
if ( nargs & 1 )
{
y += args[0];
y = OVERFLOW_ADD_LONG( y, args[0] );
args++;
nargs--;
}
@ -1643,13 +1650,16 @@
while ( args < decoder->top )
{
x += args[0];
x = OVERFLOW_ADD_LONG( x, args[0] );
cff_builder_add_point( builder, x, y, 0 );
x += args[1];
y += args[2];
x = OVERFLOW_ADD_LONG( x, args[1] );
y = OVERFLOW_ADD_LONG( y, args[2] );
cff_builder_add_point( builder, x, y, 0 );
x += args[3];
x = OVERFLOW_ADD_LONG( x, args[3] );
cff_builder_add_point( builder, x, y, 1 );
args += 4;
}
args = stack;
@ -1688,26 +1698,30 @@
nargs -= 4;
if ( phase )
{
x += args[0];
x = OVERFLOW_ADD_LONG( x, args[0] );
cff_builder_add_point( builder, x, y, 0 );
x += args[1];
y += args[2];
x = OVERFLOW_ADD_LONG( x, args[1] );
y = OVERFLOW_ADD_LONG( y, args[2] );
cff_builder_add_point( builder, x, y, 0 );
y += args[3];
y = OVERFLOW_ADD_LONG( y, args[3] );
if ( nargs == 1 )
x += args[4];
x = OVERFLOW_ADD_LONG( x, args[4] );
cff_builder_add_point( builder, x, y, 1 );
}
else
{
y += args[0];
y = OVERFLOW_ADD_LONG( y, args[0] );
cff_builder_add_point( builder, x, y, 0 );
x += args[1];
y += args[2];
x = OVERFLOW_ADD_LONG( x, args[1] );
y = OVERFLOW_ADD_LONG( y, args[2] );
cff_builder_add_point( builder, x, y, 0 );
x += args[3];
x = OVERFLOW_ADD_LONG( x, args[3] );
if ( nargs == 1 )
y += args[4];
y = OVERFLOW_ADD_LONG( y, args[4] );
cff_builder_add_point( builder, x, y, 1 );
}
args += 4;
@ -1740,23 +1754,27 @@
/* first, add the line segments */
while ( num_lines > 0 )
{
x += args[0];
y += args[1];
x = OVERFLOW_ADD_LONG( x, args[0] );
y = OVERFLOW_ADD_LONG( y, args[1] );
cff_builder_add_point( builder, x, y, 1 );
args += 2;
num_lines--;
}
/* then the curve */
x += args[0];
y += args[1];
x = OVERFLOW_ADD_LONG( x, args[0] );
y = OVERFLOW_ADD_LONG( y, args[1] );
cff_builder_add_point( builder, x, y, 0 );
x += args[2];
y += args[3];
x = OVERFLOW_ADD_LONG( x, args[2] );
y = OVERFLOW_ADD_LONG( y, args[3] );
cff_builder_add_point( builder, x, y, 0 );
x += args[4];
y += args[5];
x = OVERFLOW_ADD_LONG( x, args[4] );
y = OVERFLOW_ADD_LONG( y, args[5] );
cff_builder_add_point( builder, x, y, 1 );
args = stack;
}
break;
@ -1785,23 +1803,27 @@
/* first, add the curves */
while ( num_curves > 0 )
{
x += args[0];
y += args[1];
x = OVERFLOW_ADD_LONG( x, args[0] );
y = OVERFLOW_ADD_LONG( y, args[1] );
cff_builder_add_point( builder, x, y, 0 );
x += args[2];
y += args[3];
x = OVERFLOW_ADD_LONG( x, args[2] );
y = OVERFLOW_ADD_LONG( y, args[3] );
cff_builder_add_point( builder, x, y, 0 );
x += args[4];
y += args[5];
x = OVERFLOW_ADD_LONG( x, args[4] );
y = OVERFLOW_ADD_LONG( y, args[5] );
cff_builder_add_point( builder, x, y, 1 );
args += 6;
num_curves--;
}
/* then the final line */
x += args[0];
y += args[1];
x = OVERFLOW_ADD_LONG( x, args[0] );
y = OVERFLOW_ADD_LONG( y, args[1] );
cff_builder_add_point( builder, x, y, 1 );
args = stack;
}
break;
@ -1824,33 +1846,33 @@
start_y = y;
/* first control point */
x += args[0];
y += args[1];
x = OVERFLOW_ADD_LONG( x, args[0] );
y = OVERFLOW_ADD_LONG( y, args[1] );
cff_builder_add_point( builder, x, y, 0 );
/* second control point */
x += args[2];
y += args[3];
x = OVERFLOW_ADD_LONG( x, args[2] );
y = OVERFLOW_ADD_LONG( y, args[3] );
cff_builder_add_point( builder, x, y, 0 );
/* join point; on curve, with y-value the same as the last */
/* control point's y-value */
x += args[4];
x = OVERFLOW_ADD_LONG( x, args[4] );
cff_builder_add_point( builder, x, y, 1 );
/* third control point, with y-value the same as the join */
/* point's y-value */
x += args[5];
x = OVERFLOW_ADD_LONG( x, args[5] );
cff_builder_add_point( builder, x, y, 0 );
/* fourth control point */
x += args[6];
y += args[7];
x = OVERFLOW_ADD_LONG( x, args[6] );
y = OVERFLOW_ADD_LONG( y, args[7] );
cff_builder_add_point( builder, x, y, 0 );
/* ending point, with y-value the same as the start */
x += args[8];
y = start_y;
x = OVERFLOW_ADD_LONG( x, args[8] );
y = start_y;
cff_builder_add_point( builder, x, y, 1 );
args = stack;
@ -1873,32 +1895,32 @@
start_y = y;
/* first control point */
x += args[0];
x = OVERFLOW_ADD_LONG( x, args[0] );
cff_builder_add_point( builder, x, y, 0 );
/* second control point */
x += args[1];
y += args[2];
x = OVERFLOW_ADD_LONG( x, args[1] );
y = OVERFLOW_ADD_LONG( y, args[2] );
cff_builder_add_point( builder, x, y, 0 );
/* join point; on curve, with y-value the same as the last */
/* control point's y-value */
x += args[3];
x = OVERFLOW_ADD_LONG( x, args[3] );
cff_builder_add_point( builder, x, y, 1 );
/* third control point, with y-value the same as the join */
/* point's y-value */
x += args[4];
x = OVERFLOW_ADD_LONG( x, args[4] );
cff_builder_add_point( builder, x, y, 0 );
/* fourth control point */
x += args[5];
y = start_y;
x = OVERFLOW_ADD_LONG( x, args[5] );
y = start_y;
cff_builder_add_point( builder, x, y, 0 );
/* ending point, with y-value the same as the start point's */
/* y-value -- we don't add this point, though */
x += args[6];
x = OVERFLOW_ADD_LONG( x, args[6] );
cff_builder_add_point( builder, x, y, 1 );
args = stack;
@ -1934,8 +1956,8 @@
/* grab up to the last argument */
for ( count = 5; count > 0; count-- )
{
dx += temp[0];
dy += temp[1];
dx = OVERFLOW_ADD_LONG( dx, temp[0] );
dy = OVERFLOW_ADD_LONG( dy, temp[1] );
temp += 2;
}
@ -1949,8 +1971,8 @@
for ( count = 5; count > 0; count-- )
{
x += args[0];
y += args[1];
x = OVERFLOW_ADD_LONG( x, args[0] );
y = OVERFLOW_ADD_LONG( y, args[1] );
cff_builder_add_point( builder, x, y,
(FT_Bool)( count == 3 ) );
args += 2;
@ -1959,13 +1981,13 @@
/* is last operand an x- or y-delta? */
if ( horizontal )
{
x += args[0];
y = start_y;
x = OVERFLOW_ADD_LONG( x, args[0] );
y = start_y;
}
else
{
x = start_x;
y += args[0];
x = start_x;
y = OVERFLOW_ADD_LONG( y, args[0] );
}
cff_builder_add_point( builder, x, y, 1 );
@ -1987,8 +2009,8 @@
for ( count = 6; count > 0; count-- )
{
x += args[0];
y += args[1];
x = OVERFLOW_ADD_LONG( x, args[0] );
y = OVERFLOW_ADD_LONG( y, args[1] );
cff_builder_add_point( builder, x, y,
(FT_Bool)( count == 4 || count == 1 ) );
args += 2;
@ -2066,21 +2088,26 @@
FT_TRACE4(( " abs\n" ));
if ( args[0] < 0 )
args[0] = -args[0];
{
if ( args[0] == FT_LONG_MIN )
args[0] = FT_LONG_MAX;
else
args[0] = -args[0];
}
args++;
break;
case cff_op_add:
FT_TRACE4(( " add\n" ));
args[0] += args[1];
args[0] = OVERFLOW_ADD_LONG( args[0], args[1] );
args++;
break;
case cff_op_sub:
FT_TRACE4(( " sub\n" ));
args[0] -= args[1];
args[0] = OVERFLOW_SUB_LONG( args[0], args[1] );
args++;
break;
@ -2094,6 +2121,8 @@
case cff_op_neg:
FT_TRACE4(( " neg\n" ));
if ( args[0] == FT_LONG_MIN )
args[0] = FT_LONG_MAX;
args[0] = -args[0];
args++;
break;
@ -2350,12 +2379,13 @@
FT_TRACE4(( " hsbw (invalid op)\n" ));
decoder->glyph_width = decoder->nominal_width + ( args[1] >> 16 );
decoder->glyph_width =
OVERFLOW_ADD_LONG( decoder->nominal_width, ( args[1] >> 16 ) );
decoder->builder.left_bearing.x = args[0];
decoder->builder.left_bearing.y = 0;
x = decoder->builder.pos_x + args[0];
x = OVERFLOW_ADD_LONG( decoder->builder.pos_x, args[0] );
y = decoder->builder.pos_y;
args = stack;
break;
@ -2367,13 +2397,14 @@
FT_TRACE4(( " sbw (invalid op)\n" ));
decoder->glyph_width = decoder->nominal_width + ( args[2] >> 16 );
decoder->glyph_width =
OVERFLOW_ADD_LONG( decoder->nominal_width, ( args[2] >> 16 ) );
decoder->builder.left_bearing.x = args[0];
decoder->builder.left_bearing.y = args[1];
x = decoder->builder.pos_x + args[0];
y = decoder->builder.pos_y + args[1];
x = OVERFLOW_ADD_LONG( decoder->builder.pos_x, args[0] );
y = OVERFLOW_ADD_LONG( decoder->builder.pos_y, args[1] );
args = stack;
break;
@ -2384,8 +2415,8 @@
FT_TRACE4(( " setcurrentpoint (invalid op)\n" ));
x = decoder->builder.pos_x + args[0];
y = decoder->builder.pos_y + args[1];
x = OVERFLOW_ADD_LONG( decoder->builder.pos_x, args[0] );
y = OVERFLOW_ADD_LONG( decoder->builder.pos_y, args[1] );
args = stack;
break;

View File

@ -20,6 +20,7 @@
#include "cffparse.h"
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_CALC_H
#include "cfferrs.h"
#include "cffpic.h"
@ -156,6 +157,22 @@
1000000000L
};
/* maximum values allowed for multiplying */
/* with the corresponding `power_tens' element */
static const FT_Long power_ten_limits[] =
{
FT_LONG_MAX / 1L,
FT_LONG_MAX / 10L,
FT_LONG_MAX / 100L,
FT_LONG_MAX / 1000L,
FT_LONG_MAX / 10000L,
FT_LONG_MAX / 100000L,
FT_LONG_MAX / 1000000L,
FT_LONG_MAX / 10000000L,
FT_LONG_MAX / 100000000L,
FT_LONG_MAX / 1000000000L,
};
/* read a real */
static FT_Fixed
@ -484,7 +501,15 @@
if ( scaling )
{
if ( FT_ABS( val ) > power_ten_limits[scaling] )
{
val = val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFFL;
goto Overflow;
}
val *= power_tens[scaling];
}
if ( val > 0x7FFF )
{
@ -1585,7 +1610,8 @@
val = 0;
while ( num_args > 0 )
{
val += cff_parse_num( parser, data++ );
val = OVERFLOW_ADD_LONG( val,
cff_parse_num( parser, data++ ) );
switch ( field->size )
{
case (8 / FT_CHAR_BIT):