Commit 649ca5562d321f1008087eb0f2be584a495fabd9

Werner Lemberg 2015-10-21T07:01:45

[type42] Better check invalid `sfnts' array data (#46255). * src/type42/t42parse.c (t42_parse_sfnts): Table lengths must be checked individually against available data size.

diff --git a/ChangeLog b/ChangeLog
index b95f65e..0d52a85 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2015-10-21  Werner Lemberg  <wl@gnu.org>
+
+	[type42] Better check invalid `sfnts' array data (#46255).
+
+	* src/type42/t42parse.c (t42_parse_sfnts): Table lengths must be
+	checked individually against available data size.
+
 2015-10-20  Werner Lemberg  <wl@gnu.org>
 
 	[cid] Add a bunch of safety checks.
diff --git a/src/type42/t42parse.c b/src/type42/t42parse.c
index a32d496..3bcf97e 100644
--- a/src/type42/t42parse.c
+++ b/src/type42/t42parse.c
@@ -575,6 +575,9 @@
 
     while ( parser->root.cursor < limit )
     {
+      FT_ULong  size;
+
+
       cur = parser->root.cursor;
 
       if ( *cur == ']' )
@@ -666,6 +669,11 @@
         goto Fail;
       }
 
+      /* The whole TTF is now loaded into `string_buf'.  We are */
+      /* checking its contents while copying it to `ttf_data'.  */
+
+      size = limit - parser->root.cursor;
+
       for ( n = 0; n < string_size; n++ )
       {
         switch ( status )
@@ -683,7 +691,7 @@
             status         = BEFORE_TABLE_DIR;
             face->ttf_size = 12 + 16 * num_tables;
 
-            if ( (FT_Long)( limit - parser->root.cursor ) < face->ttf_size )
+            if ( (FT_Long)size < face->ttf_size )
             {
               FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
               error = FT_THROW( Invalid_File_Format );
@@ -714,6 +722,14 @@
 
 
               len = FT_PEEK_ULONG( p );
+              if ( len > size                               ||
+                   face->ttf_size > (FT_Long)( size - len ) )
+              {
+                FT_ERROR(( "t42_parse_sfnts:"
+                           " invalid data in sfnts array\n" ));
+                error = FT_THROW( Invalid_File_Format );
+                goto Fail;
+              }
 
               /* Pad to a 4-byte boundary length */
               face->ttf_size += (FT_Long)( ( len + 3 ) & ~3U );
@@ -721,7 +737,6 @@
 
             status = OTHER_TABLES;
 
-            /* there are no more than 256 tables, so no size check here */
             if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
                              face->ttf_size + 1 ) )
               goto Fail;