Do strip and tile size calculations in unsigned arithmetic, and then complain if the result overflows signed int32, because callers of these functions expect signed results (tsize_t is signed). CVE-2012-2088 NB: must be applied after libtiff-subsampling.patch to avoid fuzz issues. diff -Naur tiff-3.9.4.orig/libtiff/tif_strip.c tiff-3.9.4/libtiff/tif_strip.c --- tiff-3.9.4.orig/libtiff/tif_strip.c 2010-06-08 14:50:43.000000000 -0400 +++ tiff-3.9.4/libtiff/tif_strip.c 2012-06-27 12:37:55.054788399 -0400 @@ -107,6 +107,7 @@ TIFFVStripSize(TIFF* tif, uint32 nrows) { TIFFDirectory *td = &tif->tif_dir; + uint32 stripsize; if (nrows == (uint32) -1) nrows = td->td_imagelength; @@ -122,7 +123,7 @@ * YCbCr data for the extended image. */ uint16 ycbcrsubsampling[2]; - tsize_t w, scanline, samplingarea; + uint32 w, scanline, samplingarea; TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, ycbcrsubsampling + 0, @@ -141,13 +142,27 @@ nrows = TIFFroundup(nrows, ycbcrsubsampling[1]); /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ scanline = multiply(tif, nrows, scanline, "TIFFVStripSize"); - return ((tsize_t) - summarize(tif, scanline, - multiply(tif, 2, scanline / samplingarea, - "TIFFVStripSize"), "TIFFVStripSize")); + /* a zero anywhere in here means overflow, must return zero */ + if (scanline > 0) { + uint32 extra = + multiply(tif, 2, scanline / samplingarea, + "TIFFVStripSize"); + if (extra > 0) + stripsize = summarize(tif, scanline, extra, + "TIFFVStripSize"); + else + stripsize = 0; + } else + stripsize = 0; } else - return ((tsize_t) multiply(tif, nrows, TIFFScanlineSize(tif), - "TIFFVStripSize")); + stripsize = multiply(tif, nrows, TIFFScanlineSize(tif), + "TIFFVStripSize"); + /* Because tsize_t is signed, we might have conversion overflow */ + if (((tsize_t) stripsize) < 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", "TIFFVStripSize"); + stripsize = 0; + } + return (tsize_t) stripsize; } diff -Naur tiff-3.9.4.orig/libtiff/tif_tile.c tiff-3.9.4/libtiff/tif_tile.c --- tiff-3.9.4.orig/libtiff/tif_tile.c 2010-06-08 14:50:43.000000000 -0400 +++ tiff-3.9.4/libtiff/tif_tile.c 2012-06-27 12:37:55.055788446 -0400 @@ -174,7 +174,7 @@ TIFFTileRowSize(TIFF* tif) { TIFFDirectory *td = &tif->tif_dir; - tsize_t rowsize; + uint32 rowsize; if (td->td_tilelength == 0 || td->td_tilewidth == 0) return ((tsize_t) 0); @@ -193,7 +193,7 @@ TIFFVTileSize(TIFF* tif, uint32 nrows) { TIFFDirectory *td = &tif->tif_dir; - tsize_t tilesize; + uint32 tilesize; if (td->td_tilelength == 0 || td->td_tilewidth == 0 || td->td_tiledepth == 0) @@ -209,12 +209,12 @@ * horizontal/vertical subsampling area include * YCbCr data for the extended image. */ - tsize_t w = + uint32 w = TIFFroundup(td->td_tilewidth, td->td_ycbcrsubsampling[0]); - tsize_t rowsize = + uint32 rowsize = TIFFhowmany8(multiply(tif, w, td->td_bitspersample, "TIFFVTileSize")); - tsize_t samplingarea = + uint32 samplingarea = td->td_ycbcrsubsampling[0]*td->td_ycbcrsubsampling[1]; if (samplingarea == 0) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Invalid YCbCr subsampling"); @@ -223,15 +223,27 @@ nrows = TIFFroundup(nrows, td->td_ycbcrsubsampling[1]); /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ tilesize = multiply(tif, nrows, rowsize, "TIFFVTileSize"); - tilesize = summarize(tif, tilesize, - multiply(tif, 2, tilesize / samplingarea, - "TIFFVTileSize"), + /* a zero anywhere in here means overflow, must return zero */ + if (tilesize > 0) { + uint32 extra = + multiply(tif, 2, tilesize / samplingarea, "TIFFVTileSize"); + if (extra > 0) + tilesize = summarize(tif, tilesize, extra, + "TIFFVTileSize"); + else + tilesize = 0; + } } else tilesize = multiply(tif, nrows, TIFFTileRowSize(tif), "TIFFVTileSize"); - return ((tsize_t) - multiply(tif, tilesize, td->td_tiledepth, "TIFFVTileSize")); + tilesize = multiply(tif, tilesize, td->td_tiledepth, "TIFFVTileSize"); + /* Because tsize_t is signed, we might have conversion overflow */ + if (((tsize_t) tilesize) < 0) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", "TIFFVTileSize"); + tilesize = 0; + } + return (tsize_t) tilesize; } /*