1From 49723b0eb683cca80142b01a48ba1475fed5188a Mon Sep 17 00:00:00 2001 2From: =?UTF-8?q?Nikola=20Forr=C3=B3?= <nforro@redhat.com> 3Date: Fri, 23 Mar 2018 15:35:39 +0100 4Subject: [PATCH] Fix for bug 2772 5 6It is possible to craft a TIFF document where the IFD list is circular, 7leading to an infinite loop while traversing the chain. The libtiff 8directory reader has a failsafe that will break out of this loop after 9reading 65535 directory entries, but it will continue processing, 10consuming time and resources to process what is essentially a bogus TIFF 11document. 12 13This change fixes the above behavior by breaking out of processing when 14a TIFF document has >= 65535 directories and terminating with an error. 15--- 16 contrib/addtiffo/tif_overview.c | 14 +++++++++++++- 17 tools/tiff2pdf.c | 10 ++++++++++ 18 tools/tiffcrop.c | 13 +++++++++++-- 19 3 files changed, 34 insertions(+), 3 deletions(-) 20 21diff --git a/contrib/addtiffo/tif_overview.c b/contrib/addtiffo/tif_overview.c 22index c61ffbb..03b3573 100644 23--- a/contrib/addtiffo/tif_overview.c 24+++ b/contrib/addtiffo/tif_overview.c 25@@ -65,6 +65,8 @@ 26 # define MAX(a,b) ((a>b) ? a : b) 27 #endif 28 29+#define TIFF_DIR_MAX 65534 30+ 31 void TIFFBuildOverviews( TIFF *, int, int *, int, const char *, 32 int (*)(double,void*), void * ); 33 34@@ -91,6 +93,7 @@ uint32 TIFF_WriteOverview( TIFF *hTIFF, uint32 nXSize, uint32 nYSize, 35 { 36 toff_t nBaseDirOffset; 37 toff_t nOffset; 38+ tdir_t iNumDir; 39 40 (void) bUseSubIFDs; 41 42@@ -147,7 +150,16 @@ uint32 TIFF_WriteOverview( TIFF *hTIFF, uint32 nXSize, uint32 nYSize, 43 return 0; 44 45 TIFFWriteDirectory( hTIFF ); 46- TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) ); 47+ iNumDir = TIFFNumberOfDirectories(hTIFF); 48+ if( iNumDir > TIFF_DIR_MAX ) 49+ { 50+ TIFFErrorExt( TIFFClientdata(hTIFF), 51+ "TIFF_WriteOverview", 52+ "File `%s' has too many directories.\n", 53+ TIFFFileName(hTIFF) ); 54+ exit(-1); 55+ } 56+ TIFFSetDirectory( hTIFF, (tdir_t) (iNumDir - 1) ); 57 58 nOffset = TIFFCurrentDirOffset( hTIFF ); 59 60diff --git a/tools/tiff2pdf.c b/tools/tiff2pdf.c 61index 454befb..bdb9126 100644 62--- a/tools/tiff2pdf.c 63+++ b/tools/tiff2pdf.c 64@@ -68,6 +68,8 @@ extern int getopt(int, char**, char*); 65 66 #define PS_UNIT_SIZE 72.0F 67 68+#define TIFF_DIR_MAX 65534 69+ 70 /* This type is of PDF color spaces. */ 71 typedef enum { 72 T2P_CS_BILEVEL = 0x01, /* Bilevel, black and white */ 73@@ -1049,6 +1051,14 @@ void t2p_read_tiff_init(T2P* t2p, TIFF* input){ 74 uint16 xuint16=0; 75 76 directorycount=TIFFNumberOfDirectories(input); 77+ if(directorycount > TIFF_DIR_MAX) { 78+ TIFFError( 79+ TIFF2PDF_MODULE, 80+ "TIFF contains too many directories, %s", 81+ TIFFFileName(input)); 82+ t2p->t2p_error = T2P_ERR_ERROR; 83+ return; 84+ } 85 t2p->tiff_pages = (T2P_PAGE*) _TIFFmalloc(TIFFSafeMultiply(tmsize_t,directorycount,sizeof(T2P_PAGE))); 86 if(t2p->tiff_pages==NULL){ 87 TIFFError( 88diff --git a/tools/tiffcrop.c b/tools/tiffcrop.c 89index c69177e..c60cb38 100644 90--- a/tools/tiffcrop.c 91+++ b/tools/tiffcrop.c 92@@ -217,6 +217,8 @@ extern int getopt(int argc, char * const argv[], const char *optstring); 93 #define DUMP_TEXT 1 94 #define DUMP_RAW 2 95 96+#define TIFF_DIR_MAX 65534 97+ 98 /* Offsets into buffer for margins and fixed width and length segments */ 99 struct offset { 100 uint32 tmargin; 101@@ -2233,7 +2235,7 @@ main(int argc, char* argv[]) 102 pageNum = -1; 103 else 104 total_images = 0; 105- /* read multiple input files and write to output file(s) */ 106+ /* Read multiple input files and write to output file(s) */ 107 while (optind < argc - 1) 108 { 109 in = TIFFOpen (argv[optind], "r"); 110@@ -2241,7 +2243,14 @@ main(int argc, char* argv[]) 111 return (-3); 112 113 /* If only one input file is specified, we can use directory count */ 114- total_images = TIFFNumberOfDirectories(in); 115+ total_images = TIFFNumberOfDirectories(in); 116+ if (total_images > TIFF_DIR_MAX) 117+ { 118+ TIFFError (TIFFFileName(in), "File contains too many directories"); 119+ if (out != NULL) 120+ (void) TIFFClose(out); 121+ return (1); 122+ } 123 if (image_count == 0) 124 { 125 dirnum = 0; 126-- 1272.13.6 128 129