Handle some integer overflow run-time errors (#46149, #48979). This commit (mainly for 32bit CPUs) is the first of a series of similar commits to handle known integer overflows. Basically, all of them are harmless, since they affect rendering of glyphs only, not posing security threats. It is expected that fuzzying will show up more overflows, to be fixed in due course. The idea is to mark places where overflows can occur, using macros that simply cast to unsigned integers, because overflow arithmetic is well defined in this case. Doing so suppresses run-time errors of sanitizers without adding computational overhead. * include/freetype/internal/ftcalc.h (OVERFLOW_ADD_INT, OVERFLOW_SUB_INT, OVERFLOW_MUL_INT, OVERFLOW_ADD_LONG, OVERFLOW_SUB_LONG, OVERFLOW_MUL_LONG): New macros. * src/base/ftcalc.c (FT_RoundFix, FT_CeilFix, FT_Matrix_Multiply, FT_Matrix_Multiply_Scaled, FT_Vector_Transform_Scaled, ft_corner_orientation): Use new macros. * src/base/ftoutln.c (FT_Outline_Get_Orientation): Use new macros.
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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
diff --git a/ChangeLog b/ChangeLog
index 5d7c7d8..7a9244e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2017-05-29 Werner Lemberg <wl@gnu.org>
+
+ Handle some integer overflow run-time errors (#46149, #48979).
+
+ This commit (mainly for 32bit CPUs) is the first of a series of
+ similar commits to handle known integer overflows. Basically, all
+ of them are harmless, since they affect rendering of glyphs only,
+ not posing security threats. It is expected that fuzzying will show
+ up more overflows, to be fixed in due course.
+
+ The idea is to mark places where overflows can occur, using macros
+ that simply cast to unsigned integers, because overflow arithmetic
+ is well defined in this case. Doing so suppresses run-time errors
+ of sanitizers without adding computational overhead.
+
+ * include/freetype/internal/ftcalc.h (OVERFLOW_ADD_INT,
+ OVERFLOW_SUB_INT, OVERFLOW_MUL_INT, OVERFLOW_ADD_LONG,
+ OVERFLOW_SUB_LONG, OVERFLOW_MUL_LONG): New macros.
+
+ * src/base/ftcalc.c (FT_RoundFix, FT_CeilFix, FT_Matrix_Multiply,
+ FT_Matrix_Multiply_Scaled, FT_Vector_Transform_Scaled,
+ ft_corner_orientation): Use new macros.
+
+ * src/base/ftoutln.c (FT_Outline_Get_Orientation): Use new macros.
+
2017-05-28 Werner Lemberg <wl@gnu.org>
* include/freetype/internal/ftcalc.h (FLOAT_TO_FIXED): Remove.
diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h
index 2989fbb..bd7f6a3 100644
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -4327,6 +4327,9 @@ FT_BEGIN_HEADER
/* `a' rounded to the nearest 16.16 fixed integer, halfway cases away */
/* from zero. */
/* */
+ /* <Note> */
+ /* The function uses wrap-around arithmetic. */
+ /* */
FT_EXPORT( FT_Fixed )
FT_RoundFix( FT_Fixed a );
@@ -4345,6 +4348,9 @@ FT_BEGIN_HEADER
/* <Return> */
/* `a' rounded towards plus infinity. */
/* */
+ /* <Note> */
+ /* The function uses wrap-around arithmetic. */
+ /* */
FT_EXPORT( FT_Fixed )
FT_CeilFix( FT_Fixed a );
diff --git a/include/freetype/ftglyph.h b/include/freetype/ftglyph.h
index 79879a7..5869bc1 100644
--- a/include/freetype/ftglyph.h
+++ b/include/freetype/ftglyph.h
@@ -566,6 +566,9 @@ FT_BEGIN_HEADER
/* <Note> */
/* The result is undefined if either `a' or `b' is zero. */
/* */
+ /* Since the function uses wrap-around arithmetic, results become */
+ /* meaningless if the arguments are very large. */
+ /* */
FT_EXPORT( void )
FT_Matrix_Multiply( const FT_Matrix* a,
FT_Matrix* b );
diff --git a/include/freetype/internal/ftcalc.h b/include/freetype/internal/ftcalc.h
index df6c376..1cd32c8 100644
--- a/include/freetype/internal/ftcalc.h
+++ b/include/freetype/internal/ftcalc.h
@@ -408,6 +408,29 @@ FT_BEGIN_HEADER
#define ROUND_F26DOT6( x ) ( x >= 0 ? ( ( (x) + 32 ) & -64 ) \
: ( -( ( 32 - (x) ) & -64 ) ) )
+ /*
+ * The following macros have two purposes.
+ *
+ * . Tag places where overflow is expected and harmless.
+ *
+ * . Avoid run-time sanitizer errors.
+ *
+ * Use with care!
+ */
+#define OVERFLOW_ADD_INT( a, b ) \
+ (FT_Int)( (FT_UInt)(a) + (FT_UInt)(b) )
+#define OVERFLOW_SUB_INT( a, b ) \
+ (FT_Int)( (FT_UInt)(a) - (FT_UInt)(b) )
+#define OVERFLOW_MUL_INT( a, b ) \
+ (FT_Int)( (FT_UInt)(a) * (FT_UInt)(b) )
+
+#define OVERFLOW_ADD_LONG( a, b ) \
+ (FT_Long)( (FT_ULong)(a) + (FT_ULong)(b) )
+#define OVERFLOW_SUB_LONG( a, b ) \
+ (FT_Long)( (FT_ULong)(a) - (FT_ULong)(b) )
+#define OVERFLOW_MUL_LONG( a, b ) \
+ (FT_Long)( (FT_ULong)(a) * (FT_ULong)(b) )
+
FT_END_HEADER
diff --git a/src/base/ftcalc.c b/src/base/ftcalc.c
index b4b66e4..bc1c47f 100644
--- a/src/base/ftcalc.c
+++ b/src/base/ftcalc.c
@@ -87,7 +87,8 @@
FT_EXPORT_DEF( FT_Fixed )
FT_RoundFix( FT_Fixed a )
{
- return ( a + 0x8000L - ( a < 0 ) ) & ~0xFFFFL;
+ return ( OVERFLOW_ADD_LONG( a,
+ 0x8000L - ( a < 0 ) ) ) & ~0xFFFFL;
}
@@ -96,7 +97,7 @@
FT_EXPORT_DEF( FT_Fixed )
FT_CeilFix( FT_Fixed a )
{
- return ( a + 0xFFFFL ) & ~0xFFFFL;
+ return ( OVERFLOW_ADD_LONG( a, 0xFFFFL ) ) & ~0xFFFFL;
}
@@ -667,13 +668,19 @@
if ( !a || !b )
return;
- xx = FT_MulFix( a->xx, b->xx ) + FT_MulFix( a->xy, b->yx );
- xy = FT_MulFix( a->xx, b->xy ) + FT_MulFix( a->xy, b->yy );
- yx = FT_MulFix( a->yx, b->xx ) + FT_MulFix( a->yy, b->yx );
- yy = FT_MulFix( a->yx, b->xy ) + FT_MulFix( a->yy, b->yy );
-
- b->xx = xx; b->xy = xy;
- b->yx = yx; b->yy = yy;
+ xx = OVERFLOW_ADD_LONG( FT_MulFix( a->xx, b->xx ),
+ FT_MulFix( a->xy, b->yx ) );
+ xy = OVERFLOW_ADD_LONG( FT_MulFix( a->xx, b->xy ),
+ FT_MulFix( a->xy, b->yy ) );
+ yx = OVERFLOW_ADD_LONG( FT_MulFix( a->yx, b->xx ),
+ FT_MulFix( a->yy, b->yx ) );
+ yy = OVERFLOW_ADD_LONG( FT_MulFix( a->yx, b->xy ),
+ FT_MulFix( a->yy, b->yy ) );
+
+ b->xx = xx;
+ b->xy = xy;
+ b->yx = yx;
+ b->yy = yy;
}
@@ -723,13 +730,19 @@
if ( !a || !b )
return;
- xx = FT_MulDiv( a->xx, b->xx, val ) + FT_MulDiv( a->xy, b->yx, val );
- xy = FT_MulDiv( a->xx, b->xy, val ) + FT_MulDiv( a->xy, b->yy, val );
- yx = FT_MulDiv( a->yx, b->xx, val ) + FT_MulDiv( a->yy, b->yx, val );
- yy = FT_MulDiv( a->yx, b->xy, val ) + FT_MulDiv( a->yy, b->yy, val );
-
- b->xx = xx; b->xy = xy;
- b->yx = yx; b->yy = yy;
+ xx = OVERFLOW_ADD_LONG( FT_MulDiv( a->xx, b->xx, val ),
+ FT_MulDiv( a->xy, b->yx, val ) );
+ xy = OVERFLOW_ADD_LONG( FT_MulDiv( a->xx, b->xy, val ),
+ FT_MulDiv( a->xy, b->yy, val ) );
+ yx = OVERFLOW_ADD_LONG( FT_MulDiv( a->yx, b->xx, val ),
+ FT_MulDiv( a->yy, b->yx, val ) );
+ yy = OVERFLOW_ADD_LONG( FT_MulDiv( a->yx, b->xy, val ),
+ FT_MulDiv( a->yy, b->yy, val ) );
+
+ b->xx = xx;
+ b->xy = xy;
+ b->yx = yx;
+ b->yy = yy;
}
@@ -748,11 +761,10 @@
if ( !vector || !matrix )
return;
- xz = FT_MulDiv( vector->x, matrix->xx, val ) +
- FT_MulDiv( vector->y, matrix->xy, val );
-
- yz = FT_MulDiv( vector->x, matrix->yx, val ) +
- FT_MulDiv( vector->y, matrix->yy, val );
+ xz = OVERFLOW_ADD_LONG( FT_MulDiv( vector->x, matrix->xx, val ),
+ FT_MulDiv( vector->y, matrix->xy, val ) );
+ yz = OVERFLOW_ADD_LONG( FT_MulDiv( vector->x, matrix->yx, val ),
+ FT_MulDiv( vector->y, matrix->yy, val ) );
vector->x = xz;
vector->y = yz;
@@ -914,11 +926,13 @@
FT_Int result;
- if ( (FT_ULong)FT_ABS( in_x ) + (FT_ULong)FT_ABS( out_y ) <= 131071UL &&
- (FT_ULong)FT_ABS( in_y ) + (FT_ULong)FT_ABS( out_x ) <= 131071UL )
+ /* we silently ignore overflow errors, since such large values */
+ /* lead to even more (harmless) rendering errors later on */
+ if ( OVERFLOW_ADD_LONG( FT_ABS( in_x ), FT_ABS( out_y ) ) <= 131071L &&
+ OVERFLOW_ADD_LONG( FT_ABS( in_y ), FT_ABS( out_x ) ) <= 131071L )
{
- FT_Long z1 = in_x * out_y;
- FT_Long z2 = in_y * out_x;
+ FT_Long z1 = OVERFLOW_MUL_LONG( in_x, out_y );
+ FT_Long z2 = OVERFLOW_MUL_LONG( in_y, out_x );
if ( z1 > z2 )
diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c
index 464a066..794ddbc 100644
--- a/src/base/ftoutln.c
+++ b/src/base/ftoutln.c
@@ -1088,7 +1088,9 @@
v_cur.x = points[n].x >> xshift;
v_cur.y = points[n].y >> yshift;
- area += ( v_cur.y - v_prev.y ) * ( v_cur.x + v_prev.x );
+ area = OVERFLOW_ADD_LONG(
+ area,
+ ( v_cur.y - v_prev.y ) * ( v_cur.x + v_prev.x ) );
v_prev = v_cur;
}