shithub: freetype+ttf2subf

Download patch

ref: 6b21d1281ea2eff64534d6234190a9443b1663d5
parent: 7591bf11d19e6138c6da2d9935137ce255cbec3e
author: Werner Lemberg <[email protected]>
date: Fri Dec 30 05:00:54 EST 2016

[ftfuzzer] Restrict number of tested bitmap strikes.

Malformed fonts often have large values for the number of bitmap
strikes, and FreeType doesn't check the validity of all bitmap
strikes in advance.

Reported as

  https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=353

* src/tools/ftfuzzer/ftfuzzer.cc: Include `stdlib.h' for `rand'.
(Random): Small class to provide n randomly selected numbers
(without repitition) out of the value set [0,N].
(LLVMFuzzerTestOneInput): Use it to test only up to 10 bitmap
strikes.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2016-12-30  Werner Lemberg  <[email protected]>
+
+	[ftfuzzer] Restrict number of tested bitmap strikes.
+
+	Malformed fonts often have large values for the number of bitmap
+	strikes, and FreeType doesn't check the validity of all bitmap
+	strikes in advance.
+
+	Reported as
+
+	  https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=353
+
+	* src/tools/ftfuzzer/ftfuzzer.cc: Include `stdlib.h' for `rand'.
+	(Random): Small class to provide n randomly selected numbers
+	(without repitition) out of the value set [0,N].
+	(LLVMFuzzerTestOneInput): Use it to test only up to 10 bitmap
+	strikes.
+
 2016-12-29  Werner Lemberg  <[email protected]>
 
 	[truetype] Variation font API stability issues.
--- a/src/tools/ftfuzzer/ftfuzzer.cc
+++ b/src/tools/ftfuzzer/ftfuzzer.cc
@@ -22,6 +22,7 @@
 
 #include <assert.h>
 #include <stdint.h>
+#include <stdlib.h>
 
 #include <memory>
 #include <vector>
@@ -52,8 +53,10 @@
   static int         InitResult;
 
 
-  struct FT_Global {
-    FT_Global() {
+  struct FT_Global
+  {
+    FT_Global()
+    {
       InitResult = FT_Init_FreeType( &library );
       if ( InitResult )
         return;
@@ -64,7 +67,9 @@
                        "cff",
                        "hinting-engine", &cff_hinting_engine );
     }
-    ~FT_Global() {
+
+    ~FT_Global()
+    {
       FT_Done_FreeType( library );
     }
   };
@@ -72,6 +77,53 @@
   FT_Global  global_ft;
 
 
+  // We want to select n values at random (without repitition),
+  // with 0 < n <= N.  The algorithm is taken from TAoCP, Vol. 2
+  // (Algorithm S, selection sampling technique)
+  struct Random
+  {
+    int  n;
+    int  N;
+
+    int  t; // total number of values so far
+    int  m; // number of selected values so far
+
+    Random( int n_,
+            int N_ )
+    : n( n_ ),
+      N( N_ )
+    {
+      t = 0;
+      m = 0;
+
+      // ideally, this should depend on the input file,
+      // for example, taking the sha256 as input;
+      // however, this is overkill for fuzzying tests
+      srand( 12345 );
+    }
+
+    int get()
+    {
+      if ( m >= n )
+        return -1;
+
+    Redo:
+      double  U = double(rand()) / RAND_MAX;
+
+      if ( ( N - t ) * U >= ( n - m ) )
+      {
+        t++;
+        goto Redo;
+      }
+
+      t++;
+      m++;
+
+      return t;
+    }
+  };
+
+
   static int
   archive_read_entry_data( struct archive   *ar,
                            vector<FT_Byte>  *vw )
@@ -254,15 +306,19 @@
           FT_Attach_Stream( face, &open_args );
         }
 
-        // loop over all bitmap stroke sizes
-        // and an arbitrary size for outlines
-        for ( int  fixed_sizes_index = 0;
-              fixed_sizes_index < face->num_fixed_sizes + 1;
-              fixed_sizes_index++ )
+        // loop over an arbitrary size for outlines (index 0)
+        // and up to ten arbitrarily selected bitmap stroke sizes (index 1-10)
+        int  max_idx = face->num_fixed_sizes < 10
+                         ? face->num_fixed_sizes
+                         : 10;
+
+        Random pool( max_idx, face->num_fixed_sizes );
+
+        for ( int  idx = 0; idx <= max_idx; idx++ )
         {
           FT_Int32  flags = load_flags;
 
-          if ( !fixed_sizes_index )
+          if ( !idx )
           {
             // set up 20pt at 72dpi as an arbitrary size
             if ( FT_Set_Char_Size( face, 20 * 64, 20 * 64, 72, 72 ) )
@@ -275,7 +331,7 @@
             if ( instance_index )
               continue;
 
-            if ( FT_Select_Size( face, fixed_sizes_index - 1 ) )
+            if ( FT_Select_Size( face, pool.get() - 1 ) )
               continue;
             flags |= FT_LOAD_COLOR;
           }