Fix heap-based buffer overflow in TIFFFillStrip():

http://bugzilla.maptools.org/show_bug.cgi?id=2608

2016-12-03 Even Rouault <even.rouault at spatialys.com>

        * libtiff/tif_dirread.c: modify ChopUpSingleUncompressedStrip() to
        instanciate compute ntrips as TIFFhowmany_32(td->td_imagelength,
rowsperstrip),
        instead of a logic based on the total size of data. Which is faulty is
        the total size of data is not sufficient to fill the whole image, and
thus
        results in reading outside of the StripByCounts/StripOffsets arrays
when
        using TIFFReadScanline().
        Reported by Agostino Sarubbo.
        Fixes http://bugzilla.maptools.org/show_bug.cgi?id=2608.

        * libtiff/tif_strip.c: revert the change in TIFFNumberOfStrips() done
        for http://bugzilla.maptools.org/show_bug.cgi?id=2587 / CVE-2016-9273
since
        the above change is a better fix that makes it unnecessary.

/cvs/maptools/cvsroot/libtiff/ChangeLog,v  <--  ChangeLog
new revision: 1.1176; previous revision: 1.1175
/cvs/maptools/cvsroot/libtiff/libtiff/tif_dirread.c,v  <-- 
libtiff/tif_dirread.c
new revision: 1.205; previous revision: 1.204
/cvs/maptools/cvsroot/libtiff/libtiff/tif_strip.c,v  <--  libtiff/tif_strip.c
new revision: 1.38; previous revision: 1.37

Index: libtiff/libtiff/tif_dirread.c
===================================================================
RCS file: /cvs/maptools/cvsroot/libtiff/libtiff/tif_dirread.c,v
retrieving revision 1.204
retrieving revision 1.205
diff -u -r1.204 -r1.205
--- libtiff/libtiff/tif_dirread.c	16 Nov 2016 15:14:15 -0000	1.204
+++ libtiff/libtiff/tif_dirread.c	3 Dec 2016 11:02:15 -0000	1.205
@@ -1,4 +1,4 @@
-/* $Id: tif_dirread.c,v 1.204 2016-11-16 15:14:15 erouault Exp $ */
+/* $Id: tif_dirread.c,v 1.205 2016-12-03 11:02:15 erouault Exp $ */
 
 /*
  * Copyright (c) 1988-1997 Sam Leffler
@@ -5502,8 +5502,7 @@
 	uint64 rowblockbytes;
 	uint64 stripbytes;
 	uint32 strip;
-	uint64 nstrips64;
-	uint32 nstrips32;
+	uint32 nstrips;
 	uint32 rowsperstrip;
 	uint64* newcounts;
 	uint64* newoffsets;
@@ -5534,18 +5533,17 @@
 	    return;
 
 	/*
-	 * never increase the number of strips in an image
+	 * never increase the number of rows per strip
 	 */
 	if (rowsperstrip >= td->td_rowsperstrip)
 		return;
-	nstrips64 = TIFFhowmany_64(bytecount, stripbytes);
-	if ((nstrips64==0)||(nstrips64>0xFFFFFFFF)) /* something is wonky, do nothing. */
-	    return;
-	nstrips32 = (uint32)nstrips64;
+        nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip);
+        if( nstrips == 0 )
+            return;
 
-	newcounts = (uint64*) _TIFFCheckMalloc(tif, nstrips32, sizeof (uint64),
+	newcounts = (uint64*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64),
 				"for chopped \"StripByteCounts\" array");
-	newoffsets = (uint64*) _TIFFCheckMalloc(tif, nstrips32, sizeof (uint64),
+	newoffsets = (uint64*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64),
 				"for chopped \"StripOffsets\" array");
 	if (newcounts == NULL || newoffsets == NULL) {
 		/*
@@ -5562,18 +5560,18 @@
 	 * Fill the strip information arrays with new bytecounts and offsets
 	 * that reflect the broken-up format.
 	 */
-	for (strip = 0; strip < nstrips32; strip++) {
+	for (strip = 0; strip < nstrips; strip++) {
 		if (stripbytes > bytecount)
 			stripbytes = bytecount;
 		newcounts[strip] = stripbytes;
-		newoffsets[strip] = offset;
+		newoffsets[strip] = stripbytes ? offset : 0;
 		offset += stripbytes;
 		bytecount -= stripbytes;
 	}
 	/*
 	 * Replace old single strip info with multi-strip info.
 	 */
-	td->td_stripsperimage = td->td_nstrips = nstrips32;
+	td->td_stripsperimage = td->td_nstrips = nstrips;
 	TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
 
 	_TIFFfree(td->td_stripbytecount);
Index: libtiff/libtiff/tif_strip.c
===================================================================
RCS file: /cvs/maptools/cvsroot/libtiff/libtiff/tif_strip.c,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -r1.37 -r1.38
--- libtiff/libtiff/tif_strip.c	9 Nov 2016 23:00:49 -0000	1.37
+++ libtiff/libtiff/tif_strip.c	3 Dec 2016 11:02:15 -0000	1.38
@@ -1,4 +1,4 @@
-/* $Id: tif_strip.c,v 1.37 2016-11-09 23:00:49 erouault Exp $ */
+/* $Id: tif_strip.c,v 1.38 2016-12-03 11:02:15 erouault Exp $ */
 
 /*
  * Copyright (c) 1991-1997 Sam Leffler
@@ -63,15 +63,6 @@
 	TIFFDirectory *td = &tif->tif_dir;
 	uint32 nstrips;
 
-    /* If the value was already computed and store in td_nstrips, then return it,
-       since ChopUpSingleUncompressedStrip might have altered and resized the
-       since the td_stripbytecount and td_stripoffset arrays to the new value
-       after the initial affectation of td_nstrips = TIFFNumberOfStrips() in
-       tif_dirread.c ~line 3612.
-       See http://bugzilla.maptools.org/show_bug.cgi?id=2587 */
-    if( td->td_nstrips )
-        return td->td_nstrips;
-
 	nstrips = (td->td_rowsperstrip == (uint32) -1 ? 1 :
 	     TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip));
 	if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
