summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--src/sfnt/ttcolr.c31
2 files changed, 43 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 8c079d101..131e7c9e2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2021-06-28 Dominik Röttsches <drott@chromium.org>
+
+ [sfnt] Improve paint limit checks
+
+ Paint tables can appear before the `base_glyphs_v1` offset if the
+ font is produced with the layer list before the base glyph list. In
+ this case paint tables can occur after the layer list but before the
+ base glyph list. Checks in the 'COLR' v1 code were rejecting fonts
+ with this layout. Improve these checks by calculating a minimum
+ offset after which paint tables can occur and use that in safety
+ checks.
+
+ * src/sfnt/ttcolr.c (Colr, tt_face_load_colr): Declare
+ `paint_start_v1` and calculate that as the minimum of the end of
+ layer list and base glyph list.
+ (get_child_table_pointer, read_paint, tt_face_get_paint_layers):
+ Use that in safety checks.
+
2021-06-28 Alexei Podtelezhnikov <apodtele@gmail.com>
[raster] Clean up vertical sweep.
@@ -202,7 +220,7 @@
2021-06-09 Alexei Podtelezhnikov <apodtele@gmail.com>
- * src/truetype/ttinterp.c (TT_RunIns): Optimize tracing.
+ * src/truetype/ttinterp.c (TT_RunIns): Optimize tracing.
2021-06-09 Alexei Podtelezhnikov <apodtele@gmail.com>
diff --git a/src/sfnt/ttcolr.c b/src/sfnt/ttcolr.c
index 8db774c0d..1e297ac8c 100644
--- a/src/sfnt/ttcolr.c
+++ b/src/sfnt/ttcolr.c
@@ -41,7 +41,7 @@
/* NOTE: These are the table sizes calculated through the specs. */
#define BASE_GLYPH_SIZE 6U
-#define BASE_GLYPH_V1_RECORD_SIZE 6U
+#define BASE_GLYPH_PAINT_RECORD_SIZE 6U
#define LAYER_V1_LIST_PAINT_OFFSET_SIZE 4U
#define LAYER_V1_LIST_NUM_LAYERS_SIZE 4U
#define COLOR_STOP_SIZE 6U
@@ -83,6 +83,13 @@
FT_ULong num_layers_v1;
FT_Byte* layers_v1;
+ /*
+ * Paint tables start at the minimum of the end of the LayerList and the
+ * end of the BaseGlyphList. Record this location in a field here for
+ * safety checks when accessing paint tables.
+ */
+ FT_Byte* paints_start_v1;
+
/* The memory that backs up the `COLR' table. */
void* table;
FT_ULong table_size;
@@ -170,7 +177,7 @@
p1 = (FT_Byte*)( table + base_glyphs_offset_v1 );
num_base_glyphs_v1 = FT_PEEK_ULONG( p1 );
- if ( num_base_glyphs_v1 * BASE_GLYPH_V1_RECORD_SIZE >
+ if ( num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE >
table_size - base_glyphs_offset_v1 )
goto InvalidTable;
@@ -185,8 +192,18 @@
p1 = (FT_Byte*)( table + layer_offset_v1 );
num_layers_v1 = FT_PEEK_ULONG( p1 );
+ if ( num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE >
+ table_size - layer_offset_v1 )
+ goto InvalidTable;
+
colr->num_layers_v1 = num_layers_v1;
colr->layers_v1 = p1;
+
+ colr->paints_start_v1 =
+ FT_MIN( colr->base_glyphs_v1 +
+ colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE,
+ colr->layers_v1 +
+ colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE );
}
colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset );
@@ -367,7 +384,7 @@
child_table_p = (FT_Byte*)( paint_base + paint_offset );
- if ( child_table_p < colr->base_glyphs_v1 ||
+ if ( child_table_p < colr->paints_start_v1 ||
child_table_p >= ( (FT_Byte*)colr->table + colr->table_size ) )
return 0;
@@ -388,7 +405,7 @@
if ( !p || !colr || !colr->table )
return 0;
- if ( p < colr->base_glyphs_v1 ||
+ if ( p < colr->paints_start_v1 ||
p >= ( (FT_Byte*)colr->table + colr->table_size ) )
return 0;
@@ -608,7 +625,7 @@
* skip `numBaseGlyphV1Records` by adding 4 to start binary search
* in the array of `BaseGlyphV1Record`.
*/
- FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_V1_RECORD_SIZE;
+ FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_PAINT_RECORD_SIZE;
FT_UShort gid = FT_NEXT_USHORT( p );
@@ -704,7 +721,7 @@
/*
* First ensure that p is within COLRv1.
*/
- if ( p < colr->base_glyphs_v1 ||
+ if ( p < colr->layers_v1 ||
p >= ( (FT_Byte*)colr->table + colr->table_size ) )
return 0;
@@ -731,7 +748,7 @@
p_paint = (FT_Byte*)( colr->layers_v1 + paint_offset );
- if ( p_paint < colr->base_glyphs_v1 ||
+ if ( p_paint < colr->paints_start_v1 ||
p_paint >= ( (FT_Byte*)colr->table + colr->table_size ) )
return 0;