Commit 92359bd8851448ba40167affdf5663659a7b28f0

Werner Lemberg 2015-02-07T09:47:23

[sfnt] Fix Savannah bug #44184. * src/sfnt/ttload.c (check_table_dir, tt_face_load_font_dir): No longer reject `htmx' and `vmtx' tables with invalid length but sanitize them.

diff --git a/ChangeLog b/ChangeLog
index 7828f20..78119aa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2015-02-07  Werner Lemberg  <wl@gnu.org>
+
+	[sfnt] Fix Savannah bug #44184.
+
+	* src/sfnt/ttload.c (check_table_dir, tt_face_load_font_dir): No
+	longer reject `htmx' and `vmtx' tables with invalid length but
+	sanitize them.
+
 2015-02-06  Jon Anderson  <jon@websupergoo.com>
 
 	[truetype] Fix regression in the incremental glyph loader.
diff --git a/src/sfnt/ttload.c b/src/sfnt/ttload.c
index 8606e85..8b1f2d0 100644
--- a/src/sfnt/ttload.c
+++ b/src/sfnt/ttload.c
@@ -208,12 +208,23 @@
 
       /* we ignore invalid tables */
 
-      /* table.Offset + table.Length > stream->size ? */
-      if ( table.Length > stream->size                ||
-           table.Offset > stream->size - table.Length )
-      {
-        FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn ));
+      if ( table.Offset > stream->size )
         continue;
+      else if ( table.Length > stream->size - table.Offset )
+      {
+        /* Some tables have such a simple structure that clipping its     */
+        /* contents is harmless.  This also makes FreeType less sensitive */
+        /* to invalid table lengths (which programs like Acroread seem to */
+        /* ignore in general).                                            */
+
+        if ( table.Tag == TTAG_hmtx ||
+             table.Tag == TTAG_vmtx )
+          valid_entries++;
+        else
+        {
+          FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn ));
+          continue;
+        }
       }
       else
         valid_entries++;
@@ -397,12 +408,36 @@
       entry->Offset   = FT_GET_ULONG();
       entry->Length   = FT_GET_ULONG();
 
-      /* ignore invalid tables */
+      /* ignore invalid tables that can't be sanitized */
 
-      /* entry->Offset + entry->Length > stream->size ? */
-      if ( entry->Length > stream->size                 ||
-           entry->Offset > stream->size - entry->Length )
+      if ( entry->Offset > stream->size )
         continue;
+      else if ( entry->Length > stream->size - entry->Offset )
+      {
+        if ( entry->Tag == TTAG_hmtx ||
+             entry->Tag == TTAG_vmtx )
+        {
+          FT_ULong  old_length = entry->Length;
+
+
+          /* make metrics table length a multiple of 4 */
+          entry->Length = ( stream->size - entry->Offset ) & ~3;
+
+          FT_TRACE2(( "  %c%c%c%c  %08lx  %08lx  %08lx"
+                      " (sanitized; original length %08lx)\n",
+                      (FT_Char)( entry->Tag >> 24 ),
+                      (FT_Char)( entry->Tag >> 16 ),
+                      (FT_Char)( entry->Tag >> 8  ),
+                      (FT_Char)( entry->Tag       ),
+                      entry->Offset,
+                      entry->Length,
+                      entry->CheckSum,
+                      old_length ));
+          entry++;
+        }
+        else
+          continue;
+      }
       else
       {
         FT_TRACE2(( "  %c%c%c%c  %08lx  %08lx  %08lx\n",