Fix inconsistent handling of invalid zlib data

In libpng 1.6 zlib initialization was changed to use the window size in the zlib
stream, not a fixed value.  This causes some invalid images, ones where CINFO is
too large, to display 'correctly' if the rest of the data is valid.  This
provides a work-round for zlib versions where the error arises (ones that
support the API change to use the window size in the stream).

Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
John Bowler 2015-11-27 23:57:39 -08:00
parent 87049cbf84
commit 28a1cdfc2e
4 changed files with 46 additions and 4 deletions

View File

@ -662,7 +662,7 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,
* change the current behavior (see comments in inflate.c * change the current behavior (see comments in inflate.c
* for why this doesn't happen at present with zlib 1.2.5). * for why this doesn't happen at present with zlib 1.2.5).
*/ */
ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH); ret = PNG_INFLATE(png_ptr, Z_SYNC_FLUSH);
/* Check for any failure before proceeding. */ /* Check for any failure before proceeding. */
if (ret != Z_OK && ret != Z_STREAM_END) if (ret != Z_OK && ret != Z_STREAM_END)

View File

@ -1215,6 +1215,14 @@ PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr),
/* Initialize the row buffers, etc. */ /* Initialize the row buffers, etc. */
PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY);
#if PNG_ZLIB_VERNUM >= 0x1240
PNG_INTERNAL_FUNCTION(int,png_zlib_inflate,(png_structrp png_ptr, int flush),
PNG_EMPTY);
# define PNG_INFLATE(pp, flush) png_zlib_inflate(pp, flush)
#else /* Zlib < 1.2.4 */
# define PNG_INFLATE(pp, flush) inflate(&(pp)->zstream, flush)
#endif /* Zlib < 1.2.4 */
#ifdef PNG_READ_TRANSFORMS_SUPPORTED #ifdef PNG_READ_TRANSFORMS_SUPPORTED
/* Optional call to update the users info structure */ /* Optional call to update the users info structure */
PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr,

View File

@ -377,10 +377,16 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) ==
PNG_OPTION_ON) PNG_OPTION_ON)
{
window_bits = 15; window_bits = 15;
png_ptr->zstream_start = 0; /* fixed window size */
}
else else
{
window_bits = 0; window_bits = 0;
png_ptr->zstream_start = 1;
}
# else # else
# define window_bits 0 # define window_bits 0
# endif # endif
@ -429,6 +435,31 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
#endif #endif
} }
#if PNG_ZLIB_VERNUM >= 0x1240
/* Handle the start of the inflate stream if we called inflateInit2(strm,0);
* in this case some zlib versions skip validation of the CINFO field and, in
* certain circumstances, libpng may end up displaying an invalid image, in
* contrast to implementations that call zlib in the normal way (e.g. libpng
* 1.5).
*/
int /* PRIVATE */
png_zlib_inflate(png_structrp png_ptr, int flush)
{
if (png_ptr->zstream_start && png_ptr->zstream.avail_in > 0)
{
if ((*png_ptr->zstream.next_in >> 4) > 7)
{
png_ptr->zstream.msg = "invalid window size (libpng)";
return Z_DATA_ERROR;
}
png_ptr->zstream_start = 0;
}
return inflate(&png_ptr->zstream, flush);
}
#endif /* Zlib >= 1.2.4 */
#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED #ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED
/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to /* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to
* allow the caller to do multiple calls if required. If the 'finish' flag is * allow the caller to do multiple calls if required. If the 'finish' flag is
@ -522,7 +553,7 @@ png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish,
* the previous chunk of input data. Tell zlib if we have reached the * the previous chunk of input data. Tell zlib if we have reached the
* end of the output buffer. * end of the output buffer.
*/ */
ret = inflate(&png_ptr->zstream, avail_out > 0 ? Z_NO_FLUSH : ret = PNG_INFLATE(png_ptr, avail_out > 0 ? Z_NO_FLUSH :
(finish ? Z_FINISH : Z_SYNC_FLUSH)); (finish ? Z_FINISH : Z_SYNC_FLUSH));
} while (ret == Z_OK); } while (ret == Z_OK);
@ -771,7 +802,7 @@ png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size,
* the available output is produced; this allows reading of truncated * the available output is produced; this allows reading of truncated
* streams. * streams.
*/ */
ret = inflate(&png_ptr->zstream, ret = PNG_INFLATE(png_ptr,
*chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH));
} }
while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0)); while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0));
@ -4039,7 +4070,7 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
* *
* TODO: deal more elegantly with truncated IDAT lists. * TODO: deal more elegantly with truncated IDAT lists.
*/ */
ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); ret = PNG_INFLATE(png_ptr, Z_NO_FLUSH);
/* Take the unconsumed output back. */ /* Take the unconsumed output back. */
if (output != NULL) if (output != NULL)

View File

@ -263,6 +263,9 @@ struct png_struct_def
/* pixel depth used for the row buffers */ /* pixel depth used for the row buffers */
png_byte transformed_pixel_depth; png_byte transformed_pixel_depth;
/* pixel depth after read/write transforms */ /* pixel depth after read/write transforms */
#if PNG_ZLIB_VERNUM >= 0x1240
png_byte zstream_start; /* at start of an input zlib stream */
#endif /* Zlib >= 1.2.4 */
#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
png_uint_16 filler; /* filler bytes for pixel expansion */ png_uint_16 filler; /* filler bytes for pixel expansion */
#endif #endif