From 28a1cdfc2ed07d7c1af803dd98a50550699c847c Mon Sep 17 00:00:00 2001 From: John Bowler Date: Fri, 27 Nov 2015 23:57:39 -0800 Subject: [PATCH] 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 --- pngpread.c | 2 +- pngpriv.h | 8 ++++++++ pngrutil.c | 37 ++++++++++++++++++++++++++++++++++--- pngstruct.h | 3 +++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/pngpread.c b/pngpread.c index 076084a55..89ffc4018 100644 --- a/pngpread.c +++ b/pngpread.c @@ -662,7 +662,7 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, * change the current behavior (see comments in inflate.c * 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. */ if (ret != Z_OK && ret != Z_STREAM_END) diff --git a/pngpriv.h b/pngpriv.h index c466d4bfe..e53fb0e5a 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -1215,6 +1215,14 @@ PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr), /* Initialize the row buffers, etc. */ 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 /* Optional call to update the users info structure */ PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, diff --git a/pngrutil.c b/pngrutil.c index 2f6d6ad14..1d8653776 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -377,10 +377,16 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == PNG_OPTION_ON) + { window_bits = 15; + png_ptr->zstream_start = 0; /* fixed window size */ + } else + { window_bits = 0; + png_ptr->zstream_start = 1; + } # else # define window_bits 0 # endif @@ -429,6 +435,31 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) #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 /* 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 @@ -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 * 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)); } 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 * streams. */ - ret = inflate(&png_ptr->zstream, + ret = PNG_INFLATE(png_ptr, *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)); @@ -4039,7 +4070,7 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, * * 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. */ if (output != NULL) diff --git a/pngstruct.h b/pngstruct.h index c8c0e46e8..d0bcc7914 100644 --- a/pngstruct.h +++ b/pngstruct.h @@ -263,6 +263,9 @@ struct png_struct_def /* pixel depth used for the row buffers */ png_byte transformed_pixel_depth; /* 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) png_uint_16 filler; /* filler bytes for pixel expansion */ #endif