|
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);
|