Commit 9ca782569c218e18c420e7c13bdbdf3e9a75c87a

David Turner 2006-05-02T09:00:29

* include/freetype/internal/ftmemory.h, src/base/ftbitmap.c, src/base/ftmac.c, src/base/ftrfork.c, src/lzw/ftzopen.c, src/raster/ftrend1.c, src/sfnt/ttpost.c, src/truetype/ttgxvar.c, src/type42/t42parse.c, src/winfonts/winfnt.c: hardening the code against out-of-bounds conditions when allocating arrays. This is for the cases where FT_NEW_ARRAY and FT_RENEW_ARRAY are not used already. Introducing the new FT_ALLOC_MULT and FT_REALLOC_MULT macros.

diff --git a/ChangeLog b/ChangeLog
index 91e3617..362b06a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2006-05-02  David Turner  <david@freetype.org>
 
+    * include/freetype/internal/ftmemory.h, src/base/ftbitmap.c,
+    src/base/ftmac.c, src/base/ftrfork.c, src/lzw/ftzopen.c,
+    src/raster/ftrend1.c, src/sfnt/ttpost.c, src/truetype/ttgxvar.c,
+    src/type42/t42parse.c, src/winfonts/winfnt.c: hardening the code
+    against out-of-bounds conditions when allocating arrays. This is
+    for the cases where FT_NEW_ARRAY and FT_RENEW_ARRAY are not used
+    already. Introducing the new FT_ALLOC_MULT and FT_REALLOC_MULT
+    macros.
+
+
     * include/freetype/fterrdef.h, include/freetype/config/ftconfig.h,
     include/freetype/internal/ftmemory.h, src/base/ftdbgmem.c,
     src/base/ftutil.c: udpating the memory management functions and
@@ -25,6 +35,7 @@
     is defined, and FT_STRICT_ALIASING has disappeared, the corresponding
     code being now the default.
 
+
 2006-04-30 suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
 
 	Fix bug in Mac_Read_POST_Resource() to parse PFB font with MacOS
diff --git a/include/freetype/internal/ftmemory.h b/include/freetype/internal/ftmemory.h
index 1fc4f99..9ef5427 100644
--- a/include/freetype/internal/ftmemory.h
+++ b/include/freetype/internal/ftmemory.h
@@ -134,6 +134,19 @@ FT_BASE( long )         _ft_debug_lineno;
 #define  FT_MEM_QRENEW_ARRAY(ptr,cur,new)  \
   FT_DEBUG_INNER( (ptr) = ft_mem_qrealloc( memory, sizeof(*(ptr)), (cur), (new), (ptr), &error ) )
 
+#define  FT_MEM_ALLOC_MULT(ptr,count,item_size)   \
+  FT_DEBUG_INNER( (ptr) = ft_mem_realloc( memory, (item_size), 0, (count), NULL, &error ) )
+
+#define  FT_MEM_REALLOC_MULT(ptr,oldcnt,newcnt,itmsz)  \
+  FT_DEBUG_INNER( (ptr) = ft_mem_realloc( memory, (itmsz), (oldcnt), (newcnt), (ptr), &error ) )
+
+#define  FT_MEM_QALLOC_MULT(ptr,count,item_size)   \
+  FT_DEBUG_INNER( (ptr) = ft_mem_qrealloc( memory, (item_size), 0, (count), NULL, &error ) )
+
+#define  FT_MEM_QREALLOC_MULT(ptr,oldcnt,newcnt,itmsz)  \
+  FT_DEBUG_INNER( (ptr) = ft_mem_qrealloc( memory, (itmsz), (oldcnt), (newcnt), (ptr), &error ) )
+
+
 #define  FT_MEM_SET_ERROR( cond )  ( (cond), error != 0 )
 
 
@@ -198,12 +211,24 @@ FT_BASE( long )         _ft_debug_lineno;
 #define  FT_REALLOC(ptr,cursz,newsz)  \
            FT_MEM_SET_ERROR( FT_MEM_REALLOC(ptr,cursz,newsz) )
 
+#define  FT_ALLOC_MULT(ptr,count,item_size) \
+           FT_MEM_SET_ERROR( FT_MEM_ALLOC_MULT(ptr,count,item_size) )
+
+#define  FT_REALLOC_MULT(ptr,oldcnt,newcnt,itmsz) \
+           FT_MEM_SET_ERROR( FT_MEM_REALLOC_MULT(ptr,oldcnt,newcnt,itmsz) )
+
 #define  FT_QALLOC(ptr,size)  \
            FT_MEM_SET_ERROR( FT_MEM_QALLOC(ptr,size) )
 
 #define  FT_QREALLOC(ptr,cursz,newsz)  \
            FT_MEM_SET_ERROR( FT_MEM_QREALLOC(ptr,cursz,newsz) )
 
+#define  FT_QALLOC_MULT(ptr,count,item_size) \
+           FT_MEM_SET_ERROR( FT_MEM_QALLOC_MULT(ptr,count,item_size) )
+
+#define  FT_QREALLOC_MULT(ptr,oldcnt,newcnt,itmsz) \
+           FT_MEM_SET_ERROR( FT_MEM_QREALLOC_MULT(ptr,oldcnt,newcnt,itmsz) )
+
 #define  FT_FREE(ptr)         FT_MEM_FREE( ptr )
 
 #define  FT_NEW(ptr)  \
diff --git a/src/base/ftbitmap.c b/src/base/ftbitmap.c
index 7a88294..d4709a4 100644
--- a/src/base/ftbitmap.c
+++ b/src/base/ftbitmap.c
@@ -165,7 +165,7 @@
 
     new_pitch = ( bitmap->width + xpixels + ppb - 1 ) / ppb;
 
-    if ( FT_ALLOC( buffer, new_pitch * ( bitmap->rows + ypixels ) ) )
+    if ( FT_QALLOC_MULT( buffer, new_pitch, bitmap->rows + ypixels ) )
       return error;
 
     if ( bitmap->pitch > 0 )
diff --git a/src/base/ftmac.c b/src/base/ftmac.c
index 5aed896..6e4cbe5 100644
--- a/src/base/ftmac.c
+++ b/src/base/ftmac.c
@@ -808,6 +808,7 @@
     short          res_id;
     unsigned char  *buffer, *p, *size_p = NULL;
     FT_ULong       total_size = 0;
+    FT_ULong       old_total_size = 0;
     FT_ULong       post_size, pfb_chunk_size;
     Handle         post_data;
     char           code, last_code;
@@ -838,6 +839,15 @@
 
       total_size += GetHandleSize( post_data ) - 2;
       last_code = code;
+
+      /* detect integer overflows */
+      if ( total_size < old_total_size )
+      {
+        error = FT_Err_Array_Too_Large;
+        goto Error;
+      }
+
+      old_total_size = total_size;
     }
 
     if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
diff --git a/src/base/ftrfork.c b/src/base/ftrfork.c
index 5d44ca4..cfa5891 100644
--- a/src/base/ftrfork.c
+++ b/src/base/ftrfork.c
@@ -179,7 +179,7 @@
         if ( error )
           return error;
 
-        if ( FT_ALLOC( offsets_internal, *count * sizeof( FT_Long ) ) )
+        if ( FT_NEW_ARRAY( offsets_internal, *count ) )
           return error;
 
         for ( j = 0; j < *count; ++j )
@@ -426,20 +426,25 @@
     FT_Error   error;
     char*      newpath;
     FT_Memory  memory;
+    FT_Long    base_file_len = ft_strlen( base_file_name );
 
     FT_UNUSED( stream );
 
 
     memory = library->memory;
 
-    if ( FT_ALLOC( newpath,
-                   ft_strlen( base_file_name ) + ft_strlen( "/rsrc" ) + 1 ) )
+    if ( base_file_len > FT_INT_MAX )
+      return FT_Err_Array_Too_Large;
+
+    if ( FT_ALLOC( newpath, base_file_len + 6 ) )
       return error;
 
-    ft_strcpy( newpath, base_file_name );
-    ft_strcat( newpath, "/rsrc" );
+    FT_MEM_COPY( newpath, base_file_name, base_file_len );
+    FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 );
+
     *result_file_name = newpath;
-    *result_offset = 0;
+    *result_offset    = 0;
+
     return FT_Err_Ok;
   }
 
diff --git a/src/lzw/ftzopen.c b/src/lzw/ftzopen.c
index 4105cfa..1d29fd8 100644
--- a/src/lzw/ftzopen.c
+++ b/src/lzw/ftzopen.c
@@ -127,10 +127,8 @@
      *  to write it literally.
      *
      */
-    if ( FT_REALLOC(
-           state->prefix,
-           old_size * (sizeof ( FT_UShort ) + sizeof ( FT_Byte ) ),
-           new_size * (sizeof ( FT_UShort ) + sizeof ( FT_Byte ) ) ) )
+    if ( FT_REALLOC_MULT( state->prefix, old_size, new_size,
+                          sizeof(FT_UShort)+sizeof(FT_Byte) ) )
       return -1;
 
     /* now adjust `suffix' and move the data accordingly */
diff --git a/src/raster/ftrend1.c b/src/raster/ftrend1.c
index ed75fb6..4e8d10f 100644
--- a/src/raster/ftrend1.c
+++ b/src/raster/ftrend1.c
@@ -161,13 +161,13 @@
     if ( !( mode & FT_RENDER_MODE_MONO ) )
     {
       /* we pad to 32 bits, only for backwards compatibility with FT 1.x */
-      pitch = FT_PAD_CEIL( width, 4 );
+      pitch              = FT_PAD_CEIL( width, 4 );
       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
       bitmap->num_grays  = 256;
     }
     else
     {
-      pitch = ( ( width + 15 ) >> 4 ) << 1;
+      pitch              = ( ( width + 15 ) >> 4 ) << 1;
       bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
     }
 
@@ -175,7 +175,7 @@
     bitmap->rows  = height;
     bitmap->pitch = pitch;
 
-    if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
+    if ( FT_ALLOC_MULT( bitmap->buffer, pitch, height ) )
       goto Exit;
 
     slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
diff --git a/src/sfnt/ttpost.c b/src/sfnt/ttpost.c
index 39f9916..511288e 100644
--- a/src/sfnt/ttpost.c
+++ b/src/sfnt/ttpost.c
@@ -292,7 +292,7 @@
       goto Exit;
     }
 
-    if ( FT_ALLOC( offset_table, num_glyphs )       ||
+    if ( FT_NEW_ARRAY( offset_table, num_glyphs )   ||
          FT_STREAM_READ( offset_table, num_glyphs ) )
       goto Fail;
 
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index fe5eaa3..0e72435 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -684,15 +684,17 @@
         goto Exit;
       }
 
-      if ( FT_ALLOC( face->blend, sizeof ( GX_BlendRec ) ) )
+      if ( FT_NEW( face->blend ) )
         goto Exit;
 
+      /* XXX: TODO - check for overflows */
       face->blend->mmvar_len =
         sizeof ( FT_MM_Var ) +
         fvar_head.axisCount * sizeof ( FT_Var_Axis ) +
         fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) +
         fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) +
         5 * fvar_head.axisCount;
+
       if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
         goto Exit;
       face->blend->mmvar = mmvar;
@@ -1253,7 +1255,7 @@
         for ( j = 0; j < point_count; ++j )
         {
           int  pindex = localpoints[j];
-          
+
           face->cvt[pindex] = (FT_Short)( face->cvt[pindex] +
                                           FT_MulFix( deltas[j], apply ) );
         }
diff --git a/src/type42/t42parse.c b/src/type42/t42parse.c
index 80e7547..b589f19 100644
--- a/src/type42/t42parse.c
+++ b/src/type42/t42parse.c
@@ -623,6 +623,7 @@
             status         = OTHER_TABLES;
             face->ttf_size = ttf_size;
 
+            /* there are no more than 256 tables, so no size check here */
             if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
                              ttf_size + 1 ) )
               goto Fail;
@@ -1071,7 +1072,7 @@
             if ( !name )
               continue;
 
-            if ( cur[0] == name[0]                                  && 
+            if ( cur[0] == name[0]                                  &&
                  len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
                  ft_memcmp( cur, name, len ) == 0                   )
             {
diff --git a/src/winfonts/winfnt.c b/src/winfonts/winfnt.c
index 553cddb..3523b14 100644
--- a/src/winfonts/winfnt.c
+++ b/src/winfonts/winfnt.c
@@ -531,7 +531,7 @@
 
       /* reserve one slot for the .notdef glyph at index 0 */
       root->num_glyphs = font->header.last_char -
-                           font->header.first_char + 1 + 1;
+                         font->header.first_char + 1 + 1;
 
       /* Some broken fonts don't delimit the face name with a final */
       /* NULL byte -- the frame is erroneously one byte too small.  */
@@ -540,14 +540,18 @@
       family_size = font->header.file_size - font->header.face_name_offset;
       if ( FT_ALLOC( font->family_name, family_size + 1 ) )
         goto Fail;
+
       FT_MEM_COPY( font->family_name,
                    font->fnt_frame + font->header.face_name_offset,
                    family_size );
+
       font->family_name[family_size] = '\0';
+
       if ( FT_REALLOC( font->family_name,
                        family_size,
                        ft_strlen( font->family_name ) + 1 ) )
         goto Fail;
+
       root->family_name = font->family_name;
       root->style_name  = (char *)"Regular";
 
@@ -693,7 +697,7 @@
 
       /* note: since glyphs are stored in columns and not in rows we */
       /*       can't use ft_glyphslot_set_bitmap                     */
-      if ( FT_ALLOC( bitmap->buffer, pitch * bitmap->rows ) )
+      if ( FT_ALLOC_MULT( bitmap->buffer, pitch, bitmap->rows ) )
         goto Exit;
 
       column = (FT_Byte*)bitmap->buffer;