ref: 9b710cd56eb66c379686e82d7fe371c212aebc37
parent: 0e7b9f864f517dfe0bc37419c037dd299fdd2a27
author: Werner Lemberg <[email protected]>
date: Tue May 30 18:35:41 EDT 2017
[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.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
2017-05-30 Werner Lemberg <[email protected]>
+ [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 <[email protected]>
+
[psaux] Correctly handle sequences of multiple number signs.
* src/psaux/psconv.c (PS_Conv_Strtol, PS_Conv_ToFixed): Return zero
--- a/src/cff/cffgload.c
+++ b/src/cff/cffgload.c
@@ -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,7 +2088,12 @@
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;
@@ -2073,7 +2100,7 @@
case cff_op_add:
FT_TRACE4(( " add\n" ));
- args[0] += args[1];
+ args[0] = OVERFLOW_ADD_LONG( args[0], args[1] );
args++;
break;
@@ -2080,7 +2107,7 @@
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;
--- a/src/cff/cffparse.c
+++ b/src/cff/cffparse.c
@@ -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,7 +157,23 @@
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
cff_parse_real( FT_Byte* start,
@@ -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):