* 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
This commit is contained in:
Even Rouault 2017-06-12 19:13:49 +00:00
parent 56d802d409
commit 7057734d98
2 changed files with 40 additions and 17 deletions

View File

@ -1,3 +1,11 @@
2017-06-12 Even Rouault <even.rouault at spatialys.com>
* 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 <even.rouault at spatialys.com> 2017-06-12 Even Rouault <even.rouault at spatialys.com>
* libtiff/tif_dirread.c: fix regression of libtiff 4.0.8 in * libtiff/tif_dirread.c: fix regression of libtiff 4.0.8 in

View File

@ -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 * 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; int typesize;
uint32 datasize; uint32 datasize;
void* data; void* data;
uint64 target_count64;
typesize=TIFFDataWidth(direntry->tdir_type); 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; *value=0;
return(TIFFReadDirEntryErrOk); 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 * in either the current data type or the dest data type. This also
* avoids problems with overflow of tmsize_t on 32bit systems. * avoids problems with overflow of tmsize_t on 32bit systems.
*/ */
if ((uint64)(2147483647/typesize)<direntry->tdir_count) if ((uint64)(2147483647/typesize)<target_count64)
return(TIFFReadDirEntryErrSizesan); return(TIFFReadDirEntryErrSizesan);
if ((uint64)(2147483647/desttypesize)<direntry->tdir_count) if ((uint64)(2147483647/desttypesize)<target_count64)
return(TIFFReadDirEntryErrSizesan); return(TIFFReadDirEntryErrSizesan);
*count=(uint32)direntry->tdir_count; *count=(uint32)target_count64;
datasize=(*count)*typesize; datasize=(*count)*typesize;
assert((tmsize_t)datasize>0); assert((tmsize_t)datasize>0);
data=_TIFFCheckMalloc(tif, *count, typesize, "ReadDirEntryArray"); data=_TIFFCheckMalloc(tif, *count, typesize, "ReadDirEntryArray");
@ -834,6 +841,12 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryArray(TIFF* tif, TIFFDirEntry* d
return(TIFFReadDirEntryErrOk); 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) static enum TIFFReadDirEntryErr TIFFReadDirEntryByteArray(TIFF* tif, TIFFDirEntry* direntry, uint8** value)
{ {
enum TIFFReadDirEntryErr err; enum TIFFReadDirEntryErr err;
@ -1863,7 +1876,8 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntrySlongArray(TIFF* tif, TIFFDirEnt
return(TIFFReadDirEntryErrOk); 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; enum TIFFReadDirEntryErr err;
uint32 count; uint32 count;
@ -1883,7 +1897,7 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEnt
default: default:
return(TIFFReadDirEntryErrType); return(TIFFReadDirEntryErrType);
} }
err=TIFFReadDirEntryArray(tif,direntry,&count,8,&origdata); err=TIFFReadDirEntryArrayWithLimit(tif,direntry,&count,8,&origdata,maxcount);
if ((err!=TIFFReadDirEntryErrOk)||(origdata==0)) if ((err!=TIFFReadDirEntryErrOk)||(origdata==0))
{ {
*value=0; *value=0;
@ -2029,6 +2043,11 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryLong8Array(TIFF* tif, TIFFDirEnt
return(TIFFReadDirEntryErrOk); 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) static enum TIFFReadDirEntryErr TIFFReadDirEntrySlong8Array(TIFF* tif, TIFFDirEntry* direntry, int64** value)
{ {
enum TIFFReadDirEntryErr err; enum TIFFReadDirEntryErr err;
@ -3989,6 +4008,7 @@ TIFFReadDirectory(TIFF* tif)
tif->tif_dir.td_stripbytecount[0] < TIFFScanlineSize64(tif) * tif->tif_dir.td_imagelength) ) tif->tif_dir.td_stripbytecount[0] < TIFFScanlineSize64(tif) * tif->tif_dir.td_imagelength) )
} else if (tif->tif_dir.td_nstrips == 1 } else if (tif->tif_dir.td_nstrips == 1
&& !(tif->tif_flags&TIFF_ISTILED)
&& _TIFFFillStriles(tif) && _TIFFFillStriles(tif)
&& tif->tif_dir.td_stripoffset[0] != 0 && tif->tif_dir.td_stripoffset[0] != 0
&& BYTECOUNTLOOKSBAD) { && BYTECOUNTLOOKSBAD) {
@ -5433,14 +5453,14 @@ TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uint64** lpp)
static const char module[] = "TIFFFetchStripThing"; static const char module[] = "TIFFFetchStripThing";
enum TIFFReadDirEntryErr err; enum TIFFReadDirEntryErr err;
uint64* data; uint64* data;
err=TIFFReadDirEntryLong8Array(tif,dir,&data); err=TIFFReadDirEntryLong8ArrayWithLimit(tif,dir,&data,nstrips);
if (err!=TIFFReadDirEntryErrOk) if (err!=TIFFReadDirEntryErrOk)
{ {
const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag); const TIFFField* fip = TIFFFieldWithTag(tif,dir->tdir_tag);
TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0); TIFFReadDirEntryOutputErr(tif,err,module,fip ? fip->field_name : "unknown tagname",0);
return(0); return(0);
} }
if (dir->tdir_count!=(uint64)nstrips) if (dir->tdir_count<(uint64)nstrips)
{ {
uint64* resizeddata; uint64* resizeddata;
resizeddata=(uint64*)_TIFFCheckMalloc(tif,nstrips,sizeof(uint64),"for strip array"); 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); _TIFFfree(data);
return(0); 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));
_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));
_TIFFfree(data); _TIFFfree(data);
data=resizeddata; data=resizeddata;
} }