[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.
This commit is contained in:
Dominik Röttsches 2021-06-28 16:29:49 +03:00 committed by Werner Lemberg
parent 3a278381ae
commit 7d4e55c329
2 changed files with 43 additions and 8 deletions

View File

@ -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>

View File

@ -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;