diff --git a/backport-0001-CVE-2023-6277.patch b/backport-0001-CVE-2023-6277.patch new file mode 100644 index 0000000..3c8d407 --- /dev/null +++ b/backport-0001-CVE-2023-6277.patch @@ -0,0 +1,172 @@ +From 284ae90ae567de4ca53a3f32b472096f0da573a5 Mon Sep 17 00:00:00 2001 +From: Su Laus +Date: Sun, 5 Nov 2023 03:50:21 +0800 +Subject: [PATCH 1/2] Prevent some out-of-memory attacks + +Some small fuzzer files fake large amounts of data and provoke out-of-memory situations. For non-compressed data content / tags, out-of-memory can be prevented by comparing with the file size. + +At image reading, data size of some tags / data structures (StripByteCounts, StripOffsets, StripArray, TIFF directory) is compared with file size to prevent provoked out-of-memory attacks. + +See issue https://gitlab.com/libtiff/libtiff/-/issues/614#note_1602683857 +--- + libtiff/tif_dirread.c | 94 +++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 90 insertions(+), 4 deletions(-) + +diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c +index a762c67..2428257 100644 +--- a/libtiff/tif_dirread.c ++++ b/libtiff/tif_dirread.c +@@ -866,8 +866,23 @@ static enum TIFFReadDirEntryErr TIFFReadDirEntryArrayWithLimit( + datasize=(*count)*typesize; + assert((tmsize_t)datasize>0); + +- if( isMapped(tif) && datasize > (uint64_t)tif->tif_size ) +- return TIFFReadDirEntryErrIo; ++ /* Before allocating a huge amount of memory for corrupted files, check if ++ * size of requested memory is not greater than file size. ++ */ ++ uint64_t filesize = TIFFGetFileSize(tif); ++ if (datasize > filesize) ++ { ++ TIFFWarningExt(tif->tif_clientdata, "ReadDirEntryArray", ++ "Requested memory size for tag %d (0x%x) %" PRIu32 ++ " is greather than filesize %" PRIu64 ++ ". Memory not allocated, tag not read", ++ direntry->tdir_tag, direntry->tdir_tag, datasize, ++ filesize); ++ return (TIFFReadDirEntryErrAlloc); ++ } ++ ++ if (isMapped(tif) && datasize > (uint64_t)tif->tif_size) ++ return TIFFReadDirEntryErrIo; + + if( !isMapped(tif) && + (((tif->tif_flags&TIFF_BIGTIFF) && datasize > 8) || +@@ -4592,6 +4607,19 @@ EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount) + if( !_TIFFFillStrilesInternal( tif, 0 ) ) + return -1; + ++ /* Before allocating a huge amount of memory for corrupted files, check if ++ * size of requested memory is not greater than file size. */ ++ uint64_t filesize = TIFFGetFileSize(tif); ++ uint64_t allocsize = (uint64_t)td->td_nstrips * sizeof(uint64_t); ++ if (allocsize > filesize) ++ { ++ TIFFWarningExt(tif->tif_clientdata, module, ++ "Requested memory size for StripByteCounts of %" PRIu64 ++ " is greather than filesize %" PRIu64 ++ ". Memory not allocated", ++ allocsize, filesize); ++ return -1; ++ } + if (td->td_stripbytecount_p) + _TIFFfree(td->td_stripbytecount_p); + td->td_stripbytecount_p = (uint64_t*) +@@ -4602,9 +4630,7 @@ EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount) + + if (td->td_compression != COMPRESSION_NONE) { + uint64_t space; +- uint64_t filesize; + uint16_t n; +- filesize = TIFFGetFileSize(tif); + if (!(tif->tif_flags&TIFF_BIGTIFF)) + space=sizeof(TIFFHeaderClassic)+2+dircount*12+4; + else +@@ -4912,6 +4938,20 @@ TIFFFetchDirectory(TIFF* tif, uint64_t diroff, TIFFDirEntry** pdir, + dircount16 = (uint16_t)dircount64; + dirsize = 20; + } ++ /* Before allocating a huge amount of memory for corrupted files, check ++ * if size of requested memory is not greater than file size. */ ++ uint64_t filesize = TIFFGetFileSize(tif); ++ uint64_t allocsize = (uint64_t)dircount16 * dirsize; ++ if (allocsize > filesize) ++ { ++ TIFFWarningExt( ++ tif->tif_clientdata, module, ++ "Requested memory size for TIFF directory of %" PRIu64 ++ " is greather than filesize %" PRIu64 ++ ". Memory not allocated, TIFF directory not read", ++ allocsize, filesize); ++ return 0; ++ } + origdir = _TIFFCheckMalloc(tif, dircount16, + dirsize, "to read TIFF directory"); + if (origdir == NULL) +@@ -5015,6 +5055,20 @@ TIFFFetchDirectory(TIFF* tif, uint64_t diroff, TIFFDirEntry** pdir, + "Sanity check on directory count failed, zero tag directories not supported"); + return 0; + } ++ /* Before allocating a huge amount of memory for corrupted files, check ++ * if size of requested memory is not greater than file size. */ ++ uint64_t filesize = TIFFGetFileSize(tif); ++ uint64_t allocsize = (uint64_t)dircount16 * dirsize; ++ if (allocsize > filesize) ++ { ++ TIFFWarningExt( ++ tif->tif_clientdata, module, ++ "Requested memory size for TIFF directory of %" PRIu64 ++ " is greather than filesize %" PRIu64 ++ ". Memory not allocated, TIFF directory not read", ++ allocsize, filesize); ++ return 0; ++ } + origdir = _TIFFCheckMalloc(tif, dircount16, + dirsize, + "to read TIFF directory"); +@@ -5058,6 +5112,8 @@ TIFFFetchDirectory(TIFF* tif, uint64_t diroff, TIFFDirEntry** pdir, + } + } + } ++ /* No check against filesize needed here because "dir" should have same size ++ * than "origdir" checked above. */ + dir = (TIFFDirEntry*)_TIFFCheckMalloc(tif, dircount16, + sizeof(TIFFDirEntry), + "to read TIFF directory"); +@@ -5852,6 +5908,20 @@ TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32_t nstrips, uint64_t** l + return(0); + } + ++ /* Before allocating a huge amount of memory for corrupted files, check ++ * if size of requested memory is not greater than file size. */ ++ uint64_t filesize = TIFFGetFileSize(tif); ++ uint64_t allocsize = (uint64_t)nstrips * sizeof(uint64_t); ++ if (allocsize > filesize) ++ { ++ TIFFWarningExt(tif->tif_clientdata, module, ++ "Requested memory size for StripArray of %" PRIu64 ++ " is greather than filesize %" PRIu64 ++ ". Memory not allocated", ++ allocsize, filesize); ++ _TIFFfree(data); ++ return (0); ++ } + resizeddata=(uint64_t*)_TIFFCheckMalloc(tif, nstrips, sizeof(uint64_t), "for strip array"); + if (resizeddata==0) { + _TIFFfree(data); +@@ -5947,6 +6017,22 @@ static void allocChoppedUpStripArrays(TIFF* tif, uint32_t nstrips, + } + bytecount = last_offset + last_bytecount - offset; + ++ /* Before allocating a huge amount of memory for corrupted files, check if ++ * size of StripByteCount and StripOffset tags is not greater than ++ * file size. ++ */ ++ uint64_t allocsize = (uint64_t)nstrips * sizeof(uint64_t) * 2; ++ uint64_t filesize = TIFFGetFileSize(tif); ++ if (allocsize > filesize) ++ { ++ TIFFWarningExt(tif->tif_clientdata, "allocChoppedUpStripArrays", ++ "Requested memory size for StripByteCount and " ++ "StripOffsets %" PRIu64 ++ " is greather than filesize %" PRIu64 ++ ". Memory not allocated", ++ allocsize, filesize); ++ return; ++ } + newcounts = (uint64_t*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64_t), + "for chopped \"StripByteCounts\" array"); + newoffsets = (uint64_t*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint64_t), +-- +2.33.0 + diff --git a/backport-0002-CVE-2023-6277.patch b/backport-0002-CVE-2023-6277.patch new file mode 100644 index 0000000..39e343c --- /dev/null +++ b/backport-0002-CVE-2023-6277.patch @@ -0,0 +1,46 @@ +From fcfa5b516c43c0a8eabede226ec8df7852328339 Mon Sep 17 00:00:00 2001 +From: Even Rouault +Date: Sun, 5 Nov 2023 04:42:11 +0800 +Subject: [PATCH 2/2] TIFFReadRGBAStrip/TIFFReadRGBATile: add more validation + of col/row (fixes #622) + +--- + libtiff/tif_getimage.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/libtiff/tif_getimage.c b/libtiff/tif_getimage.c +index 9a2e0c5..ca4d227 100644 +--- a/libtiff/tif_getimage.c ++++ b/libtiff/tif_getimage.c +@@ -2942,6 +2942,13 @@ TIFFReadRGBAStripExt(TIFF* tif, uint32_t row, uint32_t * raster, int stop_on_err + } + + if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg)) { ++ if (row >= img.height) ++ { ++ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), ++ "Invalid row passed to TIFFReadRGBAStrip()."); ++ TIFFRGBAImageEnd(&img); ++ return (0); ++ } + + img.row_offset = row; + img.col_offset = 0; +@@ -3018,6 +3025,14 @@ TIFFReadRGBATileExt(TIFF* tif, uint32_t col, uint32_t row, uint32_t * raster, in + return( 0 ); + } + ++ if (col >= img.width || row >= img.height) ++ { ++ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), ++ "Invalid row/col passed to TIFFReadRGBATile()."); ++ TIFFRGBAImageEnd(&img); ++ return (0); ++ } ++ + /* + * The TIFFRGBAImageGet() function doesn't allow us to get off the + * edge of the image, even to fill an otherwise valid tile. So we +-- +2.33.0 + diff --git a/libtiff.spec b/libtiff.spec index e7f9d91..5c91d68 100644 --- a/libtiff.spec +++ b/libtiff.spec @@ -1,6 +1,6 @@ Name: libtiff Version: 4.3.0 -Release: 34 +Release: 35 Summary: TIFF Library and Utilities License: libtiff URL: https://www.simplesystems.org/libtiff/ @@ -50,6 +50,8 @@ Patch6040: backport-CVE-2022-34526.patch Patch6041: backport-CVE-2023-6228.patch Patch9000: fix-raw2tiff-floating-point-exception.patch +Patch9001: backport-0001-CVE-2023-6277.patch +Patch9002: backport-0002-CVE-2023-6277.patch BuildRequires: gcc gcc-c++ zlib-devel libjpeg-devel jbigkit-devel @@ -171,6 +173,9 @@ find html -name 'Makefile*' | xargs rm %exclude %{_datadir}/html/man/tiffgt.1.html %changelog +* Sat Nov 25 2023 liningjie - 4.3.0-35 +- fix CVE-2023-6277 + * Tue Nov 21 2023 liningjie - 4.3.0-34 - fix CVE-2023-6228