|
|
- From 1077fad562e03d1cad591dd10163dd80ad63ab0e Mon Sep 17 00:00:00 2001
- From: Even Rouault <even.rouault@spatialys.com>
- Date: Fri, 30 Jun 2017 13:11:18 +0000
- Subject: [PATCH] * libtiff/tif_read.c, tiffiop.h: add a
- _TIFFReadEncodedStripAndAllocBuffer() function, variant of
- TIFFReadEncodedStrip() that allocates the decoded buffer only after a first
- successful TIFFFillStrip(). This avoids excessive memory allocation on
- corrupted files. * libtiff/tif_getimage.c: use
- _TIFFReadEncodedStripAndAllocBuffer(). Fixes
- http://bugzilla.maptools.org/show_bug.cgi?id=2708 and
- https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2433 . Credit to OSS
- Fuzz
-
- ---
- ChangeLog | 11 +++++++
- libtiff/tif_getimage.c | 59 ++++++++++++++++++++++----------------
- libtiff/tif_read.c | 78 +++++++++++++++++++++++++++++++++++++++++++-------
- libtiff/tiffiop.h | 5 ++++
- 4 files changed, 118 insertions(+), 35 deletions(-)
-
- diff --git a/ChangeLog b/ChangeLog
- index c969f9e2..6f085e09 100644
- --- a/ChangeLog
- +++ b/ChangeLog
- @@ -1,3 +1,14 @@
- +2017-06-30 Even Rouault <even.rouault at spatialys.com>
- +
- + * libtiff/tif_read.c, tiffiop.h: add a _TIFFReadEncodedStripAndAllocBuffer()
- + function, variant of TIFFReadEncodedStrip() that allocates the
- + decoded buffer only after a first successful TIFFFillStrip(). This avoids
- + excessive memory allocation on corrupted files.
- + * libtiff/tif_getimage.c: use _TIFFReadEncodedStripAndAllocBuffer().
- + Fixes http://bugzilla.maptools.org/show_bug.cgi?id=2708 and
- + https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2433 .
- + Credit to OSS Fuzz
- +
- 2017-06-26 Even Rouault <even.rouault at spatialys.com>
-
- * libtiff/tif_jbig.c: fix memory leak in error code path of JBIGDecode()
- diff --git a/libtiff/tif_getimage.c b/libtiff/tif_getimage.c
- index cee8e930..cc6e8f30 100644
- --- a/libtiff/tif_getimage.c
- +++ b/libtiff/tif_getimage.c
- @@ -905,26 +905,22 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
- tileContigRoutine put = img->put.contig;
- uint32 row, y, nrow, nrowsub, rowstoread;
- tmsize_t pos;
- - unsigned char* buf;
- + unsigned char* buf = NULL;
- uint32 rowsperstrip;
- uint16 subsamplinghor,subsamplingver;
- uint32 imagewidth = img->width;
- tmsize_t scanline;
- int32 fromskew, toskew;
- int ret = 1, flip;
- + tmsize_t maxstripsize;
-
- TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver);
- if( subsamplingver == 0 ) {
- TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Invalid vertical YCbCr subsampling");
- return (0);
- }
- -
- - buf = (unsigned char*) _TIFFmalloc(TIFFStripSize(tif));
- - if (buf == 0) {
- - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
- - return (0);
- - }
- - _TIFFmemset(buf, 0, TIFFStripSize(tif));
- +
- + maxstripsize = TIFFStripSize(tif);
-
- flip = setorientation(img);
- if (flip & FLIP_VERTICALLY) {
- @@ -946,11 +942,12 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
- nrowsub = nrow;
- if ((nrowsub%subsamplingver)!=0)
- nrowsub+=subsamplingver-nrowsub%subsamplingver;
- - if (TIFFReadEncodedStrip(tif,
- + if (_TIFFReadEncodedStripAndAllocBuffer(tif,
- TIFFComputeStrip(tif,row+img->row_offset, 0),
- - buf,
- + (void**)(&buf),
- + maxstripsize,
- ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline)==(tmsize_t)(-1)
- - && img->stoponerr)
- + && (buf == NULL || img->stoponerr))
- {
- ret = 0;
- break;
- @@ -994,8 +991,8 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
- {
- TIFF* tif = img->tif;
- tileSeparateRoutine put = img->put.separate;
- - unsigned char *buf;
- - unsigned char *p0, *p1, *p2, *pa;
- + unsigned char *buf = NULL;
- + unsigned char *p0 = NULL, *p1 = NULL, *p2 = NULL, *pa = NULL;
- uint32 row, y, nrow, rowstoread;
- tmsize_t pos;
- tmsize_t scanline;
- @@ -1014,15 +1011,6 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
- TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtStripSeparate");
- return (0);
- }
- - p0 = buf = (unsigned char *)_TIFFmalloc(bufsize);
- - if (buf == 0) {
- - TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
- - return (0);
- - }
- - _TIFFmemset(buf, 0, bufsize);
- - p1 = p0 + stripsize;
- - p2 = p1 + stripsize;
- - pa = (alpha?(p2+stripsize):NULL);
-
- flip = setorientation(img);
- if (flip & FLIP_VERTICALLY) {
- @@ -1040,7 +1028,6 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
- case PHOTOMETRIC_MINISBLACK:
- case PHOTOMETRIC_PALETTE:
- colorchannels = 1;
- - p2 = p1 = p0;
- break;
-
- default:
- @@ -1056,7 +1043,31 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
- rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip;
- nrow = (row + rowstoread > h ? h - row : rowstoread);
- offset_row = row + img->row_offset;
- - if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0),
- + if( buf == NULL )
- + {
- + if (_TIFFReadEncodedStripAndAllocBuffer(
- + tif, TIFFComputeStrip(tif, offset_row, 0),
- + (void**) &buf, bufsize,
- + ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1)
- + && (buf == NULL || img->stoponerr))
- + {
- + ret = 0;
- + break;
- + }
- + p0 = buf;
- + if( colorchannels == 1 )
- + {
- + p2 = p1 = p0;
- + pa = (alpha?(p0+3*stripsize):NULL);
- + }
- + else
- + {
- + p1 = p0 + stripsize;
- + p2 = p1 + stripsize;
- + pa = (alpha?(p2+stripsize):NULL);
- + }
- + }
- + else if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0),
- p0, ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1)
- && img->stoponerr)
- {
- diff --git a/libtiff/tif_read.c b/libtiff/tif_read.c
- index fc0072e7..047305ab 100644
- --- a/libtiff/tif_read.c
- +++ b/libtiff/tif_read.c
- @@ -442,18 +442,17 @@ TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample)
- }
-
- /*
- - * Read a strip of data and decompress the specified
- - * amount into the user-supplied buffer.
- + * Calculate the strip size according to the number of
- + * rows in the strip (check for truncated last strip on any
- + * of the separations).
- */
- -tmsize_t
- -TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
- +static tmsize_t TIFFReadEncodedStripGetStripSize(TIFF* tif, uint32 strip, uint16* pplane)
- {
- static const char module[] = "TIFFReadEncodedStrip";
- TIFFDirectory *td = &tif->tif_dir;
- uint32 rowsperstrip;
- uint32 stripsperplane;
- uint32 stripinplane;
- - uint16 plane;
- uint32 rows;
- tmsize_t stripsize;
- if (!TIFFCheckRead(tif,0))
- @@ -465,23 +464,37 @@ TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
- (unsigned long)td->td_nstrips);
- return((tmsize_t)(-1));
- }
- - /*
- - * Calculate the strip size according to the number of
- - * rows in the strip (check for truncated last strip on any
- - * of the separations).
- - */
- +
- rowsperstrip=td->td_rowsperstrip;
- if (rowsperstrip>td->td_imagelength)
- rowsperstrip=td->td_imagelength;
- stripsperplane= TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
- stripinplane=(strip%stripsperplane);
- - plane=(uint16)(strip/stripsperplane);
- + if( pplane ) *pplane=(uint16)(strip/stripsperplane);
- rows=td->td_imagelength-stripinplane*rowsperstrip;
- if (rows>rowsperstrip)
- rows=rowsperstrip;
- stripsize=TIFFVStripSize(tif,rows);
- if (stripsize==0)
- return((tmsize_t)(-1));
- + return stripsize;
- +}
- +
- +/*
- + * Read a strip of data and decompress the specified
- + * amount into the user-supplied buffer.
- + */
- +tmsize_t
- +TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
- +{
- + static const char module[] = "TIFFReadEncodedStrip";
- + TIFFDirectory *td = &tif->tif_dir;
- + tmsize_t stripsize;
- + uint16 plane;
- +
- + stripsize=TIFFReadEncodedStripGetStripSize(tif, strip, &plane);
- + if (stripsize==((tmsize_t)(-1)))
- + return((tmsize_t)(-1));
-
- /* shortcut to avoid an extra memcpy() */
- if( td->td_compression == COMPRESSION_NONE &&
- @@ -510,6 +523,49 @@ TIFFReadEncodedStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size)
- return(stripsize);
- }
-
- +/* Variant of TIFFReadEncodedStrip() that does
- + * * if *buf == NULL, *buf = _TIFFmalloc(bufsizetoalloc) only after TIFFFillStrip() has
- + * suceeded. This avoid excessive memory allocation in case of truncated
- + * file.
- + * * calls regular TIFFReadEncodedStrip() if *buf != NULL
- + */
- +tmsize_t
- +_TIFFReadEncodedStripAndAllocBuffer(TIFF* tif, uint32 strip,
- + void **buf, tmsize_t bufsizetoalloc,
- + tmsize_t size_to_read)
- +{
- + tmsize_t this_stripsize;
- + uint16 plane;
- +
- + if( *buf != NULL )
- + {
- + return TIFFReadEncodedStrip(tif, strip, *buf, size_to_read);
- + }
- +
- + this_stripsize=TIFFReadEncodedStripGetStripSize(tif, strip, &plane);
- + if (this_stripsize==((tmsize_t)(-1)))
- + return((tmsize_t)(-1));
- +
- + if ((size_to_read!=(tmsize_t)(-1))&&(size_to_read<this_stripsize))
- + this_stripsize=size_to_read;
- + if (!TIFFFillStrip(tif,strip))
- + return((tmsize_t)(-1));
- +
- + *buf = _TIFFmalloc(bufsizetoalloc);
- + if (*buf == NULL) {
- + TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
- + return((tmsize_t)(-1));
- + }
- + _TIFFmemset(*buf, 0, bufsizetoalloc);
- +
- + if ((*tif->tif_decodestrip)(tif,*buf,this_stripsize,plane)<=0)
- + return((tmsize_t)(-1));
- + (*tif->tif_postdecode)(tif,*buf,this_stripsize);
- + return(this_stripsize);
- +
- +
- +}
- +
- static tmsize_t
- TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size,
- const char* module)
- diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h
- index 846ade03..7f0b90f7 100644
- --- a/libtiff/tiffiop.h
- +++ b/libtiff/tiffiop.h
- @@ -365,6 +365,11 @@ extern void* _TIFFCheckRealloc(TIFF*, void*, tmsize_t, tmsize_t, const char*);
- extern double _TIFFUInt64ToDouble(uint64);
- extern float _TIFFUInt64ToFloat(uint64);
-
- +extern tmsize_t
- +_TIFFReadEncodedStripAndAllocBuffer(TIFF* tif, uint32 strip,
- + void **buf, tmsize_t bufsizetoalloc,
- + tmsize_t size_to_read);
- +
- extern int TIFFInitDumpMode(TIFF*, int);
- #ifdef PACKBITS_SUPPORT
- extern int TIFFInitPackBits(TIFF*, int);
|