Commit 1c0862938d798a1e79a3a087d4a93ff8628c13d2

Dominik Röttsches 2021-04-02T06:55:29

[sfnt] Check validity of pointer location of `read_color_line`. * src/sfnt/ttcolr.c (get_child_table_pointer): New function to fetch child table pointer early for all paint formats that compute a child table pointer. (read_color_line, read_paint): Updated. (tt_face_get_colorline_stops): Check `colr->table`.

diff --git a/ChangeLog b/ChangeLog
index ed2d094..ec0d132 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2021-03-30  Dominik Röttsches  <drott@chromium.org>
+
+	[sfnt] Check validity of pointer location of `read_color_line`.
+
+	* src/sfnt/ttcolr.c (get_child_table_pointer): New function to fetch
+	child table pointer early for all paint formats that compute a child
+	table pointer.
+	(read_color_line, read_paint): Updated.
+	(tt_face_get_colorline_stops): Check `colr->table`.
+
 2021-03-28  Nikhil Ramakrishnan  <ramakrishnan.nikhil@gmail.com>
 
 	[docs] Update docwriter stylesheet for 1.3.1.
diff --git a/src/sfnt/ttcolr.c b/src/sfnt/ttcolr.c
index 1430cfc..2f1ae52 100644
--- a/src/sfnt/ttcolr.c
+++ b/src/sfnt/ttcolr.c
@@ -320,13 +320,11 @@
 
 
   static FT_Bool
-  read_color_line( FT_Byte*      paint_base,
-                   FT_ULong      colorline_offset,
+  read_color_line( FT_Byte*      color_line_p,
                    FT_ColorLine  *colorline )
   {
-    FT_Byte*        p = (FT_Byte *)( paint_base + colorline_offset );
+    FT_Byte*        p = color_line_p;
     FT_PaintExtend  paint_extend;
-    /* TODO: Check pointer limits. */
 
 
     paint_extend = FT_NEXT_BYTE( p );
@@ -343,14 +341,53 @@
   }
 
 
+  /*
+   * Read a paint offset for `FT_Paint*` objects that have them and check
+   * whether it is within reasonable limits within the font and the COLR
+   * table.
+   *
+   * Return 1 on success, 0 on failure.
+   */
+  static FT_Bool
+  get_child_table_pointer ( Colr*      colr,
+                            FT_Byte*   paint_base,
+                            FT_Byte**  p,
+                            FT_Byte**  child_table_pointer )
+  {
+    FT_UInt32  paint_offset;
+    FT_Byte*   child_table_p;
+
+
+    if ( !child_table_pointer )
+      return 0;
+
+    paint_offset = FT_NEXT_UOFF3( *p );
+    if ( !paint_offset )
+      return 0;
+
+    child_table_p = (FT_Byte*)( paint_base + paint_offset );
+
+    if ( child_table_p < colr->base_glyphs_v1                          ||
+         child_table_p >= ( (FT_Byte*)colr->table + colr->table_size ) )
+      return 0;
+
+    *child_table_pointer = child_table_p;
+    return 1;
+  }
+
+
   static FT_Bool
   read_paint( Colr*           colr,
               FT_Byte*        p,
               FT_COLR_Paint*  apaint )
   {
-    FT_Byte*  paint_base = p;
+    FT_Byte*  paint_base     = p;
+    FT_Byte*  child_table_p  = NULL;
 
 
+    if ( !p || !colr || !colr->table )
+      return 0;
+
     apaint->format = FT_NEXT_BYTE( p );
 
     if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX )
@@ -382,38 +419,34 @@
       return 1;
     }
 
-    if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH )
-    {
-      FT_UInt32  paint_offset;
-      FT_Byte*   paint_p;
-
-
-      paint_offset = FT_NEXT_UOFF3( p );
-      if ( !paint_offset )
-        return 0;
-
-      paint_p = (FT_Byte*)( paint_base + paint_offset );
-      if ( paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
-        return 0;
-
-      apaint->u.glyph.paint.p                     = paint_p;
-      apaint->u.glyph.paint.insert_root_transform = 0;
-      apaint->u.glyph.glyphID                     = FT_NEXT_USHORT( p );
-    }
-
     else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID )
     {
       apaint->u.solid.color.palette_index = FT_NEXT_USHORT ( p );
       apaint->u.solid.color.alpha         = FT_NEXT_USHORT ( p );
+
+      return 1;
     }
 
-    else if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT )
+    else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH )
     {
-      FT_ULong  color_line_offset = FT_NEXT_OFF3( p );
+      apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p );
+
+      return 1;
+    }
+
+    /*
+     * Grouped below here are all paint formats that have an offset to a
+     * child paint table as the first entry (for example, a color line or a
+     * child paint table).  Retrieve that and determine whether that paint
+     * offset is valid first.
+     */
 
+    if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
+      return 0;
 
-      if ( !read_color_line( paint_base,
-                             color_line_offset,
+    if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT )
+    {
+      if ( !read_color_line( child_table_p,
                              &apaint->u.linear_gradient.colorline ) )
         return 0;
 
@@ -423,15 +456,13 @@
       apaint->u.linear_gradient.p1.y = FT_NEXT_SHORT ( p );
       apaint->u.linear_gradient.p2.x = FT_NEXT_SHORT ( p );
       apaint->u.linear_gradient.p2.y = FT_NEXT_SHORT ( p );
+
+      return 1;
     }
 
     else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT )
     {
-      FT_ULong  color_line_offset = color_line_offset = FT_NEXT_OFF3( p );
-
-
-      if ( !read_color_line( paint_base,
-                             color_line_offset,
+      if ( !read_color_line( child_table_p,
                              &apaint->u.radial_gradient.colorline ) )
         return 0;
 
@@ -444,15 +475,13 @@
       apaint->u.radial_gradient.c1.y = FT_NEXT_SHORT ( p );
 
       apaint->u.radial_gradient.r1 = FT_NEXT_USHORT ( p );
+
+      return 1;
     }
 
     else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT )
     {
-      FT_ULong  color_line_offset = color_line_offset = FT_NEXT_OFF3( p );
-
-
-      if ( !read_color_line( paint_base,
-                             color_line_offset,
+      if ( !read_color_line( child_table_p,
                              &apaint->u.sweep_gradient.colorline ) )
         return 0;
 
@@ -461,23 +490,22 @@
 
       apaint->u.sweep_gradient.start_angle = FT_NEXT_LONG( p );
       apaint->u.sweep_gradient.end_angle = FT_NEXT_LONG( p );
+
+      return 1;
     }
 
-    else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORMED )
+    if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH )
     {
-      FT_UInt32  paint_offset;
-      FT_Byte*   paint_p;
-
-
-      paint_offset = FT_NEXT_UOFF3( p );
-      if ( !paint_offset )
-        return 0;
+      apaint->u.glyph.paint.p                     = child_table_p;
+      apaint->u.glyph.paint.insert_root_transform = 0;
+      apaint->u.glyph.glyphID                     = FT_NEXT_USHORT( p );
 
-      paint_p = (FT_Byte*)( paint_base + paint_offset );
-      if ( paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
-        return 0;
+      return 1;
+    }
 
-      apaint->u.transformed.paint.p                     = paint_p;
+    else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORMED )
+    {
+      apaint->u.transformed.paint.p                     = child_table_p;
       apaint->u.transformed.paint.insert_root_transform = 0;
 
       apaint->u.transformed.affine.xx = FT_NEXT_LONG( p );
@@ -486,67 +514,37 @@
       apaint->u.transformed.affine.yy = FT_NEXT_LONG( p );
       apaint->u.transformed.affine.dx = FT_NEXT_LONG( p );
       apaint->u.transformed.affine.dy = FT_NEXT_LONG( p );
+
+      return 1;
     }
 
     else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSLATE )
     {
-      FT_UInt32  paint_offset;
-      FT_Byte*   paint_p;
-
-
-      paint_offset = FT_NEXT_UOFF3( p );
-      if ( !paint_offset )
-        return 0;
-
-      paint_p = (FT_Byte*)( paint_base + paint_offset );
-      if ( paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
-        return 0;
-
-      apaint->u.translate.paint.p                     = paint_p;
+      apaint->u.translate.paint.p                     = child_table_p;
       apaint->u.translate.paint.insert_root_transform = 0;
 
       apaint->u.translate.dx = FT_NEXT_LONG( p );
       apaint->u.translate.dy = FT_NEXT_LONG( p );
+
+      return 1;
     }
 
     else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE )
     {
-      FT_UInt32  paint_offset;
-      FT_Byte*   paint_p;
-
-
-      paint_offset = FT_NEXT_UOFF3( p );
-      if ( !paint_offset )
-        return 0;
-
-      paint_p = (FT_Byte*)( paint_base + paint_offset );
-      if ( paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
-        return 0;
-
-      apaint->u.rotate.paint.p                     = paint_p;
+      apaint->u.rotate.paint.p                     = child_table_p;
       apaint->u.rotate.paint.insert_root_transform = 0;
 
       apaint->u.rotate.angle = FT_NEXT_LONG( p );
 
       apaint->u.rotate.center_x = FT_NEXT_LONG( p );
       apaint->u.rotate.center_y = FT_NEXT_LONG( p );
+
+      return 1;
     }
 
     else if ( apaint->format == FT_COLR_PAINTFORMAT_SKEW )
     {
-      FT_UInt32  paint_offset;
-      FT_Byte*   paint_p;
-
-
-      paint_offset = FT_NEXT_UOFF3( p );
-      if ( !paint_offset )
-        return 0;
-
-      paint_p = (FT_Byte*)( paint_base + paint_offset );
-      if ( paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
-        return 0;
-
-      apaint->u.skew.paint.p                     = paint_p;
+      apaint->u.skew.paint.p                     = child_table_p;
       apaint->u.skew.paint.insert_root_transform = 0;
 
       apaint->u.skew.x_skew_angle = FT_NEXT_LONG( p );
@@ -554,31 +552,17 @@
 
       apaint->u.skew.center_x = FT_NEXT_LONG( p );
       apaint->u.skew.center_y = FT_NEXT_LONG( p );
+
+      return 1;
     }
 
     else if ( apaint->format == FT_COLR_PAINTFORMAT_COMPOSITE )
     {
-      FT_UInt32  source_paint_offset;
-      FT_Byte*   source_paint_p;
-
-      FT_UInt32  backdrop_paint_offset;
-      FT_Byte*   backdrop_paint_p;
+      FT_UInt  composite_mode;
 
-      FT_UInt    composite_mode;
 
-
-      source_paint_offset = FT_NEXT_UOFF3( p );
-      if ( !source_paint_offset )
-        return 0;
-
-      source_paint_p = (FT_Byte*)( paint_base + source_paint_offset );
-      if ( source_paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
-        return 0;
-
-      apaint->u.composite.source_paint.p =
-        source_paint_p;
-      apaint->u.composite.source_paint.insert_root_transform =
-        0;
+      apaint->u.composite.source_paint.p                     = child_table_p;
+      apaint->u.composite.source_paint.insert_root_transform = 0;
 
       composite_mode = FT_NEXT_BYTE( p );
       if ( composite_mode >= FT_COLR_COMPOSITE_MAX )
@@ -586,24 +570,18 @@
 
       apaint->u.composite.composite_mode = composite_mode;
 
-      backdrop_paint_offset = FT_NEXT_UOFF3( p );
-      if ( !backdrop_paint_offset )
-        return 0;
-
-      backdrop_paint_p = (FT_Byte*)( paint_base + backdrop_paint_offset );
-      if ( backdrop_paint_p > ( (FT_Byte*)colr->table + colr->table_size ) )
-        return 0;
+      if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
+         return 0;
 
       apaint->u.composite.backdrop_paint.p =
-        backdrop_paint_p;
+        child_table_p;
       apaint->u.composite.backdrop_paint.insert_root_transform =
         0;
-    }
 
-    else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH )
-      apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p );
+      return 1;
+    }
 
-    return 1;
+    return 0;
   }
 
 
@@ -759,7 +737,7 @@
     FT_Byte*  p;
 
 
-    if ( !colr )
+    if ( !colr || !colr->table )
       return 0;
 
     if ( iterator->current_color_stop >= iterator->num_color_stops )