From 473851d211cf8805a161820337ca74cc9615d6ef Mon Sep 17 00:00:00 2001
From: Nathan Baker <nathanb@lenovo-chrome.com>
Date: Tue, 6 Feb 2018 10:13:57 -0500
Subject: [PATCH] Fix for bug 2772

It is possible to craft a TIFF document where the IFD list is circular,
leading to an infinite loop while traversing the chain. The libtiff
directory reader has a failsafe that will break out of this loop after
reading 65535 directory entries, but it will continue processing,
consuming time and resources to process what is essentially a bogus TIFF
document.

This change fixes the above behavior by breaking out of processing when
a TIFF document has >= 65535 directories and terminating with an error.
---
 contrib/addtiffo/tif_overview.c | 14 +++++++++++++-
 tools/tiff2pdf.c                | 10 ++++++++++
 tools/tiffcrop.c                | 13 +++++++++++--
 3 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/contrib/addtiffo/tif_overview.c b/contrib/addtiffo/tif_overview.c
index c61ffbb..03b3573 100644
--- a/contrib/addtiffo/tif_overview.c
+++ b/contrib/addtiffo/tif_overview.c
@@ -65,6 +65,8 @@
 #  define MAX(a,b)      ((a>b) ? a : b)
 #endif
 
+#define TIFF_DIR_MAX  65534
+
 void TIFFBuildOverviews( TIFF *, int, int *, int, const char *,
                          int (*)(double,void*), void * );
 
@@ -91,6 +93,7 @@ uint32 TIFF_WriteOverview( TIFF *hTIFF, uint32 nXSize, uint32 nYSize,
 {
     toff_t	nBaseDirOffset;
     toff_t	nOffset;
+    tdir_t	iNumDir;
 
     (void) bUseSubIFDs;
 
@@ -147,7 +150,16 @@ uint32 TIFF_WriteOverview( TIFF *hTIFF, uint32 nXSize, uint32 nYSize,
         return 0;
 
     TIFFWriteDirectory( hTIFF );
-    TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) );
+    iNumDir = TIFFNumberOfDirectories(hTIFF);
+    if( iNumDir > TIFF_DIR_MAX )
+    {
+        TIFFErrorExt( TIFFClientdata(hTIFF),
+                      "TIFF_WriteOverview",
+                      "File `%s' has too many directories.\n",
+                      TIFFFileName(hTIFF) );
+        exit(-1);
+    }
+    TIFFSetDirectory( hTIFF, (tdir_t) (iNumDir - 1) );
 
     nOffset = TIFFCurrentDirOffset( hTIFF );
 
diff --git a/tools/tiff2pdf.c b/tools/tiff2pdf.c
index 984ef65..832a247 100644
--- a/tools/tiff2pdf.c
+++ b/tools/tiff2pdf.c
@@ -68,6 +68,8 @@ extern int getopt(int, char**, char*);
 
 #define PS_UNIT_SIZE	72.0F
 
+#define TIFF_DIR_MAX    65534
+
 /* This type is of PDF color spaces. */
 typedef enum {
 	T2P_CS_BILEVEL = 0x01,	/* Bilevel, black and white */
@@ -1053,6 +1053,14 @@ void t2p_read_tiff_init(T2P* t2p, TIFF* input){
 	float* tiff_transferfunction[3];
 
 	directorycount=TIFFNumberOfDirectories(input);
+	if(directorycount > TIFF_DIR_MAX) {
+		TIFFError(
+			TIFF2PDF_MODULE,
+			"TIFF contains too many directories, %s",
+			TIFFFileName(input));
+		t2p->t2p_error = T2P_ERR_ERROR;
+		return;
+	}
 	t2p->tiff_pages = (T2P_PAGE*) _TIFFmalloc(TIFFSafeMultiply(tmsize_t,directorycount,sizeof(T2P_PAGE)));
 	if(t2p->tiff_pages==NULL){
 		TIFFError(
diff --git a/tools/tiffcrop.c b/tools/tiffcrop.c
index 91a38f6..e466dae 100644
--- a/tools/tiffcrop.c
+++ b/tools/tiffcrop.c
@@ -215,6 +215,8 @@ extern int getopt(int argc, char * const argv[], const char *optstring);
 #define DUMP_TEXT   1
 #define DUMP_RAW    2
 
+#define TIFF_DIR_MAX  65534
+
 /* Offsets into buffer for margins and fixed width and length segments */
 struct offset {
   uint32  tmargin;
@@ -2232,7 +2234,7 @@ main(int argc, char* argv[])
     pageNum = -1;
   else
     total_images = 0;
-  /* read multiple input files and write to output file(s) */
+  /* Read multiple input files and write to output file(s) */
   while (optind < argc - 1)
     {
     in = TIFFOpen (argv[optind], "r");
@@ -2240,7 +2242,14 @@ main(int argc, char* argv[])
       return (-3);
 
     /* If only one input file is specified, we can use directory count */
-    total_images = TIFFNumberOfDirectories(in); 
+    total_images = TIFFNumberOfDirectories(in);
+    if (total_images > TIFF_DIR_MAX)
+      {
+      TIFFError (TIFFFileName(in), "File contains too many directories");
+      if (out != NULL)
+        (void) TIFFClose(out);
+      return (1);
+      }
     if (image_count == 0)
       {
       dirnum = 0;
--
libgit2 0.27.0