shithub: freetype+ttf2subf

Download patch

ref: 0d9459294238c4fa5a45ccf8077c8b258bd487ac
parent: a764963f267b5e253a0a48fefd10efdb0b20c5b9
author: Werner Lemberg <[email protected]>
date: Tue Sep 27 04:44:31 EDT 2016

[truetype] Introduce dynamic limits for some bytecode opcodes.

This speeds up FreeType's handling of malformed fonts.

* src/truetype/ttinterp.c (TT_RunIns): Set up limits for the number
of twilight points, the total number of negative jumps, and the
total number of loops in LOOPCALL opcodes.  The values are based on
the number of points and entries in the CVT table.
(Ins_JMPR): Test negative jump counter.
(Ins_LOOPCALL): Test loopcall counter.

* src/truetype/ttinterp.h (TT_ExecContext): Updated.

* docs/CHANGES: Updated.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2016-09-27  Werner Lemberg  <[email protected]>
+
+	[truetype] Introduce dynamic limits for some bytecode opcodes.
+
+	This speeds up FreeType's handling of malformed fonts.
+
+	* src/truetype/ttinterp.c (TT_RunIns): Set up limits for the number
+	of twilight points, the total number of negative jumps, and the
+	total number of loops in LOOPCALL opcodes.  The values are based on
+	the number of points and entries in the CVT table.
+	(Ins_JMPR): Test negative jump counter.
+	(Ins_LOOPCALL): Test loopcall counter.
+
+	* src/truetype/ttinterp.h (TT_ExecContext): Updated.
+
+	* docs/CHANGES: Updated.
+
 2016-09-25  Werner Lemberg  <[email protected]>
 
 	[truetype] Sanitize only last entry of `loca' table.
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -1,4 +1,31 @@
 
+CHANGES BETWEEN 2.7 and 2.7.1
+
+  I. IMPORTANT CHANGES
+
+
+  II. IMPORTANT BUG FIXES
+
+
+  III. MISCELLANEOUS
+
+    - Some limits for TrueType  bytecode execution have been tightened
+      to  speed   up  FreeType's  handling  of   malformed  fonts,  in
+      particular to quickly abort endless loops.
+
+      - The  number of  twilight points  can no  longer be  set to  an
+        arbitrarily large value.
+
+      - The total number of jump  opcode instructions (like JMPR) with
+        negative arguments  is dynamically restricted; the  same holds
+        for the total number of iterations in LOOPCALL opcodes.
+
+      The dynamic limits are based on  the number of points in a glyph
+      and the number of CVT entries.  Please report if you encounter a
+      font where the selected values are not adequate.
+
+======================================================================
+
 CHANGES BETWEEN 2.6.5 and 2.7
 
   I. IMPORTANT CHANGES
--- a/src/truetype/ttinterp.c
+++ b/src/truetype/ttinterp.c
@@ -3388,13 +3388,27 @@
             FT_Long*        args )
   {
     if ( args[0] == 0 && exc->args == 0 )
+    {
       exc->error = FT_THROW( Bad_Argument );
+      return;
+    }
+
     exc->IP += args[0];
     if ( exc->IP < 0                                             ||
          ( exc->callTop > 0                                    &&
            exc->IP > exc->callStack[exc->callTop - 1].Def->end ) )
+    {
       exc->error = FT_THROW( Bad_Argument );
+      return;
+    }
+
     exc->step_ins = FALSE;
+
+    if ( args[0] < 0 )
+    {
+      if ( ++exc->neg_jump_counter > exc->neg_jump_counter_max )
+        exc->error = FT_THROW( Execution_Too_Long );
+    }
   }
 
 
@@ -3949,6 +3963,10 @@
       Ins_Goto_CodeRange( exc, def->range, def->start );
 
       exc->step_ins = FALSE;
+
+      exc->loopcall_counter += args[0];
+      if ( exc->loopcall_counter > exc->loopcall_counter_max )
+        exc->error = FT_THROW( Execution_Too_Long );
     }
 
     return;
@@ -7533,6 +7551,7 @@
   TT_RunIns( TT_ExecContext  exc )
   {
     FT_Long    ins_counter = 0;  /* executed instructions counter */
+    FT_Long    num_twilight_points;
     FT_UShort  i;
 
 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
@@ -7567,6 +7586,41 @@
     exc->iupx_called = FALSE;
     exc->iupy_called = FALSE;
 #endif
+
+    /* We restrict the number of twilight points to a reasonable,     */
+    /* heuristic value to avoid slow execution of malformed bytecode. */
+    num_twilight_points = FT_MAX( 30,
+                                  2 * ( exc->pts.n_points + exc->cvtSize ) );
+    if ( exc->twilight.n_points > num_twilight_points )
+    {
+      FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n"
+                  "           from %d to the more reasonable value %d\n",
+                  exc->twilight.n_points,
+                  num_twilight_points ));
+      exc->twilight.n_points = num_twilight_points;
+    }
+
+    /* Set up loop detectors.  We restrict the number of LOOPCALL loops  */
+    /* and the number of JMPR, JROT, and JROF calls with a negative      */
+    /* argument to values that depend on the size of the CVT table and   */
+    /* the number of points in the current glyph (if applicable).        */
+    /*                                                                   */
+    /* The idea is that in real-world bytecode you either iterate over   */
+    /* all CVT entries, or over all points (or contours) of a glyph, and */
+    /* such iterations don't happen very often.                          */
+    exc->loopcall_counter = 0;
+    exc->neg_jump_counter = 0;
+
+    /* The maximum values are heuristic. */
+    exc->loopcall_counter_max = FT_MAX( 100,
+                                        10 * ( exc->pts.n_points +
+                                               exc->cvtSize ) );
+    FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL"
+                " to %d\n", exc->loopcall_counter_max ));
+
+    exc->neg_jump_counter_max = exc->loopcall_counter_max;
+    FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps"
+                " to %d\n", exc->neg_jump_counter_max ));
 
     /* set PPEM and CVT functions */
     exc->tt_metrics.ratio = 0;
--- a/src/truetype/ttinterp.h
+++ b/src/truetype/ttinterp.h
@@ -408,6 +408,14 @@
 
 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
 
+    /* We maintain two counters (in addition to the instruction counter) */
+    /* that act as loop detectors for LOOPCALL and jump opcodes with     */
+    /* negative arguments.                                               */
+    FT_Long            loopcall_counter;
+    FT_Long            loopcall_counter_max;
+    FT_Long            neg_jump_counter;
+    FT_Long            neg_jump_counter_max;
+
   } TT_ExecContextRec;