Commit message: * tools/tiffcrop.c: fix readContigStripsIntoBuffer() in -i (ignore) mode so
that the output buffer is correctly incremented to avoid write outside bounds.
Reported by Agostino Sarubbo.
Fixes http://bugzilla.maptools.org/show_bug.cgi?id=2620
CVE: CVE-2016-10092
CWE: CWE-119
Vulnerability description: Heap-based buffer overflow in the readContigStripsIntoBuffer function in tif_unix.c in LibTIFF 4.0.7, 3.9.3, 3.9.4, 3.9.5, 3.9.6, 3.9.7, 4.0.0alpha4, 4.0.0alpha5, 4.0.0alpha6, 4.0.0beta7, 4.0.0, 4.0.1, 4.0.2, 4.0.3, 4.0.4, 4.0.4beta, 4.0.5 and 4.0.6 allows remote attackers to have unspecified impact via a crafted image.

Project: libtiff

static int readContigTilesIntoBuffer (TIFF* in, uint8* buf, 
                                      uint32 imagelength, 
                                      uint32 imagewidth, 
                                      uint32 tw, uint32 tl,
                                      tsample_t spp, uint16 bps)
  {
  int status = 1;
  tsample_t sample = 0;
  tsample_t count = spp; 
  uint32 row, col, trow;
  uint32 nrow, ncol;
  uint32 dst_rowsize, shift_width;
  uint32 bytes_per_sample, bytes_per_pixel;
  uint32 trailing_bits, prev_trailing_bits;
  uint32 tile_rowsize  = TIFFTileRowSize(in);
  uint32 src_offset, dst_offset;
  uint32 row_offset, col_offset;
  uint8 *bufp = (uint8*) buf;
  unsigned char *src = NULL;
  unsigned char *dst = NULL;
  tsize_t tbytes = 0, tile_buffsize = 0;
  tsize_t tilesize = TIFFTileSize(in);
  unsigned char *tilebuf = NULL;

  bytes_per_sample = (bps + 7) / 8; 
  bytes_per_pixel  = ((bps * spp) + 7) / 8;

  if ((bps % 8) == 0)
    shift_width = 0;
  else
    {
    if (bytes_per_pixel < (bytes_per_sample + 1))
      shift_width = bytes_per_pixel;
    else
      shift_width = bytes_per_sample + 1;
    }

  tile_buffsize = tilesize;
  if (tilesize == 0 || tile_rowsize == 0)
  {
     TIFFError("readContigTilesIntoBuffer", "Tile size or tile rowsize is zero");
     exit(-1);
  }

  if (tilesize < (tsize_t)(tl * tile_rowsize))
    {
#ifdef DEBUG2
    TIFFError("readContigTilesIntoBuffer",
	      "Tilesize %lu is too small, using alternate calculation %u",
              tilesize, tl * tile_rowsize);
#endif
    tile_buffsize = tl * tile_rowsize;
    if (tl != (tile_buffsize / tile_rowsize))
    {
    	TIFFError("readContigTilesIntoBuffer", "Integer overflow when calculating buffer size.");
        exit(-1);
    }
    }

  /* Add 3 padding bytes for extractContigSamplesShifted32bits */
  if( (size_t) tile_buffsize > 0xFFFFFFFFU - 3U )
  {
      TIFFError("readContigTilesIntoBuffer", "Integer overflow when calculating buffer size.");
      exit(-1);
  }
  tilebuf = _TIFFmalloc(tile_buffsize + 3);
  if (tilebuf == 0)
    return 0;
  tilebuf[tile_buffsize] = 0;
  tilebuf[tile_buffsize+1] = 0;
  tilebuf[tile_buffsize+2] = 0;

  dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;  
  for (row = 0; row < imagelength; row += tl)
    {
    nrow = (row + tl > imagelength) ? imagelength - row : tl;
    for (col = 0; col < imagewidth; col += tw)
      {
      tbytes = TIFFReadTile(in, tilebuf, col, row, 0, 0);
      if (tbytes < tilesize  && !ignore)
        {
	TIFFError(TIFFFileName(in),
		  "Error, can't read tile at row %lu col %lu, Read %lu bytes of %lu",
		  (unsigned long) col, (unsigned long) row, (unsigned long)tbytes,
                  (unsigned long)tilesize);
		  status = 0;
                  _TIFFfree(tilebuf);
		  return status;
	}
      
      row_offset = row * dst_rowsize;
      col_offset = ((col * bps * spp) + 7)/ 8;
      bufp = buf + row_offset + col_offset;

      if (col + tw > imagewidth)
	ncol = imagewidth - col;
      else
        ncol = tw;

      /* Each tile scanline will start on a byte boundary but it
       * has to be merged into the scanline for the entire
       * image buffer and the previous segment may not have
       * ended on a byte boundary
       */
      /* Optimization for common bit depths, all samples */
      if (((bps % 8) == 0) && (count == spp))
        {
	for (trow = 0; trow < nrow; trow++)
          {
	  src_offset = trow * tile_rowsize;
	  _TIFFmemcpy (bufp, tilebuf + src_offset, (ncol * spp * bps) / 8);
          bufp += (imagewidth * bps * spp) / 8;
	  }
        }
      else
        {
	/* Bit depths not a multiple of 8 and/or extract fewer than spp samples */
        prev_trailing_bits = trailing_bits = 0;
        trailing_bits = (ncol * bps * spp) % 8;

	/*	for (trow = 0; tl < nrow; trow++) */
	for (trow = 0; trow < nrow; trow++)
          {
	  src_offset = trow * tile_rowsize;
          src = tilebuf + src_offset;
	  dst_offset = (row + trow) * dst_rowsize;
          dst = buf + dst_offset + col_offset;
          switch (shift_width)
            {
            case 0: if (extractContigSamplesBytes (src, dst, ncol, sample,
                                                   spp, bps, count, 0, ncol))
                      {
		      TIFFError("readContigTilesIntoBuffer",
                                "Unable to extract row %d from tile %lu", 
				row, (unsigned long)TIFFCurrentTile(in));
		      return 1;
		      }
		    break;
            case 1: if (bps == 1)
                      { 
                      if (extractContigSamplesShifted8bits (src, dst, ncol,
                                                            sample, spp,
                                                            bps, count,
                                                            0, ncol,
                                                            prev_trailing_bits))
                        {
		        TIFFError("readContigTilesIntoBuffer",
                                  "Unable to extract row %d from tile %lu", 
				  row, (unsigned long)TIFFCurrentTile(in));
		        return 1;
		        }
		      break;
		      }
                    else
                      if (extractContigSamplesShifted16bits (src, dst, ncol,
                                                             sample, spp,
                                                             bps, count,
                                                             0, ncol,
                                                             prev_trailing_bits))
                        {
		        TIFFError("readContigTilesIntoBuffer",
                                  "Unable to extract row %d from tile %lu", 
			  	  row, (unsigned long)TIFFCurrentTile(in));
		        return 1;
		        }
	            break;
            case 2: if (extractContigSamplesShifted24bits (src, dst, ncol,
                                                           sample, spp,
                                                           bps, count,
                                                           0, ncol,
                                                           prev_trailing_bits))
                      {
		      TIFFError("readContigTilesIntoBuffer",
                                "Unable to extract row %d from tile %lu", 
		  	        row, (unsigned long)TIFFCurrentTile(in));
		      return 1;
		      }
		    break;
            case 3:
            case 4:
            case 5: if (extractContigSamplesShifted32bits (src, dst, ncol,
                                                           sample, spp,
                                                           bps, count,
                                                           0, ncol,
                                                           prev_trailing_bits))
                      {
		      TIFFError("readContigTilesIntoBuffer",
                                "Unable to extract row %d from tile %lu", 
			        row, (unsigned long)TIFFCurrentTile(in));
		      return 1;
		      }
		    break;
            default: TIFFError("readContigTilesIntoBuffer", "Unsupported bit depth %d", bps);
		     return 1;
	    }
          }
        prev_trailing_bits += trailing_bits;
        /* if (prev_trailing_bits > 7) */
	/*   prev_trailing_bits-= 8; */
	}
      }
    }

  _TIFFfree(tilebuf);
  return status;
  }

Project: libtiff

static int writeBufferToContigTiles (TIFF* out, uint8* buf, uint32 imagelength,
				       uint32 imagewidth, tsample_t spp, 
                                       struct dump_opts* dump)
  {
  uint16 bps;
  uint32 tl, tw;
  uint32 row, col, nrow, ncol;
  uint32 src_rowsize, col_offset;
  uint32 tile_rowsize  = TIFFTileRowSize(out);
  uint8* bufp = (uint8*) buf;
  tsize_t tile_buffsize = 0;
  tsize_t tilesize = TIFFTileSize(out);
  unsigned char *tilebuf = NULL;

  if( !TIFFGetField(out, TIFFTAG_TILELENGTH, &tl) ||
      !TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw) ||
      !TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps) )
      return 1;

  if (tilesize == 0 || tile_rowsize == 0 || tl == 0 || tw == 0)
  {
    TIFFError("writeBufferToContigTiles", "Tile size, tile row size, tile width, or tile length is zero");
    exit(-1);
  }
  
  tile_buffsize = tilesize;
  if (tilesize < (tsize_t)(tl * tile_rowsize))
    {
#ifdef DEBUG2
    TIFFError("writeBufferToContigTiles",
	      "Tilesize %lu is too small, using alternate calculation %u",
              tilesize, tl * tile_rowsize);
#endif
    tile_buffsize = tl * tile_rowsize;
    if (tl != tile_buffsize / tile_rowsize)
    {
	TIFFError("writeBufferToContigTiles", "Integer overflow when calculating buffer size");
	exit(-1);
    }
    }

  if( imagewidth == 0 ||
      (uint32)bps * (uint32)spp > TIFF_UINT32_MAX / imagewidth ||
      bps * spp * imagewidth > TIFF_UINT32_MAX - 7U )
  {
      TIFFError(TIFFFileName(out),
            "Error, uint32 overflow when computing (imagewidth * bps * spp) + 7");
      return 1;
  }
  src_rowsize = ((imagewidth * spp * bps) + 7U) / 8;

  tilebuf = _TIFFmalloc(tile_buffsize);
  if (tilebuf == 0)
    return 1;
  for (row = 0; row < imagelength; row += tl)
    {
    nrow = (row + tl > imagelength) ? imagelength - row : tl;
    for (col = 0; col < imagewidth; col += tw)
      {
      /* Calculate visible portion of tile. */
      if (col + tw > imagewidth)
	ncol = imagewidth - col;
      else
        ncol = tw;

      col_offset = (((col * bps * spp) + 7) / 8);
      bufp = buf + (row * src_rowsize) + col_offset;
      if (extractContigSamplesToTileBuffer(tilebuf, bufp, nrow, ncol, imagewidth,
					   tw, 0, spp, spp, bps, dump) > 0)
        {
	TIFFError("writeBufferToContigTiles", 
                  "Unable to extract data to tile for row %lu, col %lu",
                  (unsigned long) row, (unsigned long)col);
	_TIFFfree(tilebuf);
	return 1;
        }

      if (TIFFWriteTile(out, tilebuf, col, row, 0, 0) < 0)
        {
	TIFFError("writeBufferToContigTiles",
	          "Cannot write tile at %lu %lu",
	          (unsigned long) col, (unsigned long) row);
	 _TIFFfree(tilebuf);
	return 1;
	}
      }
    }
  _TIFFfree(tilebuf);

  return 0;
  } /* end writeBufferToContigTiles */

Project: libtiff

static int writeBufferToSeparateTiles (TIFF* out, uint8* buf, uint32 imagelength,
				       uint32 imagewidth, tsample_t spp, 
                                       struct dump_opts * dump)
  {
  tdata_t obuf = _TIFFmalloc(TIFFTileSize(out));
  uint32 tl, tw;
  uint32 row, col, nrow, ncol;
  uint32 src_rowsize, col_offset;
  uint16 bps;
  tsample_t s;
  uint8* bufp = (uint8*) buf;

  if (obuf == NULL)
    return 1;

  TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
  TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
  TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);

  if( imagewidth == 0 ||
      (uint32)bps * (uint32)spp > TIFF_UINT32_MAX / imagewidth ||
      bps * spp * imagewidth > TIFF_UINT32_MAX - 7 )
  {
      TIFFError(TIFFFileName(out),
            "Error, uint32 overflow when computing (imagewidth * bps * spp) + 7");
      _TIFFfree(obuf);
      return 1;
  }
  src_rowsize = ((imagewidth * spp * bps) + 7U) / 8;
         
  for (row = 0; row < imagelength; row += tl)
    {
    nrow = (row + tl > imagelength) ? imagelength - row : tl;
    for (col = 0; col < imagewidth; col += tw)
      {
      /* Calculate visible portion of tile. */
      if (col + tw > imagewidth)
	ncol = imagewidth - col;
      else
        ncol = tw;

      col_offset = (((col * bps * spp) + 7) / 8);
      bufp = buf + (row * src_rowsize) + col_offset;

      for (s = 0; s < spp; s++)
        {
	if (extractContigSamplesToTileBuffer(obuf, bufp, nrow, ncol, imagewidth,
					     tw, s, 1, spp, bps, dump) > 0)
          {
	  TIFFError("writeBufferToSeparateTiles", 
                    "Unable to extract data to tile for row %lu, col %lu sample %d",
                    (unsigned long) row, (unsigned long)col, (int)s);
	  _TIFFfree(obuf);
	  return 1;
          }

	if (TIFFWriteTile(out, obuf, col, row, 0, s) < 0)
          {
	   TIFFError("writeBufferToseparateTiles",
	             "Cannot write tile at %lu %lu sample %lu",
	             (unsigned long) col, (unsigned long) row,
	             (unsigned long) s);
	   _TIFFfree(obuf);
	   return 1;
	  }
	}
      }
    }
  _TIFFfree(obuf);

  return 0;
  } /* end writeBufferToSeparateTiles */