ref: e6593389cf557740d6b15d6065bb96a4a81cabeb
parent: 649ca5562d321f1008087eb0f2be584a495fabd9
author: Werner Lemberg <[email protected]>
date: Wed Oct 21 04:04:29 EDT 2015
[sfnt] Avoid unnecessarily large allocation for WOFFs (#46257). * src/sfnt/sfobjs.c (woff_open_font): Use WOFF's `totalSfntSize' only after thorough checks. Add tracing messages.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2015-10-21 Werner Lemberg <[email protected]>
+ [sfnt] Avoid unnecessarily large allocation for WOFFs (#46257).
+
+ * src/sfnt/sfobjs.c (woff_open_font): Use WOFF's `totalSfntSize'
+ only after thorough checks.
+ Add tracing messages.
+
+2015-10-21 Werner Lemberg <[email protected]>
+
[type42] Better check invalid `sfnts' array data (#46255).
* src/type42/t42parse.c (t42_parse_sfnts): Table lengths must be
--- a/src/autofit/afranges.c
+++ b/src/autofit/afranges.c
@@ -179,6 +179,34 @@
};
+ const AF_Script_UniRangeRec af_khmr_uniranges[] =
+ {
+ AF_UNIRANGE_REC( 0x1780UL, 0x17FFUL ), /* Khmer */
+ AF_UNIRANGE_REC( 0UL, 0UL )
+ };
+
+ const AF_Script_UniRangeRec af_khmr_nonbase_uniranges[] =
+ {
+ AF_UNIRANGE_REC( 0x17B7UL, 0x17BDUL ),
+ AF_UNIRANGE_REC( 0x17C6UL, 0x17C6UL ),
+ AF_UNIRANGE_REC( 0x17C9UL, 0x17D3UL ),
+ AF_UNIRANGE_REC( 0x17DDUL, 0x17DDUL ),
+ AF_UNIRANGE_REC( 0UL, 0UL )
+ };
+
+
+ const AF_Script_UniRangeRec af_khms_uniranges[] =
+ {
+ AF_UNIRANGE_REC( 0x19E0UL, 0x19FFUL ), /* Khmer Symbols */
+ AF_UNIRANGE_REC( 0UL, 0UL )
+ };
+
+ const AF_Script_UniRangeRec af_khms_nonbase_uniranges[] =
+ {
+ AF_UNIRANGE_REC( 0UL, 0UL )
+ };
+
+
const AF_Script_UniRangeRec af_lao_uniranges[] =
{
AF_UNIRANGE_REC( 0x0E80UL, 0x0EFFUL ), /* Lao */
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -451,10 +451,14 @@
woff.metaOrigLength != 0 ) ) ||
( woff.metaLength != 0 && woff.metaOrigLength == 0 ) ||
( woff.privOffset == 0 && woff.privLength != 0 ) )
+ {
+ FT_ERROR(( "woff_font_open: invalid WOFF header\n" ));
return FT_THROW( Invalid_Table );
+ }
- if ( FT_ALLOC( sfnt, woff.totalSfntSize ) ||
- FT_NEW( sfnt_stream ) )
+ /* Don't trust `totalSfntSize' before thorough checks. */
+ if ( FT_ALLOC( sfnt, 12 + woff.num_tables * 16UL ) ||
+ FT_NEW( sfnt_stream ) )
goto Exit;
sfnt_header = sfnt;
@@ -521,6 +525,8 @@
if ( table->Tag <= old_tag )
{
FT_FRAME_EXIT();
+
+ FT_ERROR(( "woff_font_open: table tags are not sorted\n" ));
error = FT_THROW( Invalid_Table );
goto Exit;
}
@@ -555,6 +561,7 @@
sfnt_offset > woff.totalSfntSize - table->OrigLength ||
table->CompLength > table->OrigLength )
{
+ FT_ERROR(( "woff_font_open: invalid table offsets\n" ));
error = FT_THROW( Invalid_Table );
goto Exit;
}
@@ -580,6 +587,8 @@
if ( woff.metaOffset != woff_offset ||
woff.metaOffset + woff.metaLength > woff.length )
{
+ FT_ERROR(( "woff_font_open:"
+ " invalid `metadata' offset or length\n" ));
error = FT_THROW( Invalid_Table );
goto Exit;
}
@@ -596,6 +605,7 @@
if ( woff.privOffset != woff_offset ||
woff.privOffset + woff.privLength > woff.length )
{
+ FT_ERROR(( "woff_font_open: invalid `private' offset or length\n" ));
error = FT_THROW( Invalid_Table );
goto Exit;
}
@@ -607,10 +617,19 @@
if ( sfnt_offset != woff.totalSfntSize ||
woff_offset != woff.length )
{
+ FT_ERROR(( "woff_font_open: invalid `sfnt' table structure\n" ));
error = FT_THROW( Invalid_Table );
goto Exit;
}
+ /* Now use `totalSfntSize'. */
+ if ( FT_REALLOC( sfnt,
+ 12 + woff.num_tables * 16UL,
+ woff.totalSfntSize ) )
+ goto Exit;
+
+ sfnt_header = sfnt + 12;
+
/* Write the tables. */
for ( nn = 0; nn < woff.num_tables; nn++ )
@@ -651,6 +670,7 @@
goto Exit;
if ( output_len != table->OrigLength )
{
+ FT_ERROR(( "woff_font_open: compressed table length mismatch\n" ));
error = FT_THROW( Invalid_Table );
goto Exit;
}
--- a/src/tools/ftfuzzer/ftfuzzer.cc
+++ b/src/tools/ftfuzzer/ftfuzzer.cc
@@ -3,6 +3,9 @@
# error "a C++11 compiler is needed"
#endif
+#include <archive.h>
+#include <archive_entry.h>
+
#include <assert.h>
#include <stdint.h>
@@ -45,7 +48,60 @@
FT_Global global_ft;
+ static int
+ archive_read_entry_data( struct archive *ar, vector<FT_Byte> *vw )
+ {
+ int r;
+ const FT_Byte *buff;
+ size_t size;
+ int64_t offset;
+ for (;;) {
+ r = archive_read_data_block( ar, reinterpret_cast<const void**>(&buff), &size, &offset );
+ if (r == ARCHIVE_EOF)
+ return (ARCHIVE_OK);
+ if (r != ARCHIVE_OK)
+ return (r);
+ vw->insert(vw->end(), buff, buff + size);
+ }
+ }
+
+ static vector<vector<FT_Byte>>
+ parse_data( const uint8_t* data,
+ size_t size )
+ {
+ struct archive_entry *entry;
+ int r;
+ vector<vector<FT_Byte>> files;
+
+ unique_ptr<struct archive, decltype ( archive_read_free )*> a( archive_read_new(), archive_read_free );
+ archive_read_support_format_tar(a.get());
+
+ // The need for the const_cast was removed with libarchive be4d4ddcfca77f6e43753156eaa919f4d25ed903
+ if (!(r = archive_read_open_memory( a.get(), const_cast<void*>(static_cast<const void*>(data)), size )))
+ {
+ unique_ptr<struct archive, decltype ( archive_read_close )*> a_open( a.get(), archive_read_close );
+ for (;;) {
+ r = archive_read_next_header( a_open.get(), &entry );
+ if (r == ARCHIVE_EOF)
+ break;
+ if (r != ARCHIVE_OK)
+ break;
+ vector<FT_Byte> entry_data;
+ r = archive_read_entry_data( a.get(), &entry_data );
+ if (r != ARCHIVE_OK)
+ break;
+ files.push_back( move( entry_data ) );
+ }
+ }
+
+ if (files.size() == 0)
+ files.emplace_back(data, data + size);
+
+ return files;
+ }
+
+
static void
setIntermediateAxis( FT_Face face )
{
@@ -85,6 +141,8 @@
long size = (long)size_;
+ const vector<vector<FT_Byte>>& files = parse_data( data, size );
+
FT_Face face;
FT_Int32 load_flags = FT_LOAD_DEFAULT;
#if 0
@@ -99,7 +157,7 @@
// more than a single font.
// get number of faces
- if ( FT_New_Memory_Face( library, data, size, -1, &face ) )
+ if ( FT_New_Memory_Face( library, files[0].data(), files[0].size(), -1, &face ) )
return 0;
long num_faces = face->num_faces;
FT_Done_Face( face );
@@ -111,8 +169,8 @@
{
// get number of instances
if ( FT_New_Memory_Face( library,
- data,
- size,
+ files[0].data(),
+ files[0].size(),
-( face_index + 1 ),
&face ) )
continue;
@@ -125,11 +183,22 @@
instance_index++ )
{
if ( FT_New_Memory_Face( library,
- data,
- size,
+ files[0].data(),
+ files[0].size(),
( instance_index << 16 ) + face_index,
&face ) )
continue;
+
+ for ( long files_index = 1;
+ files_index < files.size();
+ files_index++)
+ {
+ FT_Open_Args open_args = {};
+ open_args.flags = FT_OPEN_MEMORY;
+ open_args.memory_base = files[files_index].data();
+ open_args.memory_size = files[files_index].size();
+ FT_Attach_Stream( face, &open_args );
+ }
// loop over all bitmap stroke sizes
// and an arbitrary size for outlines