shithub: freetype+ttf2subf

Download patch

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.

git/fs: mount .git/fs: mount/attach disallowed
--- 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):