Commit ab7e52b1c78b27d74e9555c6488c46bd62101804

David Turner 2009-03-03T22:37:13

Fix SFNT kerning table parser against malformed tables. Closes Savannah BUG #25750 * src/sfnt/ttkern.c (tt_face_get_kerning): fix a bug where a malformed table would be succesfully loaded but later crash the engine during parsing.

diff --git a/ChangeLog b/ChangeLog
index 9f7fe9a..95833b9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2009-03-03  David Turner  <david@freetype.org>
 
+	Fix SFNT kerning table parser against malformed tables.
+	Closes Savannah BUG #25750
+
+	* src/sfnt/ttkern.c (tt_face_get_kerning): fix a bug
+	where a malformed table would be succesfully loaded but
+	later crash the engine during parsing.
+
+2009-03-03  David Turner  <david@freetype.org>
+
 	Update documentation and bump version number to 2.3.9.
 
 	* include/freetype/freetype.h: Bump patch version to 9.
diff --git a/docs/CHANGES b/docs/CHANGES
index e7eebf7..83e57c7 100644
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -33,6 +33,8 @@ CHANGES BETWEEN 2.3.9 and 2.3.8
     - `FT_Get_Advance' (and `FT_Get_Advances') returned bad values for
       almost all font formats except TrueType fonts.
 
+    - Fix a bug in the SFNT kerning table loader/parser which could crash
+      the engine if certain malformed tables were encountered.
 
   II. IMPORTANT CHANGES
 
diff --git a/src/sfnt/ttkern.c b/src/sfnt/ttkern.c
index 28e52c3..52f9574 100644
--- a/src/sfnt/ttkern.c
+++ b/src/sfnt/ttkern.c
@@ -103,6 +103,9 @@
 
       p_next += length;
 
+      if (p_next > p_limit)  /* handle broken table */
+         p_next = p_limit;
+
       /* only use horizontal kerning tables */
       if ( ( coverage & ~8 ) != 0x0001 ||
            p + 8 > p_limit             )
@@ -111,8 +114,8 @@
       num_pairs = FT_NEXT_USHORT( p );
       p        += 6;
 
-      if ( p + 6 * num_pairs > p_limit )
-        goto NextTable;
+      if ( (p_next - p)/6 < (int)num_pairs ) /* handle broken count */
+        num_pairs = (FT_UInt)((p_next - p)/6);
 
       avail |= mask;
 
@@ -181,18 +184,22 @@
     FT_Int    result = 0;
     FT_UInt   count, mask = 1;
     FT_Byte*  p       = face->kern_table;
+    FT_Byte*  p_limit = p + face->kern_table_size;
 
 
     p   += 4;
     mask = 0x0001;
 
-    for ( count = face->num_kern_tables; count > 0; count--, mask <<= 1 )
+    for ( count = face->num_kern_tables;
+          count > 0 && p + 6 <= p_limit;
+          count--, mask <<= 1 )
     {
       FT_Byte* base     = p;
       FT_Byte* next     = base;
       FT_UInt  version  = FT_NEXT_USHORT( p );
       FT_UInt  length   = FT_NEXT_USHORT( p );
       FT_UInt  coverage = FT_NEXT_USHORT( p );
+      FT_UInt  num_pairs;
       FT_Int   value    = 0;
 
       FT_UNUSED( version );
@@ -200,21 +207,27 @@
 
       next = base + length;
 
+      if (next > p_limit)  /* handle broken table */
+        next = p_limit;
+
       if ( ( face->kern_avail_bits & mask ) == 0 )
         goto NextTable;
 
       if ( p + 8 > next )
         goto NextTable;
 
+      num_pairs = FT_NEXT_USHORT( p );
+      p        += 6;
+
+      if ((next - p)/6 < (int)num_pairs)  /* handle broken count  */
+        num_pairs = (FT_UInt)((next - p)/6);
+
       switch ( coverage >> 8 )
       {
       case 0:
         {
-          FT_UInt   num_pairs = FT_NEXT_USHORT( p );
-          FT_ULong  key0      = TT_KERN_INDEX( left_glyph, right_glyph );
-
+          FT_ULong  key0 = TT_KERN_INDEX( left_glyph, right_glyph );
 
-          p += 6;
 
           if ( face->kern_order_bits & mask )   /* binary search */
           {