diff --git a/imageio/imageio_util.c b/imageio/imageio_util.c index bdd1c644..df37137e 100644 --- a/imageio/imageio_util.c +++ b/imageio/imageio_util.c @@ -148,9 +148,11 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride, // ----------------------------------------------------------------------------- -int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) { - const uint64_t total_size = nmemb * size; +int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height) { + const uint64_t total_size = stride * height; int ok = (total_size == (size_t)total_size); + // check that 'stride' is representable as int: + ok = ok && ((uint64_t)(int)stride == stride); #if defined(WEBP_MAX_IMAGE_SIZE) ok = ok && (total_size <= (uint64_t)WEBP_MAX_IMAGE_SIZE); #endif diff --git a/imageio/imageio_util.h b/imageio/imageio_util.h index e13f9856..f135f566 100644 --- a/imageio/imageio_util.h +++ b/imageio/imageio_util.h @@ -54,8 +54,8 @@ void ImgIoUtilCopyPlane(const uint8_t* src, int src_stride, //------------------------------------------------------------------------------ -// Returns 0 in case of overflow of nmemb * size. -int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t nmemb, size_t size); +// Returns 0 in case of overflow, memory over-allocation or excessive dimension. +int ImgIoUtilCheckSizeArgumentsOverflow(uint64_t stride, size_t height); #ifdef __cplusplus } // extern "C" diff --git a/imageio/tiffdec.c b/imageio/tiffdec.c index 89819d4f..1c186b35 100644 --- a/imageio/tiffdec.c +++ b/imageio/tiffdec.c @@ -157,6 +157,7 @@ int ReadTIFF(const uint8_t* const data, size_t data_size, MyData my_data = { data, (toff_t)data_size, 0 }; TIFF* tif; uint32_t image_width, image_height, tile_width, tile_height; + uint64_t stride; uint16_t samples_per_px = 0; uint16_t extra_samples = 0; uint16_t* extra_samples_ptr = NULL; @@ -194,20 +195,31 @@ int ReadTIFF(const uint8_t* const data, size_t data_size, fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n"); goto End; } - if (!ImgIoUtilCheckSizeArgumentsOverflow((uint64_t)image_width * image_height, - sizeof(*raster))) { + stride = (uint64_t)image_width * sizeof(*raster); + if (!ImgIoUtilCheckSizeArgumentsOverflow(stride, image_height)) { + fprintf(stderr, "Error! TIFF image dimension (%d x %d) is too large.\n", + image_width, image_height); goto End; } + // According to spec, a tile can be bigger than the image. However it should - // be a multiple of 16 and not way too large, so check that it's not more than - // twice the image size, for dimensions above some arbitrary minimum 32. - if ((TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) && - tile_width > 32 && tile_width / 2 > image_width) || - (TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height) && - tile_height > 32 && tile_height / 2 > image_height)) { - fprintf(stderr, "Error! TIFF tile dimensions are too big.\n"); - goto End; + // be a multiple of 16 and not way too large, so check that it's not more + // than twice the image size, for dimensions above some arbitrary minimum + // 32. We also check that they respect WebP's dimension and memory limit. + // Note that a tile can be 6byte/px in some cases. Here we assume + // 4byte/px with sizeof(*raster), to be conservative. + if (TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width) && + TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height)) { + if ((tile_width > 32 && tile_width / 2 > image_width) || + (tile_height > 32 && tile_height / 2 > image_height) || + ImgIoUtilCheckSizeArgumentsOverflow( + (uint64_t)tile_width * sizeof(*raster), tile_height)) { + fprintf(stderr, "Error! TIFF tile dimension (%d x %d) is too large.\n", + tile_width, tile_height); + goto End; + } } + if (samples_per_px > 3 && !TIFFGetField(tif, TIFFTAG_EXTRASAMPLES, &extra_samples, &extra_samples_ptr)) { fprintf(stderr, "Error! Cannot retrieve TIFF ExtraSamples info.\n"); @@ -215,15 +227,13 @@ int ReadTIFF(const uint8_t* const data, size_t data_size, } // _Tiffmalloc uses a signed type for size. - alloc_size = - (int64_t)((uint64_t)image_width * image_height * sizeof(*raster)); + alloc_size = (int64_t)(stride * image_height); if (alloc_size < 0 || alloc_size != (tsize_t)alloc_size) goto End; raster = (uint32*)_TIFFmalloc((tsize_t)alloc_size); if (raster != NULL) { if (TIFFReadRGBAImageOriented(tif, image_width, image_height, raster, ORIENTATION_TOPLEFT, 1)) { - const int stride = image_width * sizeof(*raster); pic->width = image_width; pic->height = image_height; // TIFF data is ABGR @@ -241,8 +251,8 @@ int ReadTIFF(const uint8_t* const data, size_t data_size, } } ok = keep_alpha - ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride) - : WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride); + ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, (int)stride) + : WebPPictureImportRGBX(pic, (const uint8_t*)raster, (int)stride); } _TIFFfree(raster); } else {