real fix for bug #19910. the .Z format is really badly designed :-(

This commit is contained in:
David Turner 2007-05-22 13:10:59 +00:00
parent 0d0365ec59
commit 3e2f953a10
3 changed files with 100 additions and 105 deletions

View File

@ -1,8 +1,8 @@
2007-05-22 David Turner <david@freetype.org>
* src/lzw/ftzopen.h, src/lzw/ftzopen.c: apply some "band-aid"
to avoid blowing up the heap in the case of malformed fonts.
related to bug #19910; *not* a real fix though...
* src/lzw/ftzopen.h, src/lzw/ftzopen.c: fix for bug #19910
(heap blowup with very large .Z font file). The .Z format is
*really* crappy :-(
2007-05-20 Ismail Dönmez <ismail@pardus.org.tr>

View File

@ -23,59 +23,86 @@
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_DEBUG_H
/* refill input buffer, return 0 on success, or -1 if eof */
static int
ft_lzwstate_refill( FT_LzwState state )
{
int result = -1;
FT_ULong count;
if (state->in_eof)
return -1;
if ( !state->in_eof )
{
FT_ULong count = FT_Stream_TryRead( state->source,
state->in_buff,
sizeof ( state->in_buff ) );
count = FT_Stream_TryRead( state->source,
state->buf_tab,
state->num_bits ); /* WHY ?? */
state->in_cursor = state->in_buff;
state->in_limit = state->in_buff + count;
state->in_eof = FT_BOOL( count < sizeof ( state->in_buff ) );
state->buf_size = (FT_UInt) count;
state->buf_total += count;
state->in_eof = FT_BOOL( count < state->num_bits );
state->buf_offset = 0;
state->buf_size = (state->buf_size << 3) - (state->num_bits-1);
if ( count > 0 )
result = 0;
}
return result;
if (count == 0) /* end of file */
return -1;
return 0;
}
/* return new code of 'num_bits', or -1 if eof */
static FT_Int32
ft_lzwstate_get_code( FT_LzwState state,
FT_UInt num_bits )
ft_lzwstate_get_code( FT_LzwState state )
{
FT_Int32 result = -1;
FT_UInt32 pad = state->pad;
FT_UInt pad_bits = state->pad_bits;
FT_UInt num_bits = state->num_bits;
FT_Int offset = state->buf_offset;
FT_Byte* p;
FT_Int result;
while ( num_bits > pad_bits )
if ( state->buf_clear ||
offset >= state->buf_size ||
state->free_ent >= state->free_bits )
{
if ( state->in_cursor >= state->in_limit &&
ft_lzwstate_refill( state ) < 0 )
goto Exit;
if ( state->free_ent >= state->free_bits )
{
state->num_bits = ++num_bits;
state->free_bits = state->num_bits < state->max_bits
? (FT_UInt)( ( 1UL << num_bits ) - 256 )
: state->max_free + 1;
}
pad |= (FT_UInt32)(*state->in_cursor++) << pad_bits;
pad_bits += 8;
if ( state->buf_clear )
{
state->num_bits = num_bits = LZW_INIT_BITS;
state->free_bits = (FT_UInt)( ( 1UL << num_bits ) - 256 );
state->buf_clear = 0;
}
if ( ft_lzwstate_refill( state ) < 0 )
return -1;
offset = 0;
}
result = (FT_Int32)( pad & LZW_MASK( num_bits ) );
state->pad_bits = pad_bits - num_bits;
state->pad = pad >> num_bits;
state->buf_offset = offset + num_bits;
p = &state->buf_tab[offset >> 3];
offset &= 7;
result = *p++ >> offset;
offset = 8-offset;
num_bits -= offset;
if (num_bits >= 8)
{
result |= *p++ << offset;
offset += 8;
num_bits -= 8;
}
if (num_bits > 0)
result |= (*p & LZW_MASK(num_bits)) << offset;
Exit:
return result;
}
/* grow the character stack */
static int
ft_lzwstate_stack_grow( FT_LzwState state )
@ -87,11 +114,6 @@
FT_UInt old_size = state->stack_size;
FT_UInt new_size = old_size;
/* limit stack size to detect invalid files */
/* the magic number comes from the origin NetBSD zopen implementation */
if (state->stack_size >= 69001 )
return -1;
new_size = new_size + ( new_size >> 1 ) + 4;
if ( state->stack == state->stack_0 )
@ -115,7 +137,6 @@
{
FT_UInt old_size = state->prefix_size;
FT_UInt new_size = old_size;
FT_UInt max_size = INT_MAX/(sizeof(FT_UShort)+sizeof(FT_Byte));
FT_Memory memory = state->memory;
FT_Error error;
@ -125,13 +146,6 @@
else
new_size += new_size >> 2; /* don't grow too fast */
if (new_size < old_size || new_size > max_size)
{
new_size = max_size;
if (new_size == old_size)
return -1;
}
/*
* Note that the `suffix' array is located in the same memory block
* pointed to by `prefix'.
@ -159,12 +173,11 @@
FT_LOCAL_DEF( void )
ft_lzwstate_reset( FT_LzwState state )
{
state->in_cursor = state->in_buff;
state->in_limit = state->in_buff;
state->in_eof = 0;
state->pad_bits = 0;
state->pad = 0;
state->buf_offset = 0;
state->buf_size = 0;
state->buf_clear = 0;
state->buf_total = 0;
state->stack_top = 0;
state->num_bits = LZW_INIT_BITS;
state->phase = FT_LZW_PHASE_START;
@ -226,11 +239,9 @@
{
FT_ULong result = 0;
FT_UInt num_bits = state->num_bits;
FT_UInt free_ent = state->free_ent;
FT_UInt last_char = state->last_char;
FT_UInt old_code = state->old_code;
FT_UInt in_code = state->in_code;
FT_UInt old_char = state->old_char;
FT_UInt old_code = state->old_code;
FT_UInt in_code = state->in_code;
if ( out_size == 0 )
@ -256,27 +267,27 @@
if ( state->max_bits > LZW_MAX_BITS )
goto Eof;
num_bits = LZW_INIT_BITS;
free_ent = ( state->block_mode ? LZW_FIRST : LZW_CLEAR ) - 256;
state->num_bits = LZW_INIT_BITS;
state->free_ent = ( state->block_mode ? LZW_FIRST : LZW_CLEAR ) - 256;
in_code = 0;
state->free_bits = num_bits < state->max_bits
? (FT_UInt)( ( 1UL << num_bits ) - 256 )
state->free_bits = state->num_bits < state->max_bits
? (FT_UInt)( ( 1UL << state->num_bits ) - 256 )
: state->max_free + 1;
c = ft_lzwstate_get_code( state, num_bits );
c = ft_lzwstate_get_code( state );
if ( c < 0 )
goto Eof;
old_code = last_char = (FT_UInt)c;
old_code = old_char = (FT_UInt)c;
if ( buffer )
buffer[result] = (FT_Byte)last_char;
state->phase = FT_LZW_PHASE_CODE;
buffer[result] = (FT_Byte)old_char;
if ( ++result >= out_size )
goto Exit;
state->phase = FT_LZW_PHASE_CODE;
}
/* fall-through */
@ -287,7 +298,7 @@
NextCode:
c = ft_lzwstate_get_code( state, num_bits );
c = ft_lzwstate_get_code( state );
if ( c < 0 )
goto Eof;
@ -295,14 +306,9 @@
if ( code == LZW_CLEAR && state->block_mode )
{
free_ent = ( LZW_FIRST - 1 ) - 256; /* why not LZW_FIRST-256 ? */
num_bits = LZW_INIT_BITS;
state->free_bits = num_bits < state->max_bits
? (FT_UInt)( ( 1UL << num_bits ) - 256 )
: state->max_free + 1;
c = ft_lzwstate_get_code( state, num_bits );
state->free_ent = ( LZW_FIRST - 1 ) - 256; /* why not LZW_FIRST-256 ? */
state->buf_clear = 1;
c = ft_lzwstate_get_code( state );
if ( c < 0 )
goto Eof;
@ -314,9 +320,9 @@
if ( code >= 256U )
{
/* special case for KwKwKwK */
if ( code - 256U >= free_ent )
if ( code - 256U >= state->free_ent )
{
FTLZW_STACK_PUSH( last_char );
FTLZW_STACK_PUSH( old_char );
code = old_code;
}
@ -327,8 +333,8 @@
}
}
last_char = code;
FTLZW_STACK_PUSH( last_char );
old_char = code;
FTLZW_STACK_PUSH( old_char );
state->phase = FT_LZW_PHASE_STACK;
}
@ -348,25 +354,18 @@
}
/* now create new entry */
if ( free_ent < state->max_free )
if ( state->free_ent < state->max_free )
{
if ( free_ent >= state->prefix_size &&
ft_lzwstate_prefix_grow( state ) < 0 )
if ( state->free_ent >= state->prefix_size &&
ft_lzwstate_prefix_grow( state ) < 0 )
goto Eof;
FT_ASSERT( free_ent < state->prefix_size );
FT_ASSERT( state->free_ent < state->prefix_size );
state->prefix[free_ent] = (FT_UShort)old_code;
state->suffix[free_ent] = (FT_Byte) last_char;
state->prefix[state->free_ent] = (FT_UShort)old_code;
state->suffix[state->free_ent] = (FT_Byte) old_char;
if ( ++free_ent == state->free_bits )
{
num_bits++;
state->free_bits = num_bits < state->max_bits
? (FT_UInt)( ( 1UL << num_bits ) - 256 )
: state->max_free + 1;
}
state->free_ent += 1;
}
old_code = in_code;
@ -380,11 +379,9 @@
}
Exit:
state->num_bits = num_bits;
state->free_ent = free_ent;
state->old_code = old_code;
state->last_char = last_char;
state->in_code = in_code;
state->old_code = old_code;
state->old_char = old_char;
state->in_code = in_code;
return result;

View File

@ -112,13 +112,13 @@
typedef struct _FT_LzwStateRec
{
FT_LzwPhase phase;
FT_Int in_eof;
FT_Byte* in_cursor; /* current buffer pos */
FT_Byte* in_limit; /* current buffer limit */
FT_UInt32 pad; /* a pad value where incoming bits were read */
FT_Int pad_bits; /* number of meaningful bits in pad value */
FT_Byte buf_tab[16];
FT_Int buf_offset;
FT_Int buf_size;
FT_Bool buf_clear;
FT_Int buf_total;
FT_UInt max_bits; /* max code bits, from file header */
FT_Int block_mode; /* block mode flag, from file header */
@ -128,7 +128,7 @@
FT_UInt free_ent; /* index of next free entry */
FT_UInt free_bits; /* if reached by free_ent, increment num_bits */
FT_UInt old_code;
FT_UInt last_char;
FT_UInt old_char;
FT_UInt in_code;
FT_UShort* prefix; /* always dynamically allocated / reallocated */
@ -138,8 +138,6 @@
FT_Byte* stack; /* character stack */
FT_UInt stack_top;
FT_UInt stack_size;
FT_Byte in_buff[FT_LZW_IN_BUFF_SIZE]; /* small read-buffer */
FT_Byte stack_0[FT_LZW_DEFAULT_STACK_SIZE]; /* minimize heap alloc */
FT_Stream source; /* source stream */