diff --git a/SOURCES/libtiff-CVE-2019-14973.patch b/SOURCES/libtiff-CVE-2019-14973.patch new file mode 100644 index 0000000..c668664 --- /dev/null +++ b/SOURCES/libtiff-CVE-2019-14973.patch @@ -0,0 +1,830 @@ +From 3cb85548e07580e4d787ab7122900ae6946c8d26 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Nikola=20Forr=C3=B3?= +Date: Thu, 20 Feb 2020 13:08:37 +0100 +Subject: [PATCH 1/2] Fix CVE-2019-14973 + +--- + libtiff/tif_aux.c | 49 +++++- + libtiff/tif_getimage.c | 6 +- + libtiff/tif_luv.c | 7 +- + libtiff/tif_pixarlog.c | 18 +- + libtiff/tif_read.c | 375 ++++++++++++++++++++++++++++++++++------- + libtiff/tif_strip.c | 27 +-- + libtiff/tif_tile.c | 27 +-- + libtiff/tiffiop.h | 7 +- + 8 files changed, 377 insertions(+), 139 deletions(-) + +diff --git a/libtiff/tif_aux.c b/libtiff/tif_aux.c +index 927150a..f686a79 100644 +--- a/libtiff/tif_aux.c ++++ b/libtiff/tif_aux.c +@@ -59,18 +59,57 @@ _TIFFMultiply64(TIFF* tif, uint64 first, uint64 second, const char* where) + return bytes; + } + ++tmsize_t ++_TIFFMultiplySSize(TIFF* tif, tmsize_t first, tmsize_t second, const char* where) ++{ ++ if( first <= 0 || second <= 0 ) ++ { ++ if( tif != NULL && where != NULL ) ++ { ++ TIFFErrorExt(tif->tif_clientdata, where, ++ "Invalid argument to _TIFFMultiplySSize() in %s", where); ++ } ++ return 0; ++ } ++ ++ if( first > TIFF_TMSIZE_T_MAX / second ) ++ { ++ if( tif != NULL && where != NULL ) ++ { ++ TIFFErrorExt(tif->tif_clientdata, where, ++ "Integer overflow in %s", where); ++ } ++ return 0; ++ } ++ return first * second; ++} ++ ++tmsize_t _TIFFCastUInt64ToSSize(TIFF* tif, uint64 val, const char* module) ++{ ++ if( val > (uint64)TIFF_TMSIZE_T_MAX ) ++ { ++ if( tif != NULL && module != NULL ) ++ { ++ TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); ++ } ++ return 0; ++ } ++ return (tmsize_t)val; ++} ++ + void* + _TIFFCheckRealloc(TIFF* tif, void* buffer, + tmsize_t nmemb, tmsize_t elem_size, const char* what) + { + void* cp = NULL; +- tmsize_t bytes = nmemb * elem_size; +- ++ tmsize_t count = _TIFFMultiplySSize(tif, nmemb, elem_size, NULL); + /* +- * XXX: Check for integer overflow. ++ * Check for integer overflow. + */ +- if (nmemb && elem_size && bytes / elem_size == nmemb) +- cp = _TIFFrealloc(buffer, bytes); ++ if (count != 0) ++ { ++ cp = _TIFFrealloc(buffer, count); ++ } + + if (cp == NULL) { + TIFFErrorExt(tif->tif_clientdata, tif->tif_name, +diff --git a/libtiff/tif_getimage.c b/libtiff/tif_getimage.c +index 503237d..c664cc0 100644 +--- a/libtiff/tif_getimage.c ++++ b/libtiff/tif_getimage.c +@@ -720,9 +720,8 @@ gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) + int colorchannels; + + tilesize = TIFFTileSize(tif); +- bufsize = TIFFSafeMultiply(tmsize_t,alpha?4:3,tilesize); ++ bufsize = _TIFFMultiplySSize(tif, alpha?4:3,tilesize, "gtTileSeparate"); + if (bufsize == 0) { +- TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtTileSeparate"); + return (0); + } + buf = (unsigned char*) _TIFFmalloc(bufsize); +@@ -955,9 +954,8 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) + int ret = 1, flip, colorchannels; + + stripsize = TIFFStripSize(tif); +- bufsize = TIFFSafeMultiply(tmsize_t,alpha?4:3,stripsize); ++ bufsize = _TIFFMultiplySSize(tif,alpha?4:3,stripsize, "gtStripSeparate"); + if (bufsize == 0) { +- TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in %s", "gtStripSeparate"); + return (0); + } + p0 = buf = (unsigned char *)_TIFFmalloc(bufsize); +diff --git a/libtiff/tif_luv.c b/libtiff/tif_luv.c +index ebbd692..0607c41 100644 +--- a/libtiff/tif_luv.c ++++ b/libtiff/tif_luv.c +@@ -1244,12 +1244,7 @@ LogL16GuessDataFmt(TIFFDirectory *td) + static tmsize_t + multiply_ms(tmsize_t m1, tmsize_t m2) + { +- tmsize_t bytes = m1 * m2; +- +- if (m1 && bytes / m1 != m2) +- bytes = 0; +- +- return bytes; ++ return _TIFFMultiplySSize(NULL, m1, m2, NULL); + } + + static int +diff --git a/libtiff/tif_pixarlog.c b/libtiff/tif_pixarlog.c +index 6128f2f..558325d 100644 +--- a/libtiff/tif_pixarlog.c ++++ b/libtiff/tif_pixarlog.c +@@ -637,26 +637,20 @@ PixarLogGuessDataFmt(TIFFDirectory *td) + static tmsize_t + multiply_ms(tmsize_t m1, tmsize_t m2) + { +- tmsize_t bytes = m1 * m2; +- +- if (m1 && bytes / m1 != m2) +- bytes = 0; +- +- return bytes; ++ return _TIFFMultiplySSize(NULL, m1, m2, NULL); + } + + static tmsize_t + add_ms(tmsize_t m1, tmsize_t m2) + { +- tmsize_t bytes = m1 + m2; +- ++ assert(m1 >= 0 && m2 >= 0); + /* if either input is zero, assume overflow already occurred */ + if (m1 == 0 || m2 == 0) +- bytes = 0; +- else if (bytes <= m1 || bytes <= m2) +- bytes = 0; ++ return 0; ++ else if (m1 > TIFF_TMSIZE_T_MAX - m2) ++ return 0; + +- return bytes; ++ return m1 + m2; + } + + static int +diff --git a/libtiff/tif_read.c b/libtiff/tif_read.c +index ff5a548..2198b17 100644 +--- a/libtiff/tif_read.c ++++ b/libtiff/tif_read.c +@@ -1,4 +1,4 @@ +-/* $Id: tif_read.c,v 1.41 2012-07-06 19:22:58 bfriesen Exp $ */ ++/* $Id: tif_read.c,v 1.42 2013-01-18 21:37:13 fwarmerdam Exp $ */ + + /* + * Copyright (c) 1988-1997 Sam Leffler +@@ -42,14 +42,132 @@ TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size,const char* + #define NOSTRIP ((uint32)(-1)) /* undefined state */ + #define NOTILE ((uint32)(-1)) /* undefined state */ + ++#define INITIAL_THRESHOLD (1024 * 1024) ++#define THRESHOLD_MULTIPLIER 10 ++#define MAX_THRESHOLD (THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * INITIAL_THRESHOLD) ++ ++#define TIFF_INT64_MAX ((((int64)0x7FFFFFFF) << 32) | 0xFFFFFFFF) ++ ++/* Read 'size' bytes in tif_rawdata buffer starting at offset 'rawdata_offset' ++ * Returns 1 in case of success, 0 otherwise. */ ++static int TIFFReadAndRealloc( TIFF* tif, tmsize_t size, ++ tmsize_t rawdata_offset, ++ int is_strip, uint32 strip_or_tile, ++ const char* module ) ++{ ++#if SIZEOF_VOIDP == 8 || SIZEOF_SIZE_T == 8 ++ tmsize_t threshold = INITIAL_THRESHOLD; ++#endif ++ tmsize_t already_read = 0; ++ ++ /* On 64 bit processes, read first a maximum of 1 MB, then 10 MB, etc */ ++ /* so as to avoid allocating too much memory in case the file is too */ ++ /* short. We could ask for the file size, but this might be */ ++ /* expensive with some I/O layers (think of reading a gzipped file) */ ++ /* Restrict to 64 bit processes, so as to avoid reallocs() */ ++ /* on 32 bit processes where virtual memory is scarce. */ ++ while( already_read < size ) ++ { ++ tmsize_t bytes_read; ++ tmsize_t to_read = size - already_read; ++#if SIZEOF_VOIDP == 8 || SIZEOF_SIZE_T == 8 ++ if( to_read >= threshold && threshold < MAX_THRESHOLD && ++ already_read + to_read + rawdata_offset > tif->tif_rawdatasize ) ++ { ++ to_read = threshold; ++ threshold *= THRESHOLD_MULTIPLIER; ++ } ++#endif ++ if (already_read + to_read + rawdata_offset > tif->tif_rawdatasize) { ++ uint8* new_rawdata; ++ assert((tif->tif_flags & TIFF_MYBUFFER) != 0); ++ tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64( ++ (uint64)already_read + to_read + rawdata_offset, 1024); ++ if (tif->tif_rawdatasize==0) { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Invalid buffer size"); ++ return 0; ++ } ++ new_rawdata = (uint8*) _TIFFrealloc( ++ tif->tif_rawdata, tif->tif_rawdatasize); ++ if( new_rawdata == 0 ) ++ { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "No space for data buffer at scanline %lu", ++ (unsigned long) tif->tif_row); ++ _TIFFfree(tif->tif_rawdata); ++ tif->tif_rawdata = 0; ++ tif->tif_rawdatasize = 0; ++ return 0; ++ } ++ tif->tif_rawdata = new_rawdata; ++ } ++ ++ bytes_read = TIFFReadFile(tif, ++ tif->tif_rawdata + rawdata_offset + already_read, to_read); ++ already_read += bytes_read; ++ if (bytes_read != to_read) { ++ memset( tif->tif_rawdata + rawdata_offset + already_read, 0, ++ tif->tif_rawdatasize - rawdata_offset - already_read ); ++#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) ++ if( is_strip ) ++ { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Read error at scanline %lu; got %I64u bytes, " ++ "expected %I64u", ++ (unsigned long) tif->tif_row, ++ (unsigned __int64) already_read, ++ (unsigned __int64) size); ++ } ++ else ++ { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Read error at row %lu, col %lu, tile %lu; " ++ "got %I64u bytes, expected %I64u", ++ (unsigned long) tif->tif_row, ++ (unsigned long) tif->tif_col, ++ (unsigned long) strip_or_tile, ++ (unsigned __int64) already_read, ++ (unsigned __int64) size); ++ } ++#else ++ if( is_strip ) ++ { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Read error at scanline %lu; got %llu bytes, " ++ "expected %llu", ++ (unsigned long) tif->tif_row, ++ (unsigned long long) already_read, ++ (unsigned long long) size); ++ } ++ else ++ { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Read error at row %lu, col %lu, tile %lu; " ++ "got %llu bytes, expected %llu", ++ (unsigned long) tif->tif_row, ++ (unsigned long) tif->tif_col, ++ (unsigned long) strip_or_tile, ++ (unsigned long long) already_read, ++ (unsigned long long) size); ++ } ++#endif ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++ + static int + TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) + { + static const char module[] = "TIFFFillStripPartial"; + register TIFFDirectory *td = &tif->tif_dir; +- uint64 unused_data; ++ tmsize_t unused_data; + uint64 read_offset; +- tmsize_t cc, to_read; ++ tmsize_t to_read; ++ tmsize_t read_ahead_mod; + /* tmsize_t bytecountm; */ + + if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) +@@ -62,7 +180,14 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) + */ + + /* bytecountm=(tmsize_t) td->td_stripbytecount[strip]; */ +- if (read_ahead*2 > tif->tif_rawdatasize) { ++ ++ /* Not completely sure where the * 2 comes from, but probably for */ ++ /* an exponentional growth strategy of tif_rawdatasize */ ++ if( read_ahead < TIFF_TMSIZE_T_MAX / 2 ) ++ read_ahead_mod = read_ahead * 2; ++ else ++ read_ahead_mod = read_ahead; ++ if (read_ahead_mod > tif->tif_rawdatasize) { + assert( restart ); + + tif->tif_curstrip = NOSTRIP; +@@ -72,8 +197,6 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) + (unsigned long) strip); + return (0); + } +- if (!TIFFReadBufferSetup(tif, 0, read_ahead*2)) +- return (0); + } + + if( restart ) +@@ -113,34 +236,26 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) + /* + ** How much do we want to read? + */ +- to_read = tif->tif_rawdatasize - unused_data; ++ if( read_ahead_mod > tif->tif_rawdatasize ) ++ to_read = read_ahead_mod - unused_data; ++ else ++ to_read = tif->tif_rawdatasize - unused_data; + if( (uint64) to_read > td->td_stripbytecount[strip] + - tif->tif_rawdataoff - tif->tif_rawdataloaded ) + { +- to_read = td->td_stripbytecount[strip] ++ to_read = (tmsize_t) td->td_stripbytecount[strip] + - tif->tif_rawdataoff - tif->tif_rawdataloaded; + } + + assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); +- cc = TIFFReadFile(tif, tif->tif_rawdata + unused_data, to_read); +- +- if (cc != to_read) { +-#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) +- TIFFErrorExt(tif->tif_clientdata, module, +- "Read error at scanline %lu; got %I64u bytes, expected %I64u", +- (unsigned long) tif->tif_row, +- (unsigned __int64) cc, +- (unsigned __int64) to_read); +-#else +- TIFFErrorExt(tif->tif_clientdata, module, +- "Read error at scanline %lu; got %llu bytes, expected %llu", +- (unsigned long) tif->tif_row, +- (unsigned long long) cc, +- (unsigned long long) to_read); +-#endif ++ if( !TIFFReadAndRealloc( tif, to_read, unused_data, ++ 1, /* is_strip */ ++ 0, /* strip_or_tile */ ++ module) ) ++ { + return 0; + } +- ++ + tif->tif_rawdataoff = tif->tif_rawdataoff + tif->tif_rawdataloaded - unused_data ; + tif->tif_rawdataloaded = unused_data + to_read; + +@@ -214,7 +329,18 @@ TIFFSeek(TIFF* tif, uint32 row, uint16 sample ) + + if( !whole_strip ) + { +- read_ahead = tif->tif_scanlinesize * 16 + 5000; ++ /* 16 is for YCbCr mode where we may need to read 16 */ ++ /* lines at a time to get a decompressed line, and 5000 */ ++ /* is some constant value, for example for JPEG tables */ ++ if( tif->tif_scanlinesize < TIFF_TMSIZE_T_MAX / 16 && ++ tif->tif_scanlinesize * 16 < TIFF_TMSIZE_T_MAX - 5000 ) ++ { ++ read_ahead = tif->tif_scanlinesize * 16 + 5000; ++ } ++ else ++ { ++ read_ahead = tif->tif_scanlinesize; ++ } + } + + /* +@@ -401,7 +527,7 @@ TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size, + tmsize_t n; + ma=(tmsize_t)td->td_stripoffset[strip]; + mb=ma+size; +- if (((uint64)ma!=td->td_stripoffset[strip])||(ma>tif->tif_size)) ++ if ((td->td_stripoffset[strip] > (uint64)TIFF_TMSIZE_T_MAX)||(ma>tif->tif_size)) + n=0; + else if ((mbtif->tif_size)) + n=tif->tif_size-ma; +@@ -431,6 +557,43 @@ TIFFReadRawStrip1(TIFF* tif, uint32 strip, void* buf, tmsize_t size, + return (size); + } + ++static tmsize_t ++TIFFReadRawStripOrTile2(TIFF* tif, uint32 strip_or_tile, int is_strip, ++ tmsize_t size, const char* module) ++{ ++ TIFFDirectory *td = &tif->tif_dir; ++ ++ assert( !isMapped(tif) ); ++ assert((tif->tif_flags&TIFF_NOREADRAW)==0); ++ ++ if (!SeekOK(tif, td->td_stripoffset[strip_or_tile])) { ++ if( is_strip ) ++ { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Seek error at scanline %lu, strip %lu", ++ (unsigned long) tif->tif_row, ++ (unsigned long) strip_or_tile); ++ } ++ else ++ { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Seek error at row %lu, col %lu, tile %lu", ++ (unsigned long) tif->tif_row, ++ (unsigned long) tif->tif_col, ++ (unsigned long) strip_or_tile); ++ } ++ return ((tmsize_t)(-1)); ++ } ++ ++ if( !TIFFReadAndRealloc( tif, size, 0, is_strip, ++ strip_or_tile, module ) ) ++ { ++ return ((tmsize_t)(-1)); ++ } ++ ++ return (size); ++} ++ + /* + * Read a strip of data from the file. + */ +@@ -458,23 +621,8 @@ TIFFReadRawStrip(TIFF* tif, uint32 strip, void* buf, tmsize_t size) + return ((tmsize_t)(-1)); + } + bytecount = td->td_stripbytecount[strip]; +- if ((int64)bytecount <= 0) { +-#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) +- TIFFErrorExt(tif->tif_clientdata, module, +- "%I64u: Invalid strip byte count, strip %lu", +- (unsigned __int64) bytecount, +- (unsigned long) strip); +-#else +- TIFFErrorExt(tif->tif_clientdata, module, +- "%llu: Invalid strip byte count, strip %lu", +- (unsigned long long) bytecount, +- (unsigned long) strip); +-#endif +- return ((tmsize_t)(-1)); +- } +- bytecountm = (tmsize_t)bytecount; +- if ((uint64)bytecountm!=bytecount) { +- TIFFErrorExt(tif->tif_clientdata, module, "Integer overflow"); ++ bytecountm = _TIFFCastUInt64ToSSize(tif, bytecount, module); ++ if (bytecountm == 0) { + return ((tmsize_t)(-1)); + } + if (size != (tmsize_t)(-1) && size < bytecountm) +@@ -498,7 +646,7 @@ TIFFFillStrip(TIFF* tif, uint32 strip) + if ((tif->tif_flags&TIFF_NOREADRAW)==0) + { + uint64 bytecount = td->td_stripbytecount[strip]; +- if ((int64)bytecount <= 0) { ++ if( bytecount == 0 || bytecount > (uint64)TIFF_INT64_MAX ) { + #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "Invalid strip byte count %I64u, strip %lu", +@@ -512,6 +660,39 @@ TIFFFillStrip(TIFF* tif, uint32 strip) + #endif + return (0); + } ++ ++ /* To avoid excessive memory allocations: */ ++ /* Byte count should normally not be larger than a number of */ ++ /* times the uncompressed size plus some margin */ ++ if( bytecount > 1024 * 1024 ) ++ { ++ /* 10 and 4096 are just values that could be adjusted. */ ++ /* Hopefully they are safe enough for all codecs */ ++ tmsize_t stripsize = TIFFStripSize(tif); ++ if( stripsize != 0 && ++ (bytecount - 4096) / 10 > (uint64)stripsize ) ++ { ++ uint64 newbytecount = (uint64)stripsize * 10 + 4096; ++ if( newbytecount == 0 || newbytecount > (uint64)TIFF_INT64_MAX ) ++ { ++#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) ++ TIFFWarningExt(tif->tif_clientdata, module, ++ "Too large strip byte count %I64u, strip %lu. Limiting to %I64u", ++ (unsigned __int64) bytecount, ++ (unsigned long) strip, ++ (unsigned __int64) newbytecount); ++#else ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Too large strip byte count %llu, strip %lu. Limiting to %llu", ++ (unsigned long long) bytecount, ++ (unsigned long) strip, ++ (unsigned long long) newbytecount); ++#endif ++ bytecount = newbytecount; ++ } ++ } ++ } ++ + if (isMapped(tif) && + (isFillOrder(tif, td->td_fillorder) + || (tif->tif_flags & TIFF_NOBITREV))) { +@@ -601,17 +782,36 @@ TIFFFillStrip(TIFF* tif, uint32 strip) + (unsigned long) strip); + return (0); + } +- if (!TIFFReadBufferSetup(tif, 0, bytecountm)) +- return (0); + } + if (tif->tif_flags&TIFF_BUFFERMMAP) { + tif->tif_curstrip = NOSTRIP; +- if (!TIFFReadBufferSetup(tif, 0, bytecountm)) ++ tif->tif_rawdata = NULL; ++ tif->tif_rawdatasize = 0; ++ tif->tif_flags &= ~TIFF_BUFFERMMAP; ++ } ++ ++ if( isMapped(tif) ) ++ { ++ if (bytecountm > tif->tif_rawdatasize && ++ !TIFFReadBufferSetup(tif, 0, bytecountm)) ++ { ++ return (0); ++ } ++ if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata, ++ bytecountm, module) != bytecountm) ++ { + return (0); ++ } ++ } ++ else ++ { ++ if (TIFFReadRawStripOrTile2(tif, strip, 1, ++ bytecountm, module) != bytecountm) ++ { ++ return (0); ++ } + } +- if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata, +- bytecountm, module) != bytecountm) +- return (0); ++ + + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = bytecountm; +@@ -717,7 +917,7 @@ TIFFReadRawTile1(TIFF* tif, uint32 tile, void* buf, tmsize_t size, const char* m + tmsize_t n; + ma=(tmsize_t)td->td_stripoffset[tile]; + mb=ma+size; +- if (((uint64)ma!=td->td_stripoffset[tile])||(ma>tif->tif_size)) ++ if ((td->td_stripoffset[tile] > (uint64)TIFF_TMSIZE_T_MAX)||(ma>tif->tif_size)) + n=0; + else if ((mbtif->tif_size)) + n=tif->tif_size-ma; +@@ -776,10 +976,8 @@ TIFFReadRawTile(TIFF* tif, uint32 tile, void* buf, tmsize_t size) + bytecount64 = td->td_stripbytecount[tile]; + if (size != (tmsize_t)(-1) && (uint64)size < bytecount64) + bytecount64 = (uint64)size; +- bytecountm = (tmsize_t)bytecount64; +- if ((uint64)bytecountm!=bytecount64) +- { +- TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); ++ bytecountm = _TIFFCastUInt64ToSSize(tif, bytecount64, module); ++ if( bytecountm == 0 ) { + return ((tmsize_t)(-1)); + } + return (TIFFReadRawTile1(tif, tile, buf, bytecountm, module)); +@@ -801,7 +999,7 @@ TIFFFillTile(TIFF* tif, uint32 tile) + if ((tif->tif_flags&TIFF_NOREADRAW)==0) + { + uint64 bytecount = td->td_stripbytecount[tile]; +- if ((int64)bytecount <= 0) { ++ if( bytecount == 0 || bytecount > (uint64)TIFF_INT64_MAX ) { + #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) + TIFFErrorExt(tif->tif_clientdata, module, + "%I64u: Invalid tile byte count, tile %lu", +@@ -815,6 +1013,39 @@ TIFFFillTile(TIFF* tif, uint32 tile) + #endif + return (0); + } ++ ++ /* To avoid excessive memory allocations: */ ++ /* Byte count should normally not be larger than a number of */ ++ /* times the uncompressed size plus some margin */ ++ if( bytecount > 1024 * 1024 ) ++ { ++ /* 10 and 4096 are just values that could be adjusted. */ ++ /* Hopefully they are safe enough for all codecs */ ++ tmsize_t stripsize = TIFFTileSize(tif); ++ if( stripsize != 0 && ++ (bytecount - 4096) / 10 > (uint64)stripsize ) ++ { ++ uint64 newbytecount = (uint64)stripsize * 10 + 4096; ++ if( newbytecount == 0 || newbytecount > (uint64)TIFF_INT64_MAX ) ++ { ++#if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) ++ TIFFWarningExt(tif->tif_clientdata, module, ++ "Too large tile byte count %I64u, tile %lu. Limiting to %I64u", ++ (unsigned __int64) bytecount, ++ (unsigned long) tile, ++ (unsigned __int64) newbytecount); ++#else ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Too large tile byte count %llu, tile %lu. Limiting to %llu", ++ (unsigned long long) bytecount, ++ (unsigned long) tile, ++ (unsigned long long) newbytecount); ++#endif ++ bytecount = newbytecount; ++ } ++ } ++ } ++ + if (isMapped(tif) && + (isFillOrder(tif, td->td_fillorder) + || (tif->tif_flags & TIFF_NOBITREV))) { +@@ -876,18 +1107,36 @@ TIFFFillTile(TIFF* tif, uint32 tile) + (unsigned long) tile); + return (0); + } +- if (!TIFFReadBufferSetup(tif, 0, bytecountm)) +- return (0); + } + if (tif->tif_flags&TIFF_BUFFERMMAP) { + tif->tif_curtile = NOTILE; +- if (!TIFFReadBufferSetup(tif, 0, bytecountm)) ++ tif->tif_rawdata = NULL; ++ tif->tif_rawdatasize = 0; ++ tif->tif_flags &= ~TIFF_BUFFERMMAP; ++ } ++ ++ if( isMapped(tif) ) ++ { ++ if (bytecountm > tif->tif_rawdatasize && ++ !TIFFReadBufferSetup(tif, 0, bytecountm)) ++ { ++ return (0); ++ } ++ if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata, ++ bytecountm, module) != bytecountm) ++ { + return (0); ++ } ++ } ++ else ++ { ++ if (TIFFReadRawStripOrTile2(tif, tile, 0, ++ bytecountm, module) != bytecountm) ++ { ++ return (0); ++ } + } + +- if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata, +- bytecountm, module) != bytecountm) +- return (0); + + tif->tif_rawdataoff = 0; + tif->tif_rawdataloaded = bytecountm; +diff --git a/libtiff/tif_strip.c b/libtiff/tif_strip.c +index 568e489..206eeb8 100644 +--- a/libtiff/tif_strip.c ++++ b/libtiff/tif_strip.c +@@ -131,15 +131,8 @@ TIFFVStripSize(TIFF* tif, uint32 nrows) + { + static const char module[] = "TIFFVStripSize"; + uint64 m; +- tmsize_t n; + m=TIFFVStripSize64(tif,nrows); +- n=(tmsize_t)m; +- if ((uint64)n!=m) +- { +- TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); +- n=0; +- } +- return(n); ++ return _TIFFCastUInt64ToSSize(tif, m, module); + } + + /* +@@ -213,15 +206,8 @@ TIFFStripSize(TIFF* tif) + { + static const char module[] = "TIFFStripSize"; + uint64 m; +- tmsize_t n; + m=TIFFStripSize64(tif); +- n=(tmsize_t)m; +- if ((uint64)n!=m) +- { +- TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); +- n=0; +- } +- return(n); ++ return _TIFFCastUInt64ToSSize(tif, m, module); + } + + /* +@@ -362,15 +348,8 @@ TIFFRasterScanlineSize(TIFF* tif) + { + static const char module[] = "TIFFRasterScanlineSize"; + uint64 m; +- tmsize_t n; + m=TIFFRasterScanlineSize64(tif); +- n=(tmsize_t)m; +- if ((uint64)n!=m) +- { +- TIFFErrorExt(tif->tif_clientdata,module,"Integer arithmetic overflow"); +- n=0; +- } +- return(n); ++ return _TIFFCastUInt64ToSSize(tif, m, module); + } + + /* vim: set ts=8 sts=8 sw=8 noet: */ +diff --git a/libtiff/tif_tile.c b/libtiff/tif_tile.c +index 0ff7e85..57a063b 100644 +--- a/libtiff/tif_tile.c ++++ b/libtiff/tif_tile.c +@@ -160,15 +160,8 @@ TIFFTileRowSize(TIFF* tif) + { + static const char module[] = "TIFFTileRowSize"; + uint64 m; +- tmsize_t n; + m=TIFFTileRowSize64(tif); +- n=(tmsize_t)m; +- if ((uint64)n!=m) +- { +- TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); +- n=0; +- } +- return(n); ++ return _TIFFCastUInt64ToSSize(tif, m, module); + } + + /* +@@ -227,15 +220,8 @@ TIFFVTileSize(TIFF* tif, uint32 nrows) + { + static const char module[] = "TIFFVTileSize"; + uint64 m; +- tmsize_t n; + m=TIFFVTileSize64(tif,nrows); +- n=(tmsize_t)m; +- if ((uint64)n!=m) +- { +- TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); +- n=0; +- } +- return(n); ++ return _TIFFCastUInt64ToSSize(tif, m, module); + } + + /* +@@ -251,15 +237,8 @@ TIFFTileSize(TIFF* tif) + { + static const char module[] = "TIFFTileSize"; + uint64 m; +- tmsize_t n; + m=TIFFTileSize64(tif); +- n=(tmsize_t)m; +- if ((uint64)n!=m) +- { +- TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); +- n=0; +- } +- return(n); ++ return _TIFFCastUInt64ToSSize(tif, m, module); + } + + /* +diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h +index 8d1357b..d0987e2 100644 +--- a/libtiff/tiffiop.h ++++ b/libtiff/tiffiop.h +@@ -73,6 +73,9 @@ extern void *lfind(const void *, const void *, size_t *, size_t, + #define FALSE 0 + #endif + ++#define TIFF_SIZE_T_MAX ((size_t) ~ ((size_t)0)) ++#define TIFF_TMSIZE_T_MAX (tmsize_t)(TIFF_SIZE_T_MAX >> 1) ++ + typedef struct client_info { + struct client_info *next; + void *data; +@@ -251,7 +254,7 @@ struct tiff { + #define TIFFhowmany8_64(x) (((x)&0x07)?((uint64)(x)>>3)+1:(uint64)(x)>>3) + #define TIFFroundup_64(x, y) (TIFFhowmany_64(x,y)*(y)) + +-/* Safe multiply which returns zero if there is an integer overflow */ ++/* Safe multiply which returns zero if there is an *unsigned* integer overflow. This macro is not safe for *signed* integer types */ + #define TIFFSafeMultiply(t,v,m) ((((t)(m) != (t)0) && (((t)(((v)*(m))/(m))) == (t)(v))) ? (t)((v)*(m)) : (t)0) + + #define TIFFmax(A,B) ((A)>(B)?(A):(B)) +@@ -303,6 +306,8 @@ extern TIFFErrorHandlerExt _TIFFerrorHandlerExt; + + extern uint32 _TIFFMultiply32(TIFF*, uint32, uint32, const char*); + extern uint64 _TIFFMultiply64(TIFF*, uint64, uint64, const char*); ++extern tmsize_t _TIFFMultiplySSize(TIFF*, tmsize_t, tmsize_t, const char*); ++extern tmsize_t _TIFFCastUInt64ToSSize(TIFF*, uint64, const char*); + extern void* _TIFFCheckMalloc(TIFF*, tmsize_t, tmsize_t, const char*); + extern void* _TIFFCheckRealloc(TIFF*, void*, tmsize_t, tmsize_t, const char*); + +-- +2.21.1 + diff --git a/SOURCES/libtiff-CVE-2019-17546.patch b/SOURCES/libtiff-CVE-2019-17546.patch new file mode 100644 index 0000000..bd78e31 --- /dev/null +++ b/SOURCES/libtiff-CVE-2019-17546.patch @@ -0,0 +1,92 @@ +From 7a05de95bf761c4c2a9e409abd443b0c2c1d0ab7 Mon Sep 17 00:00:00 2001 +From: Even Rouault +Date: Thu, 15 Aug 2019 15:05:28 +0200 +Subject: [PATCH] RGBA interface: fix integer overflow potentially causing + write heap buffer overflow, especially on 32 bit builds. Fixes + https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=16443. Credit to OSS + Fuzz + +--- + libtiff/tif_getimage.c | 26 +++++++++++++++++++++----- + 1 file changed, 21 insertions(+), 5 deletions(-) + +diff --git a/libtiff/tif_getimage.c b/libtiff/tif_getimage.c +index c664cc0..4c79479 100644 +--- a/libtiff/tif_getimage.c ++++ b/libtiff/tif_getimage.c +@@ -889,15 +889,23 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) + fromskew = (w < imagewidth ? imagewidth - w : 0); + for (row = 0; row < h; row += nrow) + { ++ uint32 temp; + rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; + nrow = (row + rowstoread > h ? h - row : rowstoread); + nrowsub = nrow; + if ((nrowsub%subsamplingver)!=0) + nrowsub+=subsamplingver-nrowsub%subsamplingver; ++ temp = (row + img->row_offset)%rowsperstrip + nrowsub; ++ if( scanline > 0 && temp > (size_t)(TIFF_TMSIZE_T_MAX / scanline) ) ++ { ++ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in gtStripContig"); ++ _TIFFfree(buf); ++ return 0; ++ } + if (TIFFReadEncodedStrip(tif, + TIFFComputeStrip(tif,row+img->row_offset, 0), + buf, +- ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline)==(tmsize_t)(-1) ++ temp * scanline)==(tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; +@@ -997,11 +1005,19 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) + fromskew = (w < imagewidth ? imagewidth - w : 0); + for (row = 0; row < h; row += nrow) + { ++ uint32 temp; + rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; + nrow = (row + rowstoread > h ? h - row : rowstoread); + offset_row = row + img->row_offset; ++ temp = (row + img->row_offset)%rowsperstrip + nrow; ++ if( scanline > 0 && temp > (size_t)(TIFF_TMSIZE_T_MAX / scanline) ) ++ { ++ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Integer overflow in gtStripSeparate"); ++ _TIFFfree(buf); ++ return 0; ++ } + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0), +- p0, ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1) ++ p0, temp * scanline)==(tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; +@@ -1009,7 +1025,7 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) + } + if (colorchannels > 1 + && TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1), +- p1, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) == (tmsize_t)(-1) ++ p1, temp * scanline) == (tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; +@@ -1017,7 +1033,7 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) + } + if (colorchannels > 1 + && TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2), +- p2, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) == (tmsize_t)(-1) ++ p2, temp * scanline) == (tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; +@@ -1026,7 +1042,7 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) + if (alpha) + { + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, colorchannels), +- pa, ((row + img->row_offset)%rowsperstrip + nrow) * scanline)==(tmsize_t)(-1) ++ pa, temp * scanline)==(tmsize_t)(-1) + && img->stoponerr) + { + ret = 0; +-- +2.26.0.rc2 + diff --git a/SPECS/libtiff.spec b/SPECS/libtiff.spec index 59cbd7b..b2d6c52 100644 --- a/SPECS/libtiff.spec +++ b/SPECS/libtiff.spec @@ -1,7 +1,7 @@ Summary: Library of functions for manipulating TIFF format image files Name: libtiff Version: 4.0.3 -Release: 32%{?dist} +Release: 35%{?dist} License: libtiff Group: System Environment/Libraries @@ -53,6 +53,8 @@ Patch40: libtiff-CVE-2018-17101.patch Patch41: libtiff-CVE-2018-18557.patch Patch42: libtiff-CVE-2018-18661.patch Patch43: libtiff-coverity.patch +Patch44: libtiff-CVE-2019-14973.patch +Patch45: libtiff-CVE-2019-17546.patch BuildRequires: zlib-devel libjpeg-devel jbigkit-devel BuildRequires: libtool automake autoconf pkgconfig @@ -147,6 +149,8 @@ image files using the libtiff library. %patch41 -p1 %patch42 -p1 %patch43 -p1 +%patch44 -p1 +%patch45 -p1 # Use build system's libtool.m4, not the one in the package. rm -f libtool.m4 @@ -251,6 +255,18 @@ find html -name 'Makefile*' | xargs rm %{_mandir}/man1/* %changelog +* Mon Apr 06 2020 Nikola Forró - 4.0.3-35 +- Fix two resource leaks + Related: #1771371 + +* Thu Feb 20 2020 Nikola Forró - 4.0.3-34 +- Fix CVE-2019-17546 + Resolves: #1771371 + +* Thu Feb 20 2020 Nikola Forró - 4.0.3-33 +- Fix CVE-2019-14973 + Resolves: #1755704 + * Tue Apr 30 2019 Nikola Forró - 4.0.3-32 - Fix one more Covscan defect - Related: #1647965