From a764963f267b5e253a0a48fefd10efdb0b20c5b9 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Sun, 25 Sep 2016 16:29:05 +0200 Subject: [PATCH] [truetype] Sanitize only last entry of `loca' table. Without this patch, a loca sequence like `0 100000 0 100000 ...', where value 100000 is larger than the `glyf' table size, makes FreeType handle the whole `glyf' table as a single glyph again and again, which is certainly invalid (and can be very slow, too). * src/truetype/ttpload.c (tt_face_get_location): Implement. Improve tracing messages. --- ChangeLog | 12 ++++++++++++ src/truetype/ttpload.c | 32 +++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index f9be16e29..04b2d54ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2016-09-25 Werner Lemberg + + [truetype] Sanitize only last entry of `loca' table. + + Without this patch, a loca sequence like `0 100000 0 100000 ...', + where value 100000 is larger than the `glyf' table size, makes + FreeType handle the whole `glyf' table as a single glyph again and + again, which is certainly invalid (and can be very slow, too). + + * src/truetype/ttpload.c (tt_face_get_location): Implement. + Improve tracing messages. + 2016-09-25 Werner Lemberg * src/tools/ftfuzzer/ftfuzzer.cc (LLVMFuzzerTestOneInput): Fix typo. diff --git a/src/truetype/ttpload.c b/src/truetype/ttpload.c index ca158ac50..328f3a3e9 100644 --- a/src/truetype/ttpload.c +++ b/src/truetype/ttpload.c @@ -222,13 +222,13 @@ } } - /* Check broken location data */ + /* Check broken location data. */ if ( pos1 > face->glyf_len ) { FT_TRACE1(( "tt_face_get_location:" - " too large offset=0x%08lx found for gid=0x%04lx,\n" + " too large offset (0x%08lx) found for glyph index %ld,\n" " " - " exceeding the end of glyf table (0x%08lx)\n", + " exceeding the end of `glyf' table (0x%08lx)\n", pos1, gindex, face->glyf_len )); *asize = 0; return 0; @@ -236,12 +236,26 @@ if ( pos2 > face->glyf_len ) { - FT_TRACE1(( "tt_face_get_location:" - " too large offset=0x%08lx found for gid=0x%04lx,\n" - " " - " truncate at the end of glyf table (0x%08lx)\n", - pos2, gindex + 1, face->glyf_len )); - pos2 = face->glyf_len; + /* We try to sanitize the last `loca' entry. */ + if ( gindex == face->num_locations - 1 ) + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset (0x%08lx) found for glyph index %ld,\n" + " " + " truncating at the end of `glyf' table (0x%08lx)\n", + pos2, gindex + 1, face->glyf_len )); + pos2 = face->glyf_len; + } + else + { + FT_TRACE1(( "tt_face_get_location:" + " too large offset (0x%08lx) found for glyph index %ld,\n" + " " + " exceeding the end of `glyf' table (0x%08lx)\n", + pos2, gindex + 1, face->glyf_len )); + *asize = 0; + return 0; + } } /* The `loca' table must be ordered; it refers to the length of */