shithub: freetype+ttf2subf

Download patch

ref: 32f13c11a4edb2c22d5fad5dca7eb9bcdf2bcdad
parent: cff026d41599945498044d2f4dcc0e610ffb6929
author: Alexei Podtelezhnikov <[email protected]>
date: Thu Nov 25 17:38:40 EST 2021

[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.

git/fs: mount .git/fs: mount/attach disallowed
--- 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,16 +555,24 @@
     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 )
     {
-      error = FT_THROW( Invalid_File_Format );
+      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 ) )
+    {
+      FT_TRACE2(( "with record size off by %ld bytes rejected\n",
+                   (FT_Long)record_size -
+                     ( ( face->root.num_glyphs + 5 ) & ~3 ) ));
+      goto Fail;
+    }
+
     if ( FT_QNEW_ARRAY( face->hdmx_record_sizes, num_records ) )
       goto Fail;
 
@@ -586,6 +588,8 @@
     face->hdmx_record_count = nn;
     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;