* libtiff/tif_read.c: TIFFFillStrip() and TIFFFillTile():

avoid excessive memory allocation in case of shorten files.
Only effective on 64 bit builds and non-mapped cases.
Credit to OSS-Fuzz (locally run, on GDAL)
This commit is contained in:
Even Rouault 2017-05-10 19:38:49 +00:00
parent 328189565b
commit c9a6cfc51a
2 changed files with 193 additions and 15 deletions

View File

@ -1,3 +1,10 @@
2017-05-10 Even Rouault <even.rouault at spatialys.com>
* libtiff/tif_read.c: TIFFFillStrip() and TIFFFillTile():
avoid excessive memory allocation in case of shorten files.
Only effective on 64 bit builds and non-mapped cases.
Credit to OSS-Fuzz (locally run, on GDAL)
2017-05-10 Even Rouault <even.rouault at spatialys.com>
* libtiff/tif_zip.c, tif_pixarlog.c, tif_predict.c: fix memory

View File

@ -1,4 +1,4 @@
/* $Id: tif_read.c,v 1.54 2017-05-10 13:37:19 erouault Exp $ */
/* $Id: tif_read.c,v 1.55 2017-05-10 19:38:49 erouault Exp $ */
/*
* Copyright (c) 1988-1997 Sam Leffler
@ -463,6 +463,140 @@ TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size,
return (size);
}
#define INITIAL_THRESHOLD (1024 * 1024)
#define THRESHOLD_MULTIPLIER 10
#define MAX_THRESHOLD (THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * INITIAL_THRESHOLD)
static tmsize_t
TIFFReadRawStripOrTile2(TIFF* tif, uint32 strip_or_tile, int is_strip,
tmsize_t size, const char* module)
{
#if SIZEOF_VOIDP == 8 || SIZEOF_SIZE_T == 8
tmsize_t threshold = INITIAL_THRESHOLD;
#endif
tmsize_t already_read = 0;
TIFFDirectory *td = &tif->tif_dir;
assert( !isMapped(tif) );
assert((tif->tif_flags&TIFF_NOREADRAW)==0);
if (!SeekOK(tif, td->td_stripoffset[strip_or_tile])) {
if( is_strip )
{
TIFFErrorExt(tif->tif_clientdata, module,
"Seek error at scanline %lu, strip %lu",
(unsigned long) tif->tif_row,
(unsigned long) strip_or_tile);
}
else
{
TIFFErrorExt(tif->tif_clientdata, module,
"Seek error at row %lu, col %lu, tile %lu",
(unsigned long) tif->tif_row,
(unsigned long) tif->tif_col,
(unsigned long) strip_or_tile);
}
return ((tmsize_t)(-1));
}
/* On 64 bit processes, read first a maximum of 1 MB, then 10 MB, etc */
/* so as to avoid allocating too much memory in case the file is too */
/* short. We could ask for the file size, but this might be */
/* expensive with some I/O layers (think of reading a gzipped file) */
/* Restrict to 64 bit processes, so as to avoid reallocs() */
/* on 32 bit processes where virtual memory is scarce. */
while( already_read < size )
{
tmsize_t read;
tmsize_t to_read = size - already_read;
#if SIZEOF_VOIDP == 8 || SIZEOF_SIZE_T == 8
if( to_read >= threshold && threshold < MAX_THRESHOLD &&
already_read + to_read > tif->tif_rawdatasize )
{
to_read = threshold;
threshold *= THRESHOLD_MULTIPLIER;
}
#endif
if (already_read + to_read > tif->tif_rawdatasize) {
uint8* new_rawdata;
assert((tif->tif_flags & TIFF_MYBUFFER) != 0);
tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64(
(uint64)already_read + to_read, 1024);
if (tif->tif_rawdatasize==0) {
TIFFErrorExt(tif->tif_clientdata, module,
"Invalid buffer size");
return ((tmsize_t)(-1));
}
new_rawdata = (uint8*) _TIFFrealloc(
tif->tif_rawdata, tif->tif_rawdatasize);
if( new_rawdata == 0 )
{
TIFFErrorExt(tif->tif_clientdata, module,
"No space for data buffer at scanline %lu",
(unsigned long) tif->tif_row);
_TIFFfree(tif->tif_rawdata);
tif->tif_rawdata = 0;
tif->tif_rawdatasize = 0;
return ((tmsize_t)(-1));
}
tif->tif_rawdata = new_rawdata;
}
read = TIFFReadFile(tif, tif->tif_rawdata + already_read, to_read);
already_read += read;
if (read != to_read) {
memset( tif->tif_rawdata + already_read, 0,
tif->tif_rawdatasize - already_read );
#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
if( is_strip )
{
TIFFErrorExt(tif->tif_clientdata, module,
"Read error at scanline %lu; got %I64u bytes, "
"expected %I64u",
(unsigned long) tif->tif_row,
(unsigned __int64) already_read,
(unsigned __int64) size);
}
else
{
TIFFErrorExt(tif->tif_clientdata, module,
"Read error at row %lu, col %lu, tile %lu; "
"got %I64u bytes, expected %I64u",
(unsigned long) tif->tif_row,
(unsigned long) tif->tif_col,
(unsigned long) strip_or_tile,
(unsigned __int64) already_read,
(unsigned __int64) size);
}
#else
if( is_strip )
{
TIFFErrorExt(tif->tif_clientdata, module,
"Read error at scanline %lu; got %llu bytes, "
"expected %llu",
(unsigned long) tif->tif_row,
(unsigned long long) already_read,
(unsigned long long) size);
}
else
{
TIFFErrorExt(tif->tif_clientdata, module,
"Read error at row %lu, col %lu, tile %lu; "
"got %llu bytes, expected %llu",
(unsigned long) tif->tif_row,
(unsigned long) tif->tif_col,
(unsigned long) strip_or_tile,
(unsigned long long) already_read,
(unsigned long long) size);
}
#endif
return ((tmsize_t)(-1));
}
}
return (size);
}
/*
* Read a strip of data from the file.
*/
@ -666,17 +800,36 @@ TIFFFillStrip(TIFF* tif, uint32 strip)
(unsigned long) strip);
return (0);
}
if (!TIFFReadBufferSetup(tif, 0, bytecountm))
return (0);
}
if (tif->tif_flags&TIFF_BUFFERMMAP) {
tif->tif_curstrip = NOSTRIP;
if (!TIFFReadBufferSetup(tif, 0, bytecountm))
return (0);
tif->tif_rawdata = NULL;
tif->tif_rawdatasize = 0;
tif->tif_flags &= ~TIFF_BUFFERMMAP;
}
if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata,
bytecountm, module) != bytecountm)
return (0);
if( isMapped(tif) )
{
if (bytecountm > tif->tif_rawdatasize &&
!TIFFReadBufferSetup(tif, 0, bytecountm))
{
return (0);
}
if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata,
bytecountm, module) != bytecountm)
{
return (0);
}
}
else
{
if (TIFFReadRawStripOrTile2(tif, strip, 1,
bytecountm, module) != bytecountm)
{
return (0);
}
}
tif->tif_rawdataoff = 0;
tif->tif_rawdataloaded = bytecountm;
@ -959,18 +1112,36 @@ TIFFFillTile(TIFF* tif, uint32 tile)
(unsigned long) tile);
return (0);
}
if (!TIFFReadBufferSetup(tif, 0, bytecountm))
return (0);
}
if (tif->tif_flags&TIFF_BUFFERMMAP) {
tif->tif_curtile = NOTILE;
if (!TIFFReadBufferSetup(tif, 0, bytecountm))
return (0);
tif->tif_rawdata = NULL;
tif->tif_rawdatasize = 0;
tif->tif_flags &= ~TIFF_BUFFERMMAP;
}
if( isMapped(tif) )
{
if (bytecountm > tif->tif_rawdatasize &&
!TIFFReadBufferSetup(tif, 0, bytecountm))
{
return (0);
}
if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata,
bytecountm, module) != bytecountm)
{
return (0);
}
}
else
{
if (TIFFReadRawStripOrTile2(tif, tile, 0,
bytecountm, module) != bytecountm)
{
return (0);
}
}
if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata,
bytecountm, module) != bytecountm)
return (0);
tif->tif_rawdataoff = 0;
tif->tif_rawdataloaded = bytecountm;