Commit 32f13c11a4edb2c22d5fad5dca7eb9bcdf2bcdad

Alexei Podtelezhnikov 2021-11-25T22:38:40

[truetype] Quietly reject out-of-spec `hdmx` tables. The `hdmx` table is optional and can be safely rejected without an error if it does not follow specifications. The record size must be equal to the number of glyphs + 2 + 32-bit padding. * src/truetype/ttpload.c (tt_face_load_hdmx): Thoroughly check the record size and improve tracing.

diff --git a/src/truetype/ttpload.c b/src/truetype/ttpload.c
index 55a2238..c1ce0d6 100644
--- a/src/truetype/ttpload.c
+++ b/src/truetype/ttpload.c
@@ -547,12 +547,6 @@
     num_records = FT_NEXT_USHORT( p );
     record_size = FT_NEXT_ULONG( p );
 
-    /* The maximum number of bytes in an hdmx device record is the */
-    /* maximum number of glyphs + 2 + 32-bit padding, or 0x10004,  */
-    /* that is why `record_size' is a long (which we read as       */
-    /* unsigned long for convenience).  In practice, two bytes are */
-    /* sufficient to hold the size value.                          */
-    /*                                                             */
     /* There are at least two fonts, HANNOM-A and HANNOM-B version */
     /* 2.0 (2005), which get this wrong: The upper two bytes of    */
     /* the size value are set to 0xFF instead of 0x00.  We catch   */
@@ -561,13 +555,21 @@
     if ( record_size >= 0xFFFF0000UL )
       record_size &= 0xFFFFU;
 
+    FT_TRACE2(( "Hdmx ", num_records, record_size ));
+
     /* The limit for `num_records' is a heuristic value. */
-    if ( num_records > 255               ||
-         ( num_records > 0             &&
-           ( record_size > 0x10004UL ||
-             record_size < 4         ) ) )
+    if ( num_records > 255 || num_records == 0 )
+    {
+      FT_TRACE2(( "with unreasonable %u records rejected\n", num_records ));
+      goto Fail;
+    }
+
+    /* Out-of-spec tables are rejected. */
+    if ( (FT_Long)record_size != ( ( face->root.num_glyphs + 5 ) & ~3 ) )
     {
-      error = FT_THROW( Invalid_File_Format );
+      FT_TRACE2(( "with record size off by %ld bytes rejected\n",
+                   (FT_Long)record_size -
+                     ( ( face->root.num_glyphs + 5 ) & ~3 ) ));
       goto Fail;
     }
 
@@ -587,6 +589,8 @@
     face->hdmx_table_size   = table_size;
     face->hdmx_record_size  = record_size;
 
+    FT_TRACE2(( "%ux%lu loaded\n", num_records, record_size ));
+
   Exit:
     return error;