diff --git a/pngrutil.c b/pngrutil.c index 5dd5361671..4c6c482e32 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -1315,6 +1315,7 @@ png_handle_iCCP(png_struct *png_ptr, png_info *info_ptr, png_uint_32 length) { const char *errmsg = NULL; /* error message output, or no error */ int finished = 0; /* crc checked */ + int ret; /* zlib status of the final inflate call */ png_debug(1, "in png_handle_iCCP"); @@ -1421,7 +1422,7 @@ png_handle_iCCP(png_struct *png_ptr, png_info *info_ptr, png_uint_32 length) size = profile_length - (sizeof profile_header) - 12 * tag_count; - (void)png_inflate_read(png_ptr, local_buffer, + ret = png_inflate_read(png_ptr, local_buffer, (sizeof local_buffer), &length, profile + (sizeof profile_header) + 12 * tag_count, &size, 1/*finish*/); @@ -1431,7 +1432,7 @@ png_handle_iCCP(png_struct *png_ptr, png_info *info_ptr, png_uint_32 length) errmsg = "extra compressed data"; /* But otherwise allow extra data: */ - else if (size == 0) + else if (ret == Z_STREAM_END && size == 0) { if (length > 0) { @@ -1481,6 +1482,16 @@ png_handle_iCCP(png_struct *png_ptr, png_info *info_ptr, png_uint_32 length) return handled_ok; } } + else if (size == 0) + { + /* The LZ stream produced more output + * than the declared profile length; + * accepting it would silently truncate + * the profile. + */ + errmsg = "decompressed data exceeds " + "declared profile length"; + } if (errmsg == NULL) errmsg = png_ptr->zstream.msg; } @@ -3232,7 +3243,7 @@ read_chunks[PNG_INDEX_unknown] = /* Allocates 'length+1'; checked in the handler */ # define CDtIME 7U, 7U, 0, hIHDR, 0 # define CDacTL 8U, 8U, hIDAT, hIHDR, 0 -# define CDfcTL 25U, 26U, 0, hIHDR, 1 +# define CDfcTL 26U, 26U, 0, hIHDR, 1 # define CDfdAT Limit, 4U, hIDAT, hIHDR, 1 /* Supported chunks from PNG extensions 1.5.0, NYI so limit */ # define CDoFFs 9U, 9U, hIDAT, hIHDR, 0 diff --git a/pngset.c b/pngset.c index 10eea62e54..1285f921e4 100644 --- a/pngset.c +++ b/pngset.c @@ -1186,6 +1186,19 @@ png_set_tRNS(png_struct *png_ptr, png_info *info_ptr, return; + if (num_trans < 0 || num_trans > PNG_MAX_PALETTE_LENGTH) + { + /* num_trans outside the valid range would be truncated by the + * png_uint_16 assignment below, and the PNG_INFO_tRNS flag would be + * set while trans_alpha is NULL, which leads to a NULL dereference + * in png_write_info (PNG_INVERT_ALPHA) and to an inconsistent state + * visible through png_get_tRNS. + */ + png_warning(png_ptr, "Invalid num_trans in png_set_tRNS"); + + return; + } + if (trans_alpha != NULL) { /* Snapshot the caller's trans_alpha before freeing, in case it diff --git a/pngwutil.c b/pngwutil.c index dae8850feb..9264e75f41 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -1545,6 +1545,16 @@ png_write_eXIf(png_struct *png_ptr, png_byte *exif, int num_exif) png_debug(1, "in png_write_eXIf"); + if (num_exif < 0) + { + /* num_exif is signed in the API; a negative value would wrap into a + * huge chunk length field and corrupt the output stream. + */ + png_warning(png_ptr, "Invalid eXIf chunk length"); + + return; + } + png_write_chunk_header(png_ptr, png_eXIf, (png_uint_32)(num_exif)); for (i = 0; i < num_exif; i++)