diff --git a/ChangeLog b/ChangeLog index 5804889f..977bef28 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-06-12 Even Rouault + + * libtiff/tif_dirread.c: TIFFFetchStripThing(): limit the number of items + read in StripOffsets/StripByteCounts tags to the number of strips to avoid + excessive memory allocation. + Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2215 + Credit to OSS Fuzz + 2017-06-12 Even Rouault * libtiff/tif_dirread.c: fix regression of libtiff 4.0.8 in diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c index 4ac3f5e5..bf8cef22 100644 --- a/libtiff/tif_dirread.c +++ b/libtiff/tif_dirread.c @@ -1,4 +1,4 @@ -/* $Id: tif_dirread.c,v 1.210 2017-06-12 10:45:35 erouault Exp $ */ +/* $Id: tif_dirread.c,v 1.211 2017-06-12 19:13:49 erouault Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -765,13 +765,20 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryIfd8(TIFF* tif, TIFFDirEntry* di } } -static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value) +static enum TIFFReadDirEntryErr TIFFReadDirEntryArrayWithLimit( + TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, + void** value, uint64 maxcount) { int typesize; uint32 datasize; void* data; + uint64 target_count64; typesize=TIFFDataWidth(direntry->tdir_type); - if ((direntry->tdir_count==0)||(typesize==0)) + + target_count64 = (direntry->tdir_count > maxcount) ? + maxcount : direntry->tdir_count; + + if ((target_count64==0)||(typesize==0)) { *value=0; return(TIFFReadDirEntryErrOk); @@ -783,12 +790,12 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* d * in either the current data type or the dest data type. This also * avoids problems with overflow of tmsize_t on 32bit systems. */ - if ((uint64)(2147483647/typesize)tdir_count) + if ((uint64)(2147483647/typesize)tdir_count) + if ((uint64)(2147483647/desttypesize)tdir_count; + *count=(uint32)target_count64; datasize=(*count)*typesize; assert((tmsize_t)datasize>0); data=_TIFFCheckMalloc(tif, *count, typesize, "ReadDirEntryArray"); @@ -834,6 +841,12 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* d return(TIFFReadDirEntryErrOk); } +static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* direntry, uint32* count, uint32 desttypesize, void** value) +{ + return TIFFReadDirEntryArrayWithLimit(tif, direntry, count, + desttypesize, value, ~((uint64)0)); +} + static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value) { enum TIFFReadDirEntryErr err; @@ -1863,7 +1876,8 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEnt return(TIFFReadDirEntryErrOk); } -static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value) +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8ArrayWithLimit( + TIFF* tif, TIFFDirEntry* direntry, uint64** value, uint64 maxcount) { enum TIFFReadDirEntryErr err; uint32 count; @@ -1883,7 +1897,7 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEnt default: return(TIFFReadDirEntryErrType); } - err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata); + err=TIFFReadDirEntryArrayWithLimit(tif,direntry,&count,8,&origdata,maxcount); if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) { *value=0; @@ -2029,6 +2043,11 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEnt return(TIFFReadDirEntryErrOk); } +static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEntry* direntry, uint64** value) +{ + return TIFFReadDirEntryLong8ArrayWithLimit(tif, direntry, value, ~((uint64)0)); +} + static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** value) { enum TIFFReadDirEntryErr err; @@ -3989,6 +4008,7 @@ TIFFReadDirectory(TIFF* tif) tif->tif_dir.td_stripbytecount[0] < TIFFScanlineSize64(tif) * tif->tif_dir.td_imagelength) ) } else if (tif->tif_dir.td_nstrips == 1 + && !(tif->tif_flags&TIFF_ISTILED) && _TIFFFillStriles(tif) && tif->tif_dir.td_stripoffset[0] != 0 && BYTECOUNTLOOKSBAD) { @@ -5433,14 +5453,14 @@ TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp) static const char module[] = "TIFFFetchStripThing"; enum TIFFReadDirEntryErr err; uint64* data; - err=TIFFReadDirEntryLong8Array(tif,dir,&data); + err=TIFFReadDirEntryLong8ArrayWithLimit(tif,dir,&data,nstrips); if (err!=TIFFReadDirEntryErrOk) { const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag); TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0); return(0); } - if (dir->tdir_count!=(uint64)nstrips) + if (dir->tdir_count<(uint64)nstrips) { uint64* resizeddata; resizeddata=(uint64*)_TIFFCheckMalloc(tif,nstrips,sizeof(uint64),"for strip array"); @@ -5448,13 +5468,8 @@ TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp) _TIFFfree(data); return(0); } - if (dir->tdir_count<(uint64)nstrips) - { - _TIFFmemcpy(resizeddata,data,(uint32)dir->tdir_count*sizeof(uint64)); - _TIFFmemset(resizeddata+(uint32)dir->tdir_count,0,(nstrips-(uint32)dir->tdir_count)*sizeof(uint64)); - } - else - _TIFFmemcpy(resizeddata,data,nstrips*sizeof(uint64)); + _TIFFmemcpy(resizeddata,data,(uint32)dir->tdir_count*sizeof(uint64)); + _TIFFmemset(resizeddata+(uint32)dir->tdir_count,0,(nstrips-(uint32)dir->tdir_count)*sizeof(uint64)); _TIFFfree(data); data=resizeddata; }