Commit 642bc7590c701c8cd35a9f60fa899cfa518b17ff

Armin Hasitzka 2018-11-22T10:29:35

[cff] Fix memory overflow. Reported as https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=9869 https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=10869 * src/cff/cffparse.c (destruct_t2s_item, cff_parser_run): Store evaluated T2 charstrings in separately allocated memory.

diff --git a/ChangeLog b/ChangeLog
index 55d2217..7efabc2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2018-11-22  Armin Hasitzka  <prince.cherusker@gmail.com>
+
+	[cff] Fix memory overflow.
+
+	Reported as
+
+	  https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=9869
+	  https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=10869
+
+	* src/cff/cffparse.c (destruct_t2s_item, cff_parser_run): Store
+	evaluated T2 charstrings in separately allocated memory.
+
 2018-11-18  Alexei Podtelezhnikov  <apodtele@gmail.com>
 
 	* builds/windows/{visualc,vc2005,vc2008}/freetype.vcproj: Fix it.
diff --git a/src/cff/cffparse.c b/src/cff/cffparse.c
index b8b7818..d7ff16c 100644
--- a/src/cff/cffparse.c
+++ b/src/cff/cffparse.c
@@ -1121,21 +1121,35 @@
 #endif /* FT_DEBUG_LEVEL_TRACE */
 
 
+  static void
+  destruct_t2s_item( FT_Memory  memory,
+                     void*      data,
+                     void*      user )
+  {
+    FT_UNUSED( user );
+    memory->free( memory, data );
+  }
+
+
   FT_LOCAL_DEF( FT_Error )
   cff_parser_run( CFF_Parser  parser,
                   FT_Byte*    start,
                   FT_Byte*    limit )
   {
+    FT_Byte*  p     = start;
+    FT_Error  error = FT_Err_Ok;
+
 #ifdef CFF_CONFIG_OPTION_OLD_ENGINE
     PSAux_Service  psaux;
-#endif
 
-    FT_Byte*    p       = start;
-    FT_Error    error   = FT_Err_Ok;
     FT_Library  library = parser->library;
+    FT_Memory   memory  = library->memory;
+
+    FT_ListRec  t2s;
 
-    FT_UNUSED( library );
 
+    FT_ZERO( &t2s );
+#endif
 
     parser->top    = parser->stack;
     parser->start  = start;
@@ -1195,8 +1209,9 @@
         FT_Byte*     charstring_base;
         FT_ULong     charstring_len;
 
-        FT_Fixed*  stack;
-        FT_Byte*   q;
+        FT_Fixed*    stack;
+        FT_ListNode  node;
+        FT_Byte*     q;
 
 
         charstring_base = ++p;
@@ -1237,13 +1252,23 @@
         /* Now copy the stack data in the temporary decoder object,    */
         /* converting it back to charstring number representations     */
         /* (this is ugly, I know).                                     */
-        /*                                                             */
-        /* We overwrite the original top DICT charstring under the     */
-        /* assumption that the charstring representation of the result */
-        /* of `cff_decoder_parse_charstrings' is shorter, which should */
-        /* be always true.                                             */
 
-        q     = charstring_base - 1;
+        node = (FT_ListNode)memory->alloc( memory,
+                                           sizeof ( FT_ListNodeRec ) );
+        if ( !node )
+          goto Out_Of_Memory_Error;
+
+        /* `5' is the conservative upper bound of required bytes per stack */
+        /* element.                                                        */
+        q = (FT_Byte*)memory->alloc( memory,
+                                     5 * ( decoder.top - decoder.stack ) );
+        if ( !q )
+          goto Out_Of_Memory_Error;
+
+        node->data = q;
+
+        FT_List_Add( &t2s, node );
+
         stack = decoder.stack;
 
         while ( stack < decoder.top )
@@ -1500,11 +1525,18 @@
           parser->top = parser->stack;
       }
       p++;
-    }
+    } /* while ( p < limit ) */
 
   Exit:
+#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
+    FT_List_Finalize( &t2s, destruct_t2s_item, memory, NULL );
+#endif
     return error;
 
+  Out_Of_Memory_Error:
+    error = FT_THROW( Out_Of_Memory );
+    goto Exit;
+
   Stack_Overflow:
     error = FT_THROW( Invalid_Argument );
     goto Exit;