From 04272824e0f6454d4d4c61ea4f1f77f27b4aa05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20R=C3=B6ttsches?= Date: Mon, 17 Oct 2022 18:18:49 +0300 Subject: [PATCH] [sfnt] Guard individual `COLR` v1 paint field reads. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * src/sfnt/ttcolr.c (ENSURE_READ_BYTES): New macro. (read_paint): Use it – after the start pointer `p` has been checked for whether it allows reading the format byte, each successive paint table field read need to be bounds-checked before reading further values. Reported as https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=52404 --- src/sfnt/ttcolr.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/sfnt/ttcolr.c b/src/sfnt/ttcolr.c index c65ca3da5..ecebda569 100644 --- a/src/sfnt/ttcolr.c +++ b/src/sfnt/ttcolr.c @@ -69,6 +69,11 @@ &tt_driver_class && \ ((TT_Driver)FT_FACE_DRIVER( face ))->enable_variable_colrv1 ) +#define ENSURE_READ_BYTES( byte_size ) \ + if ( p < colr->paints_start_v1 || \ + p > (FT_Byte*)colr->table + colr->table_size - byte_size ) \ + return 0; + typedef enum FT_PaintFormat_Internal_ { @@ -695,6 +700,7 @@ (FT_PaintFormat_Internal)apaint->format == FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID ) { + ENSURE_READ_BYTES( 4 ); apaint->u.solid.color.palette_index = FT_NEXT_USHORT( p ); apaint->u.solid.color.alpha = FT_NEXT_SHORT( p ); @@ -703,6 +709,7 @@ FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID && VARIABLE_COLRV1_ENABLED ) { + ENSURE_READ_BYTES( 4 ); var_index_base = FT_NEXT_ULONG( p ); if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1, @@ -720,6 +727,7 @@ else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH ) { + ENSURE_READ_BYTES(2); apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p ); return 1; @@ -746,9 +754,11 @@ return 0; /* - * In order to support variations expose these as FT_Fixed 16.16 values so - * that we can support fractional values after interpolation. + * In order to support variations expose these as FT_Fixed 16.16 + * values so that we can support fractional values after + * interpolation. */ + ENSURE_READ_BYTES( 12 ); apaint->u.linear_gradient.p0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.linear_gradient.p0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.linear_gradient.p1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); @@ -759,6 +769,7 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT if ( do_read_var && VARIABLE_COLRV1_ENABLED ) { + ENSURE_READ_BYTES( 4 ); var_index_base = FT_NEXT_ULONG ( p ); if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, @@ -792,11 +803,14 @@ do_read_var ) ) return 0; + /* In the OpenType specification, `r0` and `r1` are defined as */ /* `UFWORD`. Since FreeType doesn't have a corresponding 16.16 */ /* format we convert to `FWORD` and replace negative values with */ /* (32bit) `FT_INT_MAX`. */ + ENSURE_READ_BYTES( 12 ); + apaint->u.radial_gradient.c0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.radial_gradient.c0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); @@ -812,6 +826,7 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT if ( do_read_var && VARIABLE_COLRV1_ENABLED ) { + ENSURE_READ_BYTES( 4 ); var_index_base = FT_NEXT_ULONG ( p ); if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, @@ -846,6 +861,8 @@ do_read_var) ) return 0; + ENSURE_READ_BYTES( 8 ); + apaint->u.sweep_gradient.center.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.sweep_gradient.center.y = @@ -859,6 +876,7 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT if ( do_read_var && VARIABLE_COLRV1_ENABLED ) { + ENSURE_READ_BYTES( 4 ); var_index_base = FT_NEXT_ULONG ( p ); if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, @@ -882,6 +900,7 @@ if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH ) { + ENSURE_READ_BYTES( 2 ); apaint->u.glyph.paint.p = child_table_p; apaint->u.glyph.paint.insert_root_transform = 0; apaint->u.glyph.glyphID = FT_NEXT_USHORT( p ); @@ -905,6 +924,7 @@ * The following matrix coefficients are encoded as * OpenType 16.16 fixed-point values. */ + ENSURE_READ_BYTES( 24 ); apaint->u.transform.affine.xx = FT_NEXT_LONG( p ); apaint->u.transform.affine.yx = FT_NEXT_LONG( p ); apaint->u.transform.affine.xy = FT_NEXT_LONG( p ); @@ -917,6 +937,7 @@ FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM && VARIABLE_COLRV1_ENABLED ) { + ENSURE_READ_BYTES( 4 ); var_index_base = FT_NEXT_ULONG( p ); if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, @@ -944,6 +965,7 @@ apaint->u.translate.paint.p = child_table_p; apaint->u.translate.paint.insert_root_transform = 0; + ENSURE_READ_BYTES( 4 ); apaint->u.translate.dx = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.translate.dy = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); @@ -952,6 +974,7 @@ FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE && VARIABLE_COLRV1_ENABLED ) { + ENSURE_READ_BYTES( 4 ); var_index_base = FT_NEXT_ULONG( p ); if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, @@ -976,6 +999,7 @@ apaint->u.scale.paint.insert_root_transform = 0; /* All scale paints get at least one scale value. */ + ENSURE_READ_BYTES( 2 ); apaint->u.scale.scale_x = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); /* Non-uniform ones read an extra y value. */ @@ -986,7 +1010,10 @@ FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || (FT_PaintFormat_Internal)apaint->format == FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ) + { + ENSURE_READ_BYTES( 2 ); apaint->u.scale.scale_y = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + } else apaint->u.scale.scale_y = apaint->u.scale.scale_x; @@ -1001,6 +1028,7 @@ (FT_PaintFormat_Internal)apaint->format == FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) { + ENSURE_READ_BYTES( 4 ); apaint->u.scale.center_x = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); apaint->u.scale.center_y = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); } @@ -1023,6 +1051,7 @@ FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) && VARIABLE_COLRV1_ENABLED ) { + ENSURE_READ_BYTES( 4 ); var_index_base = FT_NEXT_ULONG( p ); if ( (FT_PaintFormat_Internal)apaint->format == @@ -1093,6 +1122,7 @@ apaint->u.rotate.paint.p = child_table_p; apaint->u.rotate.paint.insert_root_transform = 0; + ENSURE_READ_BYTES( 2 ); apaint->u.rotate.angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); if ( (FT_PaintFormat_Internal)apaint->format == @@ -1100,6 +1130,7 @@ (FT_PaintFormat_Internal)apaint->format == FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) { + ENSURE_READ_BYTES( 4 ); apaint->u.rotate.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.rotate.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); } @@ -1119,6 +1150,7 @@ FT_UInt num_deltas = 0; + ENSURE_READ_BYTES( 4 ); var_index_base = FT_NEXT_ULONG( p ); if ( (FT_PaintFormat_Internal)apaint->format == @@ -1162,6 +1194,7 @@ apaint->u.skew.paint.p = child_table_p; apaint->u.skew.paint.insert_root_transform = 0; + ENSURE_READ_BYTES( 4 ); apaint->u.skew.x_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.skew.y_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); @@ -1170,6 +1203,7 @@ (FT_PaintFormat_Internal)apaint->format == FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) { + ENSURE_READ_BYTES( 4 ); apaint->u.skew.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.skew.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); } @@ -1187,6 +1221,7 @@ FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) && VARIABLE_COLRV1_ENABLED ) { + ENSURE_READ_BYTES( 4 ); var_index_base = FT_NEXT_ULONG( p ); if ( (FT_PaintFormat_Internal)apaint->format == @@ -1228,6 +1263,7 @@ apaint->u.composite.source_paint.p = child_table_p; apaint->u.composite.source_paint.insert_root_transform = 0; + ENSURE_READ_BYTES( 1 ); composite_mode = FT_NEXT_BYTE( p ); if ( composite_mode >= FT_COLR_COMPOSITE_MAX ) return 0;