[pcf] Fix Savannah bug #43774.

Work around `features' of X11's `pcfWriteFont' and `pcfReadFont'
functions.  Since the PCF format doesn't have an official
specification, we have to exactly follow these functions' behaviour.

The problem was unveiled with a patch from 2014-11-06, fixing issue #43547.

* src/pcf/pcfread.c (pcf_read_TOC): Don't check table size for last
element.  Instead, assign real size.
This commit is contained in:
Werner Lemberg 2014-12-08 16:01:50 +01:00
parent 553c9672b3
commit 74af85c4b6
2 changed files with 57 additions and 11 deletions

View File

@ -1,3 +1,17 @@
2014-12-08 Werner Lemberg <wl@gnu.org>
[pcf] Fix Savannah bug #43774.
Work around `features' of X11's `pcfWriteFont' and `pcfReadFont'
functions. Since the PCF format doesn't have an official
specification, we have to exactly follow these functions' behaviour.
The problem was unveiled with a patch from 2014-11-06, fixing issue
#43547.
* src/pcf/pcfread.c (pcf_read_TOC): Don't check table size for last
element. Instead, assign real size.
2014-12-07 Werner Lemberg <wl@gnu.org> 2014-12-07 Werner Lemberg <wl@gnu.org>
Work around a bug in Borland's C++ compiler. Work around a bug in Borland's C++ compiler.

View File

@ -2,7 +2,7 @@
FreeType font driver for pcf fonts FreeType font driver for pcf fonts
Copyright 2000-2010, 2012, 2013 by Copyright 2000-2010, 2012-2014 by
Francesco Zappa Nardelli Francesco Zappa Nardelli
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@ -78,7 +78,7 @@ THE SOFTWARE.
FT_FRAME_START( 16 ), FT_FRAME_START( 16 ),
FT_FRAME_ULONG_LE( type ), FT_FRAME_ULONG_LE( type ),
FT_FRAME_ULONG_LE( format ), FT_FRAME_ULONG_LE( format ),
FT_FRAME_ULONG_LE( size ), FT_FRAME_ULONG_LE( size ), /* rounded up to a multiple of 4 */
FT_FRAME_ULONG_LE( offset ), FT_FRAME_ULONG_LE( offset ),
FT_FRAME_END FT_FRAME_END
}; };
@ -95,9 +95,11 @@ THE SOFTWARE.
FT_Memory memory = FT_FACE( face )->memory; FT_Memory memory = FT_FACE( face )->memory;
FT_UInt n; FT_UInt n;
FT_ULong size;
if ( FT_STREAM_SEEK ( 0 ) ||
FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) ) if ( FT_STREAM_SEEK( 0 ) ||
FT_STREAM_READ_FIELDS( pcf_toc_header, toc ) )
return FT_THROW( Cannot_Open_Resource ); return FT_THROW( Cannot_Open_Resource );
if ( toc->version != PCF_FILE_VERSION || if ( toc->version != PCF_FILE_VERSION ||
@ -154,14 +156,35 @@ THE SOFTWARE.
break; break;
} }
/* we now check whether the `size' and `offset' values are reasonable: */ /*
/* `offset' + `size' must not exceed the stream size */ * We now check whether the `size' and `offset' values are reasonable:
* `offset' + `size' must not exceed the stream size.
*
* Note, however, that X11's `pcfWriteFont' routine (used by the
* `bdftopcf' program to create PDF font files) has two special
* features.
*
* - It always assigns the accelerator table a size of 100 bytes in the
* TOC, regardless of its real size, which can vary between 34 and 72
* bytes.
*
* - Due to the way the routine is designed, it ships out the last font
* table with its real size, ignoring the TOC's size value. Since
* the TOC size values are always rounded up to a multiple of 4, the
* difference can be up to three bytes for all tables except the
* accelerator table, for which the difference can be as large as 66
* bytes.
*
*/
tables = face->toc.tables; tables = face->toc.tables;
for ( n = 0; n < toc->count; n++ ) size = stream->size;
for ( n = 0; n < toc->count - 1; n++ )
{ {
/* we need two checks to avoid overflow */ /* we need two checks to avoid overflow */
if ( ( tables->size > stream->size ) || if ( ( tables->size > size ) ||
( tables->offset > stream->size - tables->size ) ) ( tables->offset > size - tables->size ) )
{ {
error = FT_THROW( Invalid_Table ); error = FT_THROW( Invalid_Table );
goto Exit; goto Exit;
@ -169,6 +192,15 @@ THE SOFTWARE.
tables++; tables++;
} }
/* no check of `tables->size' for last table element ... */
if ( ( tables->offset > size ) )
{
error = FT_THROW( Invalid_Table );
goto Exit;
}
/* ... instead, we adjust `tables->size' to the real value */
tables->size = size - tables->offset;
#ifdef FT_DEBUG_LEVEL_TRACE #ifdef FT_DEBUG_LEVEL_TRACE
{ {
@ -733,8 +765,8 @@ THE SOFTWARE.
FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps )); FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps ));
/* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */ /* XXX: PCF_Face->nmetrics is signed FT_Long, see pcf.h */
if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics ) if ( face->nmetrics < 0 || nbitmaps != (FT_ULong)face->nmetrics )
return FT_THROW( Invalid_File_Format ); return FT_THROW( Invalid_File_Format );
if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) if ( FT_NEW_ARRAY( offsets, nbitmaps ) )