[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`.
This commit is contained in:
Ben Wagner 2022-01-12 15:12:53 -05:00 committed by Werner Lemberg
parent b647dbdeb8
commit 6ee8951956
1 changed files with 24 additions and 16 deletions

View File

@ -106,6 +106,7 @@
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,6 +305,10 @@
err = BZ2_bzDecompress( bzstream );
if ( err != BZ_OK )
{
zip->reset = 1;
if ( err == BZ_STREAM_END )
{
zip->limit = (FT_Byte*)bzstream->next_out;
@ -309,13 +316,14 @@
error = FT_THROW( Invalid_Stream_Operation );
break;
}
else if ( err != BZ_OK )
else
{
zip->limit = zip->cursor;
error = FT_THROW( Invalid_Stream_Operation );
break;
}
}
}
return error;
}
@ -363,9 +371,9 @@
FT_Error error;
/* Reset inflate stream if we're seeking backwards. */
/* 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 )
if ( pos < zip->pos || zip->reset )
{
error = ft_bzip2_file_reset( zip );
if ( error )