[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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
diff --git a/ChangeLog b/ChangeLog
index aa0fd99..7b5619a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2016-12-30 Werner Lemberg <wl@gnu.org>
+
+ [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 <wl@gnu.org>
[truetype] Variation font API stability issues.
diff --git a/src/tools/ftfuzzer/ftfuzzer.cc b/src/tools/ftfuzzer/ftfuzzer.cc
index be8a473..535be3f 100644
--- 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;
}