All pastes #1903631 Raw Edit

j0rn

public text v1 · immutable
#1903631 ·published 2010-07-19 13:29 UTC
rendered paste body
Description: fix arbitrary code execution from additional data row via malformed PNG imageOrigin: Backport, from upstream 1.2.44diff -Nur libpng-1.2.42/pngpread.c libpng-1.2.42.new/pngpread.c--- libpng-1.2.42/pngpread.c	2010-01-03 00:04:19.000000000 -0500+++ libpng-1.2.42.new/pngpread.c	2010-07-05 11:26:26.000000000 -0400@@ -776,8 +776,7 @@        png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); -      if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))-         png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);+      png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);        png_ptr->idat_size -= save_size;       png_ptr->buffer_size -= save_size;@@ -800,8 +799,8 @@          save_size = png_ptr->current_buffer_size;        png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);-      if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))-        png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);++      png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);        png_ptr->idat_size -= save_size;       png_ptr->buffer_size -= save_size;@@ -826,60 +825,101 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer,    png_size_t buffer_length) {-   int ret;--   if ((png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) && buffer_length)-      png_error(png_ptr, "Extra compression data");-+   /* The caller checks for a non-zero buffer length. */+   if (!(buffer_length > 0) || buffer == NULL)+      png_error(png_ptr, "No IDAT data (internal error)");++   /* This routine must process all the data it has been given+    * before returning, calling the row callback as required to+    * handle the uncompressed results.+    */    png_ptr->zstream.next_in = buffer;    png_ptr->zstream.avail_in = (uInt)buffer_length;-   for (;;)++   /* Keep going until the decompressed data is all processed+    * or the stream marked as finished.+    */+   while (png_ptr->zstream.avail_in > 0 &&+	  !(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))    {-      ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);-      if (ret != Z_OK)+      int ret;++      /* We have data for zlib, but we must check that zlib+       * has somewhere to put the results.  It doesn't matter+       * if we don't expect any results -- it may be the input+       * data is just the LZ end code.+       */+      if (!(png_ptr->zstream.avail_out > 0))       {-         if (ret == Z_STREAM_END)-         {-            if (png_ptr->zstream.avail_in)-               png_error(png_ptr, "Extra compressed data");+         png_ptr->zstream.avail_out =+             (uInt) PNG_ROWBYTES(png_ptr->pixel_depth,+             png_ptr->iwidth) + 1;+         png_ptr->zstream.next_out = png_ptr->row_buf;+      } -            if (!(png_ptr->zstream.avail_out))-            {-               png_push_process_row(png_ptr);-            }+      /* Using Z_SYNC_FLUSH here means that an unterminated+       * LZ stream can still be handled (a stream with a missing+       * end code), otherwise (Z_NO_FLUSH) a future zlib+       * implementation might defer output and, therefore,+       * 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); -            png_ptr->mode |= PNG_AFTER_IDAT;-            png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;-            break;-         }-         else if (ret == Z_BUF_ERROR)-            break;+      /* Check for any failure before proceeding. */+      if (ret != Z_OK && ret != Z_STREAM_END)+      {+	 /* Terminate the decompression. */+	 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;++         /* This may be a truncated stream (missing or+	  * damaged end code).  Treat that as a warning.+	  */+         if (png_ptr->row_number >= png_ptr->num_rows ||+	     png_ptr->pass > 6)+	    png_warning(png_ptr, "Truncated compressed data in IDAT");+	 else+	    png_error(png_ptr, "Decompression error in IDAT"); -         else-            png_error(png_ptr, "Decompression Error");+	 /* Skip the check on unprocessed input */+         return;       }-      if (!(png_ptr->zstream.avail_out))++      /* Did inflate output any data? */+      if (png_ptr->zstream.next_out != png_ptr->row_buf)       {-         if ((-#ifdef PNG_READ_INTERLACING_SUPPORTED-             png_ptr->interlaced && png_ptr->pass > 6) ||-             (!png_ptr->interlaced &&-#endif-             png_ptr->row_number == png_ptr->num_rows))+	 /* Is this unexpected data after the last row?+	  * If it is, artificially terminate the LZ output+	  * here.+	  */+         if (png_ptr->row_number >= png_ptr->num_rows ||+	     png_ptr->pass > 6)          {-           if (png_ptr->zstream.avail_in)-             png_warning(png_ptr, "Too much data in IDAT chunks");-           png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;-           break;-         }-         png_push_process_row(png_ptr);-         png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;-         png_ptr->zstream.next_out = png_ptr->row_buf;+	    /* Extra data. */+	    png_warning(png_ptr, "Extra compressed data in IDAT");+            png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;+	    /* Do no more processing; skip the unprocessed+	     * input check below.+	     */+            return;+	 }++	 /* Do we have a complete row? */+	 if (png_ptr->zstream.avail_out == 0)+	    png_push_process_row(png_ptr);       } -      else-         break;+      /* And check for the end of the stream. */+      if (ret == Z_STREAM_END)+	 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;    }++   /* All the data should have been processed, if anything+    * is left at this point we have bytes of IDAT data+    * after the zlib end code.+    */+   if (png_ptr->zstream.avail_in > 0)+      png_warning(png_ptr, "Extra compression data"); }  void /* PRIVATE */