From 6ee89519561aa33c63abcb24ae63920742f81316 Mon Sep 17 00:00:00 2001 From: Ben Wagner Date: Wed, 12 Jan 2022 15:12:53 -0500 Subject: [PATCH] [bzip2] Reset bzip stream on any error. According to the bzip documentation it is undefined what will happen if `BZ2_bzDecompress` is called on a `bz_stream` it has previously returned an error against. If `BZ2_bzDecompress` returns anything other than `BZ_OK` the only valid next action is `BZ2_bzDecompressEnd`. Reported as https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=43564 * src/bzip2/ftbzip2.c (FT_BZip2FileRec_): Add `reset` to track the need to reset the stream. (ft_bzip2_file_init): Initialize `reset` to 0. (ft_bzip2_file_reset): Set `reset` to 0 after resetting. (ft_bzip2_file_fill_output): Set `reset` to 1 when `BZ2_bzDecompress` returns anything other than `BZ_OK`. --- src/bzip2/ftbzip2.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/bzip2/ftbzip2.c b/src/bzip2/ftbzip2.c index 1d08f5e18..6f34a8bb7 100644 --- a/src/bzip2/ftbzip2.c +++ b/src/bzip2/ftbzip2.c @@ -102,10 +102,11 @@ FT_Byte input[FT_BZIP2_BUFFER_SIZE]; /* input read buffer */ - FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */ - FT_ULong pos; /* position in output */ + FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ FT_Byte* cursor; FT_Byte* limit; + FT_Bool reset; /* reset before next read */ } FT_BZip2FileRec, *FT_BZip2File; @@ -153,6 +154,7 @@ zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE; zip->cursor = zip->limit; zip->pos = 0; + zip->reset = 0; /* check .bz2 header */ { @@ -228,6 +230,7 @@ zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE; zip->cursor = zip->limit; zip->pos = 0; + zip->reset = 0; BZ2_bzDecompressInit( bzstream, 0, 0 ); } @@ -302,18 +305,23 @@ err = BZ2_bzDecompress( bzstream ); - if ( err == BZ_STREAM_END ) + if ( err != BZ_OK ) { - zip->limit = (FT_Byte*)bzstream->next_out; - if ( zip->limit == zip->cursor ) - error = FT_THROW( Invalid_Stream_Operation ); - break; - } - else if ( err != BZ_OK ) - { - zip->limit = zip->cursor; - error = FT_THROW( Invalid_Stream_Operation ); - break; + zip->reset = 1; + + if ( err == BZ_STREAM_END ) + { + zip->limit = (FT_Byte*)bzstream->next_out; + if ( zip->limit == zip->cursor ) + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + else + { + zip->limit = zip->cursor; + error = FT_THROW( Invalid_Stream_Operation ); + break; + } } } @@ -363,9 +371,9 @@ FT_Error error; - /* Reset inflate stream if we're seeking backwards. */ - /* Yes, that is not too efficient, but it saves memory :-) */ - if ( pos < zip->pos ) + /* Reset inflate stream if seeking backwards or bzip reported an error. */ + /* Yes, that is not too efficient, but it saves memory :-) */ + if ( pos < zip->pos || zip->reset ) { error = ft_bzip2_file_reset( zip ); if ( error )