import UBI libtiff-4.4.0-12.el9
This commit is contained in:
parent
503a6cd329
commit
9321e4aced
@ -0,0 +1,548 @@
|
||||
From 98648d3b62d4f123915410b8cae47954f9223000 Mon Sep 17 00:00:00 2001
|
||||
From: Even Rouault <even.rouault@spatialys.com>
|
||||
Date: Thu, 6 Oct 2022 10:11:06 +0000
|
||||
Subject: [PATCH] (CVE-2023-40090) Improved IFD-Loop Handling (fixes #455)
|
||||
|
||||
Closes #455
|
||||
|
||||
See merge request libtiff/libtiff!386
|
||||
|
||||
(cherry picked from commit d093eb5d961e21ba51420bc22382c514683a4d91)
|
||||
---
|
||||
libtiff/tif_close.c | 6 +-
|
||||
libtiff/tif_dir.c | 129 +++++++++++++++++++++++++-----------
|
||||
libtiff/tif_dir.h | 2 +
|
||||
libtiff/tif_dirread.c | 147 +++++++++++++++++++++++++++++++++---------
|
||||
libtiff/tif_open.c | 3 +-
|
||||
libtiff/tiffiop.h | 3 +-
|
||||
6 files changed, 219 insertions(+), 71 deletions(-)
|
||||
|
||||
diff --git a/libtiff/tif_close.c b/libtiff/tif_close.c
|
||||
index 6c9f7349..b5fa9603 100644
|
||||
--- a/libtiff/tif_close.c
|
||||
+++ b/libtiff/tif_close.c
|
||||
@@ -52,8 +52,10 @@ TIFFCleanup(TIFF* tif)
|
||||
(*tif->tif_cleanup)(tif);
|
||||
TIFFFreeDirectory(tif);
|
||||
|
||||
- if (tif->tif_dirlist)
|
||||
- _TIFFfree(tif->tif_dirlist);
|
||||
+ if (tif->tif_dirlistoff)
|
||||
+ _TIFFfree(tif->tif_dirlistoff);
|
||||
+ if (tif->tif_dirlistdirn)
|
||||
+ _TIFFfree(tif->tif_dirlistdirn);
|
||||
|
||||
/*
|
||||
* Clean up client info links.
|
||||
diff --git a/libtiff/tif_dir.c b/libtiff/tif_dir.c
|
||||
index a4295dc9..d9022f5b 100644
|
||||
--- a/libtiff/tif_dir.c
|
||||
+++ b/libtiff/tif_dir.c
|
||||
@@ -1521,12 +1521,22 @@ TIFFDefaultDirectory(TIFF* tif)
|
||||
}
|
||||
|
||||
static int
|
||||
-TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
|
||||
+TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdiroff, uint64_t* off, uint16_t* nextdirnum)
|
||||
{
|
||||
static const char module[] = "TIFFAdvanceDirectory";
|
||||
+
|
||||
+ /* Add this directory to the directory list, if not already in. */
|
||||
+ if (!_TIFFCheckDirNumberAndOffset(tif, *nextdirnum, *nextdiroff)) {
|
||||
+ TIFFErrorExt(tif->tif_clientdata, module, "Starting directory %"PRIu16" at offset 0x%"PRIx64" (%"PRIu64") might cause an IFD loop",
|
||||
+ *nextdirnum, *nextdiroff, *nextdiroff);
|
||||
+ *nextdiroff = 0;
|
||||
+ *nextdirnum = 0;
|
||||
+ return(0);
|
||||
+ }
|
||||
+
|
||||
if (isMapped(tif))
|
||||
{
|
||||
- uint64_t poff=*nextdir;
|
||||
+ uint64_t poff=*nextdiroff;
|
||||
if (!(tif->tif_flags&TIFF_BIGTIFF))
|
||||
{
|
||||
tmsize_t poffa,poffb,poffc,poffd;
|
||||
@@ -1537,7 +1547,7 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
|
||||
if (((uint64_t)poffa != poff) || (poffb < poffa) || (poffb < (tmsize_t)sizeof(uint16_t)) || (poffb > tif->tif_size))
|
||||
{
|
||||
TIFFErrorExt(tif->tif_clientdata,module,"Error fetching directory count");
|
||||
- *nextdir=0;
|
||||
+ *nextdiroff=0;
|
||||
return(0);
|
||||
}
|
||||
_TIFFmemcpy(&dircount,tif->tif_base+poffa,sizeof(uint16_t));
|
||||
@@ -1555,7 +1565,7 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
|
||||
_TIFFmemcpy(&nextdir32,tif->tif_base+poffc,sizeof(uint32_t));
|
||||
if (tif->tif_flags&TIFF_SWAB)
|
||||
TIFFSwabLong(&nextdir32);
|
||||
- *nextdir=nextdir32;
|
||||
+ *nextdiroff=nextdir32;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1587,11 +1597,10 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
|
||||
}
|
||||
if (off!=NULL)
|
||||
*off=(uint64_t)poffc;
|
||||
- _TIFFmemcpy(nextdir,tif->tif_base+poffc,sizeof(uint64_t));
|
||||
+ _TIFFmemcpy(nextdiroff,tif->tif_base+poffc,sizeof(uint64_t));
|
||||
if (tif->tif_flags&TIFF_SWAB)
|
||||
- TIFFSwabLong8(nextdir);
|
||||
+ TIFFSwabLong8(nextdiroff);
|
||||
}
|
||||
- return(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1599,7 +1608,7 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
|
||||
{
|
||||
uint16_t dircount;
|
||||
uint32_t nextdir32;
|
||||
- if (!SeekOK(tif, *nextdir) ||
|
||||
+ if (!SeekOK(tif, *nextdiroff) ||
|
||||
!ReadOK(tif, &dircount, sizeof (uint16_t))) {
|
||||
TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count",
|
||||
tif->tif_name);
|
||||
@@ -1620,13 +1629,13 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
|
||||
}
|
||||
if (tif->tif_flags & TIFF_SWAB)
|
||||
TIFFSwabLong(&nextdir32);
|
||||
- *nextdir=nextdir32;
|
||||
+ *nextdiroff=nextdir32;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t dircount64;
|
||||
uint16_t dircount16;
|
||||
- if (!SeekOK(tif, *nextdir) ||
|
||||
+ if (!SeekOK(tif, *nextdiroff) ||
|
||||
!ReadOK(tif, &dircount64, sizeof (uint64_t))) {
|
||||
TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count",
|
||||
tif->tif_name);
|
||||
@@ -1646,17 +1655,27 @@ TIFFAdvanceDirectory(TIFF* tif, uint64_t* nextdir, uint64_t* off)
|
||||
else
|
||||
(void) TIFFSeekFile(tif,
|
||||
dircount16*20, SEEK_CUR);
|
||||
- if (!ReadOK(tif, nextdir, sizeof (uint64_t))) {
|
||||
+ if (!ReadOK(tif, nextdiroff, sizeof (uint64_t))) {
|
||||
TIFFErrorExt(tif->tif_clientdata, module,
|
||||
"%s: Error fetching directory link",
|
||||
tif->tif_name);
|
||||
return (0);
|
||||
}
|
||||
if (tif->tif_flags & TIFF_SWAB)
|
||||
- TIFFSwabLong8(nextdir);
|
||||
+ TIFFSwabLong8(nextdiroff);
|
||||
}
|
||||
- return (1);
|
||||
}
|
||||
+ if (*nextdiroff != 0) {
|
||||
+ (*nextdirnum)++;
|
||||
+ /* Check next directory for IFD looping and if so, set it as last directory. */
|
||||
+ if (!_TIFFCheckDirNumberAndOffset(tif, *nextdirnum, *nextdiroff)) {
|
||||
+ TIFFWarningExt(tif->tif_clientdata, module, "the next directory %"PRIu16" at offset 0x%"PRIx64" (%"PRIu64") might be an IFD loop. Treating directory %"PRIu16" as last directory",
|
||||
+ *nextdirnum, *nextdiroff, *nextdiroff, *nextdirnum-1);
|
||||
+ *nextdiroff = 0;
|
||||
+ (*nextdirnum)--;
|
||||
+ }
|
||||
+ }
|
||||
+ return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1666,14 +1685,16 @@ uint16_t
|
||||
TIFFNumberOfDirectories(TIFF* tif)
|
||||
{
|
||||
static const char module[] = "TIFFNumberOfDirectories";
|
||||
- uint64_t nextdir;
|
||||
+ uint64_t nextdiroff;
|
||||
+ uint16_t nextdirnum;
|
||||
uint16_t n;
|
||||
if (!(tif->tif_flags&TIFF_BIGTIFF))
|
||||
- nextdir = tif->tif_header.classic.tiff_diroff;
|
||||
+ nextdiroff = tif->tif_header.classic.tiff_diroff;
|
||||
else
|
||||
- nextdir = tif->tif_header.big.tiff_diroff;
|
||||
+ nextdiroff = tif->tif_header.big.tiff_diroff;
|
||||
+ nextdirnum = 0;
|
||||
n = 0;
|
||||
- while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL))
|
||||
+ while (nextdiroff != 0 && TIFFAdvanceDirectory(tif, &nextdiroff, NULL, &nextdirnum))
|
||||
{
|
||||
if (n != 65535) {
|
||||
++n;
|
||||
@@ -1696,28 +1717,30 @@ TIFFNumberOfDirectories(TIFF* tif)
|
||||
int
|
||||
TIFFSetDirectory(TIFF* tif, uint16_t dirn)
|
||||
{
|
||||
- uint64_t nextdir;
|
||||
+ uint64_t nextdiroff;
|
||||
+ uint16_t nextdirnum;
|
||||
uint16_t n;
|
||||
|
||||
if (!(tif->tif_flags&TIFF_BIGTIFF))
|
||||
- nextdir = tif->tif_header.classic.tiff_diroff;
|
||||
+ nextdiroff = tif->tif_header.classic.tiff_diroff;
|
||||
else
|
||||
- nextdir = tif->tif_header.big.tiff_diroff;
|
||||
- for (n = dirn; n > 0 && nextdir != 0; n--)
|
||||
- if (!TIFFAdvanceDirectory(tif, &nextdir, NULL))
|
||||
+ nextdiroff = tif->tif_header.big.tiff_diroff;
|
||||
+ nextdirnum = 0;
|
||||
+ for (n = dirn; n > 0 && nextdiroff != 0; n--)
|
||||
+ if (!TIFFAdvanceDirectory(tif, &nextdiroff, NULL, &nextdirnum))
|
||||
return (0);
|
||||
- tif->tif_nextdiroff = nextdir;
|
||||
+ /* If the n-th directory could not be reached (does not exist),
|
||||
+ * return here without touching anything further. */
|
||||
+ if (nextdiroff == 0 || n > 0)
|
||||
+ return (0);
|
||||
+
|
||||
+ tif->tif_nextdiroff = nextdiroff;
|
||||
/*
|
||||
* Set curdir to the actual directory index. The
|
||||
* -1 is because TIFFReadDirectory will increment
|
||||
* tif_curdir after successfully reading the directory.
|
||||
*/
|
||||
tif->tif_curdir = (dirn - n) - 1;
|
||||
- /*
|
||||
- * Reset tif_dirnumber counter and start new list of seen directories.
|
||||
- * We need this to prevent IFD loops.
|
||||
- */
|
||||
- tif->tif_dirnumber = 0;
|
||||
return (TIFFReadDirectory(tif));
|
||||
}
|
||||
|
||||
@@ -1730,13 +1753,42 @@ TIFFSetDirectory(TIFF* tif, uint16_t dirn)
|
||||
int
|
||||
TIFFSetSubDirectory(TIFF* tif, uint64_t diroff)
|
||||
{
|
||||
- tif->tif_nextdiroff = diroff;
|
||||
- /*
|
||||
- * Reset tif_dirnumber counter and start new list of seen directories.
|
||||
- * We need this to prevent IFD loops.
|
||||
+ /* Match nextdiroff and curdir for consistent IFD-loop checking.
|
||||
+ * Only with TIFFSetSubDirectory() the IFD list can be corrupted with invalid offsets
|
||||
+ * within the main IFD tree.
|
||||
+ * In the case of several subIFDs of a main image,
|
||||
+ * there are two possibilities that are not even mutually exclusive.
|
||||
+ * a.) The subIFD tag contains an array with all offsets of the subIFDs.
|
||||
+ * b.) The SubIFDs are concatenated with their NextIFD parameters.
|
||||
+ * (refer to https://www.awaresystems.be/imaging/tiff/specification/TIFFPM6.pdf.)
|
||||
*/
|
||||
- tif->tif_dirnumber = 0;
|
||||
- return (TIFFReadDirectory(tif));
|
||||
+ int retval;
|
||||
+ uint16_t curdir = 0;
|
||||
+ int8_t probablySubIFD = 0;
|
||||
+ if (diroff == 0) {
|
||||
+ /* Special case to invalidate the tif_lastdiroff member. */
|
||||
+ tif->tif_curdir = 65535;
|
||||
+ } else {
|
||||
+ if (!_TIFFGetDirNumberFromOffset(tif, diroff, &curdir)) {
|
||||
+ /* Non-existing offsets might point to a SubIFD or invalid IFD.*/
|
||||
+ probablySubIFD = 1;
|
||||
+ }
|
||||
+ /* -1 because TIFFReadDirectory() will increment tif_curdir. */
|
||||
+ tif->tif_curdir = curdir - 1;
|
||||
+ }
|
||||
+
|
||||
+ tif->tif_nextdiroff = diroff;
|
||||
+ retval = TIFFReadDirectory(tif);
|
||||
+ /* If failed, curdir was not incremented in TIFFReadDirectory(), so set it back. */
|
||||
+ if (!retval )tif->tif_curdir++;
|
||||
+ if (retval && probablySubIFD) {
|
||||
+ /* Reset IFD list to start new one for SubIFD chain and also start SubIFD chain with tif_curdir=0. */
|
||||
+ tif->tif_dirnumber = 0;
|
||||
+ tif->tif_curdir = 0; /* first directory of new chain */
|
||||
+ /* add this offset to new IFD list */
|
||||
+ _TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff);
|
||||
+ }
|
||||
+ return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1760,12 +1812,15 @@ TIFFLastDirectory(TIFF* tif)
|
||||
|
||||
/*
|
||||
* Unlink the specified directory from the directory chain.
|
||||
+ * Note: First directory starts with number dirn=1.
|
||||
+ * This is different to TIFFSetDirectory() where the first directory starts with zero.
|
||||
*/
|
||||
int
|
||||
TIFFUnlinkDirectory(TIFF* tif, uint16_t dirn)
|
||||
{
|
||||
static const char module[] = "TIFFUnlinkDirectory";
|
||||
uint64_t nextdir;
|
||||
+ uint16_t nextdirnum;
|
||||
uint64_t off;
|
||||
uint16_t n;
|
||||
|
||||
@@ -1789,19 +1844,21 @@ TIFFUnlinkDirectory(TIFF* tif, uint16_t dirn)
|
||||
nextdir = tif->tif_header.big.tiff_diroff;
|
||||
off = 8;
|
||||
}
|
||||
+ nextdirnum = 0; /* First directory is dirn=0 */
|
||||
+
|
||||
for (n = dirn-1; n > 0; n--) {
|
||||
if (nextdir == 0) {
|
||||
TIFFErrorExt(tif->tif_clientdata, module, "Directory %"PRIu16" does not exist", dirn);
|
||||
return (0);
|
||||
}
|
||||
- if (!TIFFAdvanceDirectory(tif, &nextdir, &off))
|
||||
+ if (!TIFFAdvanceDirectory(tif, &nextdir, &off, &nextdirnum))
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Advance to the directory to be unlinked and fetch
|
||||
* the offset of the directory that follows.
|
||||
*/
|
||||
- if (!TIFFAdvanceDirectory(tif, &nextdir, NULL))
|
||||
+ if (!TIFFAdvanceDirectory(tif, &nextdir, NULL, &nextdirnum))
|
||||
return (0);
|
||||
/*
|
||||
* Go back and patch the link field of the preceding
|
||||
diff --git a/libtiff/tif_dir.h b/libtiff/tif_dir.h
|
||||
index 0c251c9e..deaa4594 100644
|
||||
--- a/libtiff/tif_dir.h
|
||||
+++ b/libtiff/tif_dir.h
|
||||
@@ -302,6 +302,8 @@ extern int _TIFFMergeFields(TIFF*, const TIFFField[], uint32_t);
|
||||
extern const TIFFField* _TIFFFindOrRegisterField(TIFF *, uint32_t, TIFFDataType);
|
||||
extern TIFFField* _TIFFCreateAnonField(TIFF *, uint32_t, TIFFDataType);
|
||||
extern int _TIFFCheckFieldIsValidForCodec(TIFF *tif, ttag_t tag);
|
||||
+extern int _TIFFCheckDirNumberAndOffset(TIFF *tif, uint16_t dirn, uint64_t diroff);
|
||||
+extern int _TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, uint16_t *dirn);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c
|
||||
index 32653f04..f4c1b08d 100644
|
||||
--- a/libtiff/tif_dirread.c
|
||||
+++ b/libtiff/tif_dirread.c
|
||||
@@ -159,7 +159,6 @@ static void TIFFReadDirectoryFindFieldInfo(TIFF* tif, uint16_t tagid, uint32_t*
|
||||
|
||||
static int EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16_t dircount);
|
||||
static void MissingRequired(TIFF*, const char*);
|
||||
-static int TIFFCheckDirOffset(TIFF* tif, uint64_t diroff);
|
||||
static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32_t);
|
||||
static uint16_t TIFFFetchDirectory(TIFF* tif, uint64_t diroff, TIFFDirEntry** pdir, uint64_t* nextdiroff);
|
||||
static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*, int recover);
|
||||
@@ -3922,12 +3921,19 @@ TIFFReadDirectory(TIFF* tif)
|
||||
int bitspersample_read = FALSE;
|
||||
int color_channels;
|
||||
|
||||
- tif->tif_diroff=tif->tif_nextdiroff;
|
||||
- if (!TIFFCheckDirOffset(tif,tif->tif_nextdiroff))
|
||||
- return 0; /* last offset or bad offset (IFD looping) */
|
||||
- (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
|
||||
- tif->tif_curdir++;
|
||||
- nextdiroff = tif->tif_nextdiroff;
|
||||
+ if (tif->tif_nextdiroff == 0) {
|
||||
+ /* In this special case, tif_diroff needs also to be set to 0. */
|
||||
+ tif->tif_diroff = tif->tif_nextdiroff;
|
||||
+ return 0; /* last offset, thus no checking necessary */
|
||||
+ }
|
||||
+
|
||||
+ nextdiroff = tif->tif_nextdiroff;
|
||||
+ /* tif_curdir++ and tif_nextdiroff should only be updated after SUCCESSFUL reading of the directory. Otherwise, invalid IFD offsets could corrupt the IFD list. */
|
||||
+ if (!_TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir + 1, nextdiroff)) {
|
||||
+ TIFFWarningExt(tif->tif_clientdata, module,
|
||||
+ "Didn't read next directory due to IFD looping at offset 0x%"PRIx64" (%"PRIu64") to offset 0x%"PRIx64" (%"PRIu64")", tif->tif_diroff, tif->tif_diroff, nextdiroff, nextdiroff);
|
||||
+ return 0; /* bad offset (IFD looping) */
|
||||
+ }
|
||||
dircount=TIFFFetchDirectory(tif,nextdiroff,&dir,&tif->tif_nextdiroff);
|
||||
if (!dircount)
|
||||
{
|
||||
@@ -3935,6 +3941,11 @@ TIFFReadDirectory(TIFF* tif)
|
||||
"Failed to read directory at offset %" PRIu64, nextdiroff);
|
||||
return 0;
|
||||
}
|
||||
+ /* Set global values after a valid directory has been fetched.
|
||||
+ * tif_diroff is already set to nextdiroff in TIFFFetchDirectory() in the beginning. */
|
||||
+ tif->tif_curdir++;
|
||||
+ (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
|
||||
+
|
||||
TIFFReadDirectoryCheckOrder(tif,dir,dircount);
|
||||
|
||||
/*
|
||||
@@ -5026,53 +5037,127 @@ MissingRequired(TIFF* tif, const char* tagname)
|
||||
}
|
||||
|
||||
/*
|
||||
- * Check the directory offset against the list of already seen directory
|
||||
- * offsets. This is a trick to prevent IFD looping. The one can create TIFF
|
||||
- * file with looped directory pointers. We will maintain a list of already
|
||||
- * seen directories and check every IFD offset against that list.
|
||||
+ * Check the directory number and offset against the list of already seen
|
||||
+ * directory numbers and offsets. This is a trick to prevent IFD looping.
|
||||
+ * The one can create TIFF file with looped directory pointers. We will
|
||||
+ * maintain a list of already seen directories and check every IFD offset
|
||||
+ * and its IFD number against that list. However, the offset of an IFD number
|
||||
+ * can change - e.g. when writing updates to file.
|
||||
+ * Returns 1 if all is ok; 0 if last directory or IFD loop is encountered,
|
||||
+ * or an error has occured.
|
||||
*/
|
||||
-static int
|
||||
-TIFFCheckDirOffset(TIFF* tif, uint64_t diroff)
|
||||
+int
|
||||
+_TIFFCheckDirNumberAndOffset(TIFF *tif, uint16_t dirn, uint64_t diroff)
|
||||
{
|
||||
uint16_t n;
|
||||
|
||||
if (diroff == 0) /* no more directories */
|
||||
return 0;
|
||||
if (tif->tif_dirnumber == 65535) {
|
||||
- TIFFErrorExt(tif->tif_clientdata, "TIFFCheckDirOffset",
|
||||
- "Cannot handle more than 65535 TIFF directories");
|
||||
- return 0;
|
||||
+ TIFFErrorExt(tif->tif_clientdata, "_TIFFCheckDirNumberAndOffset",
|
||||
+ "Cannot handle more than 65535 TIFF directories");
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
- for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) {
|
||||
- if (tif->tif_dirlist[n] == diroff)
|
||||
- return 0;
|
||||
+ /* Check if offset is already in the list:
|
||||
+ * - yes: check, if offset is at the same IFD number - if not, it is an IFD loop
|
||||
+ * - no: add to list or update offset at that IFD number
|
||||
+ */
|
||||
+ for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlistdirn && tif->tif_dirlistoff; n++) {
|
||||
+ if (tif->tif_dirlistoff[n] == diroff) {
|
||||
+ if (tif->tif_dirlistdirn[n] == dirn) {
|
||||
+ return 1;
|
||||
+ } else {
|
||||
+ TIFFWarningExt(tif->tif_clientdata, "_TIFFCheckDirNumberAndOffset",
|
||||
+ "TIFF directory %"PRIu16" has IFD looping to directory %"PRIu16" at offset 0x%"PRIx64" (%"PRIu64")",
|
||||
+ dirn-1, tif->tif_dirlistdirn[n], diroff, diroff);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ /* Check if offset of an IFD has been changed and update offset of that IFD number. */
|
||||
+ if (dirn < tif->tif_dirnumber && tif->tif_dirlistdirn && tif->tif_dirlistoff) {
|
||||
+ /* tif_dirlistdirn can have IFD numbers dirn in random order */
|
||||
+ for (n = 0; n < tif->tif_dirnumber; n++) {
|
||||
+ if (tif->tif_dirlistdirn[n] == dirn) {
|
||||
+ tif->tif_dirlistoff[n] = diroff;
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
+ /* Add IFD offset and dirn to IFD directory list */
|
||||
tif->tif_dirnumber++;
|
||||
|
||||
- if (tif->tif_dirlist == NULL || tif->tif_dirnumber > tif->tif_dirlistsize) {
|
||||
- uint64_t* new_dirlist;
|
||||
-
|
||||
+ if (tif->tif_dirlistoff == NULL || tif->tif_dirlistdirn == NULL || tif->tif_dirnumber > tif->tif_dirlistsize) {
|
||||
+ uint64_t *new_dirlist;
|
||||
/*
|
||||
* XXX: Reduce memory allocation granularity of the dirlist
|
||||
* array.
|
||||
*/
|
||||
- new_dirlist = (uint64_t*)_TIFFCheckRealloc(tif, tif->tif_dirlist,
|
||||
- tif->tif_dirnumber, 2 * sizeof(uint64_t), "for IFD list");
|
||||
+ if (tif->tif_dirnumber >= 32768)
|
||||
+ tif->tif_dirlistsize = 65535;
|
||||
+ else
|
||||
+ tif->tif_dirlistsize = 2 * tif->tif_dirnumber;
|
||||
+
|
||||
+ new_dirlist = (uint64_t *)_TIFFCheckRealloc(tif, tif->tif_dirlistoff,
|
||||
+ tif->tif_dirlistsize, sizeof(uint64_t), "for IFD offset list");
|
||||
if (!new_dirlist)
|
||||
return 0;
|
||||
- if( tif->tif_dirnumber >= 32768 )
|
||||
- tif->tif_dirlistsize = 65535;
|
||||
- else
|
||||
- tif->tif_dirlistsize = 2 * tif->tif_dirnumber;
|
||||
- tif->tif_dirlist = new_dirlist;
|
||||
+ tif->tif_dirlistoff = new_dirlist;
|
||||
+ new_dirlist = (uint64_t *)_TIFFCheckRealloc(tif, tif->tif_dirlistdirn,
|
||||
+ tif->tif_dirlistsize, sizeof(uint16_t), "for IFD dirnumber list");
|
||||
+ if (!new_dirlist)
|
||||
+ return 0;
|
||||
+ tif->tif_dirlistdirn = (uint16_t *)new_dirlist;
|
||||
}
|
||||
|
||||
- tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff;
|
||||
+ tif->tif_dirlistoff[tif->tif_dirnumber - 1] = diroff;
|
||||
+ tif->tif_dirlistdirn[tif->tif_dirnumber - 1] = dirn;
|
||||
|
||||
return 1;
|
||||
-}
|
||||
+} /* --- _TIFFCheckDirNumberAndOffset() ---*/
|
||||
+
|
||||
+/*
|
||||
+ * Retrieve the matching IFD directory number of a given IFD offset
|
||||
+ * from the list of directories already seen.
|
||||
+ * Returns 1 if the offset was in the list and the directory number
|
||||
+ * can be returned.
|
||||
+ * Otherwise returns 0 or if an error occured.
|
||||
+ */
|
||||
+int
|
||||
+_TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, uint16_t* dirn)
|
||||
+{
|
||||
+ uint16_t n;
|
||||
+
|
||||
+ if (diroff == 0) /* no more directories */
|
||||
+ return 0;
|
||||
+ if (tif->tif_dirnumber == 65535) {
|
||||
+ TIFFErrorExt(tif->tif_clientdata, "_TIFFGetDirNumberFromOffset",
|
||||
+ "Cannot handle more than 65535 TIFF directories");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /* Check if offset is already in the list and return matching directory number.
|
||||
+ * Otherwise update IFD list using TIFFNumberOfDirectories()
|
||||
+ * and search again in IFD list.
|
||||
+ */
|
||||
+ for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlistoff && tif->tif_dirlistdirn; n++) {
|
||||
+ if (tif->tif_dirlistoff[n] == diroff) {
|
||||
+ *dirn = tif->tif_dirlistdirn[n];
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+ TIFFNumberOfDirectories(tif);
|
||||
+ for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlistoff && tif->tif_dirlistdirn; n++) {
|
||||
+ if (tif->tif_dirlistoff[n] == diroff) {
|
||||
+ *dirn = tif->tif_dirlistdirn[n];
|
||||
+ return 1;
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+} /*--- _TIFFGetDirNumberFromOffset() ---*/
|
||||
+
|
||||
|
||||
/*
|
||||
* Check the count field of a directory entry against a known value. The
|
||||
diff --git a/libtiff/tif_open.c b/libtiff/tif_open.c
|
||||
index 549f56ce..85c2af47 100644
|
||||
--- a/libtiff/tif_open.c
|
||||
+++ b/libtiff/tif_open.c
|
||||
@@ -354,7 +354,8 @@ TIFFClientOpen(
|
||||
goto bad;
|
||||
tif->tif_diroff = 0;
|
||||
tif->tif_lastdiroff = 0;
|
||||
- tif->tif_dirlist = NULL;
|
||||
+ tif->tif_dirlistoff = NULL;
|
||||
+ tif->tif_dirlistdirn = NULL;
|
||||
tif->tif_dirlistsize = 0;
|
||||
tif->tif_dirnumber = 0;
|
||||
return (tif);
|
||||
diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h
|
||||
index 4e8bdac2..8e0e2454 100644
|
||||
--- a/libtiff/tiffiop.h
|
||||
+++ b/libtiff/tiffiop.h
|
||||
@@ -118,7 +118,8 @@ struct tiff {
|
||||
uint64_t tif_diroff; /* file offset of current directory */
|
||||
uint64_t tif_nextdiroff; /* file offset of following directory */
|
||||
uint64_t tif_lastdiroff; /* file offset of last directory written so far */
|
||||
- uint64_t* tif_dirlist; /* list of offsets to already seen directories to prevent IFD looping */
|
||||
+ uint64_t* tif_dirlistoff; /* list of offsets to already seen directories to prevent IFD looping */
|
||||
+ uint16_t* tif_dirlistdirn; /* list of directory numbers to already seen directories to prevent IFD looping */
|
||||
uint16_t tif_dirlistsize; /* number of entries in offset list */
|
||||
uint16_t tif_dirnumber; /* number of already seen directories */
|
||||
TIFFDirectory tif_dir; /* internal rep of current directory */
|
@ -0,0 +1,36 @@
|
||||
From 979173fc37955d27c9550beb6c7ed1f2466c6ff4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Matej=20Mu=C5=BEila?= <mmuzila@redhat.com>
|
||||
Date: Wed, 4 Oct 2023 13:13:08 +0200
|
||||
Subject: [PATCH] (CVE-2023-3618) tiffcrop: fix 553 by considering error return
|
||||
of writeSelections()
|
||||
|
||||
Closes #553
|
||||
|
||||
See merge request libtiff/libtiff!485
|
||||
|
||||
(cherry picked from commit 7ead6c42c70636c0ffec2e9ff3f16d614e37fb7b)
|
||||
---
|
||||
tools/tiffcrop.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/tools/tiffcrop.c b/tools/tiffcrop.c
|
||||
index be72ec52..edb33e25 100644
|
||||
--- a/tools/tiffcrop.c
|
||||
+++ b/tools/tiffcrop.c
|
||||
@@ -2464,8 +2464,14 @@ main(int argc, char* argv[])
|
||||
{ /* Whole image or sections not based on output page size */
|
||||
if (crop.selections > 0)
|
||||
{
|
||||
- writeSelections(in, &out, &crop, &image, &dump, seg_buffs,
|
||||
- mp, argv[argc - 1], &next_page, total_pages);
|
||||
+ if (writeSelections(in, &out, &crop, &image, &dump,
|
||||
+ seg_buffs, mp, argv[argc - 1],
|
||||
+ &next_page, total_pages))
|
||||
+ {
|
||||
+ TIFFError("main",
|
||||
+ "Unable to write new image selections");
|
||||
+ exit(EXIT_FAILURE);
|
||||
+ }
|
||||
}
|
||||
else /* One file all images and sections */
|
||||
{
|
@ -0,0 +1,67 @@
|
||||
From fffa3dc40d30155a17487ba3edacb320cb29b873 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Matej=20Mu=C5=BEila?= <mmuzila@redhat.com>
|
||||
Date: Wed, 4 Oct 2023 13:20:28 +0200
|
||||
Subject: [PATCH] (CVE-2023-40745 CVE-2023-41175) raw2tiff: fix integer
|
||||
overflow and bypass of the check (fixes #592)
|
||||
|
||||
See merge request libtiff/libtiff!516
|
||||
|
||||
(cherry picked from commit 6ac40fefa1763ad08c6e9654d10910e462426f82)
|
||||
---
|
||||
tools/raw2tiff.c | 29 +++++++++++++++++++++++++++++
|
||||
1 file changed, 29 insertions(+)
|
||||
|
||||
diff --git a/tools/raw2tiff.c b/tools/raw2tiff.c
|
||||
index 0c6001f7..747ede7f 100644
|
||||
--- a/tools/raw2tiff.c
|
||||
+++ b/tools/raw2tiff.c
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
+#include <limits.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
@@ -101,6 +102,7 @@ main(int argc, char* argv[])
|
||||
int fd;
|
||||
char *outfilename = NULL;
|
||||
TIFF *out;
|
||||
+ uint32_t temp_limit_check = 0; /* temp for integer overflow checking*/
|
||||
|
||||
uint32_t row, col, band;
|
||||
int c;
|
||||
@@ -217,6 +219,33 @@ main(int argc, char* argv[])
|
||||
if (guessSize(fd, dtype, hdr_size, nbands, swab, &width, &length) < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
+ /* check for integer overflow in */
|
||||
+ /* hdr_size + (*width) * (*length) * nbands * depth */
|
||||
+
|
||||
+ if ((width == 0) || (length == 0) ){
|
||||
+ fprintf(stderr, "Too large nbands value specified.\n");
|
||||
+ return (EXIT_FAILURE);
|
||||
+ }
|
||||
+
|
||||
+ temp_limit_check = nbands * depth;
|
||||
+
|
||||
+ if ( !temp_limit_check || length > ( UINT_MAX / temp_limit_check ) ) {
|
||||
+ fprintf(stderr, "Too large length size specified.\n");
|
||||
+ return (EXIT_FAILURE);
|
||||
+ }
|
||||
+ temp_limit_check = temp_limit_check * length;
|
||||
+
|
||||
+ if ( !temp_limit_check || width > ( UINT_MAX / temp_limit_check ) ) {
|
||||
+ fprintf(stderr, "Too large width size specified.\n");
|
||||
+ return (EXIT_FAILURE);
|
||||
+ }
|
||||
+ temp_limit_check = temp_limit_check * width;
|
||||
+
|
||||
+ if ( !temp_limit_check || hdr_size > ( UINT_MAX - temp_limit_check ) ) {
|
||||
+ fprintf(stderr, "Too large header size specified.\n");
|
||||
+ return (EXIT_FAILURE);
|
||||
+ }
|
||||
+
|
||||
if (outfilename == NULL)
|
||||
outfilename = argv[optind+1];
|
||||
out = TIFFOpen(outfilename, "w");
|
@ -0,0 +1,30 @@
|
||||
From b57347d203cf577a3abb02cb62aee84b82903fcf Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Matej=20Mu=C5=BEila?= <mmuzila@redhat.com>
|
||||
Date: Thu, 23 Nov 2023 11:05:35 +0100
|
||||
Subject: [PATCH] (CVE-2023-6228) Merge branch
|
||||
'fix_606_tiffcp_check_also_input_compression_codec' into 'master'
|
||||
|
||||
tiffcp: Fixes #606. Check also codec of input image, not only from output image.
|
||||
|
||||
Closes #606
|
||||
|
||||
See merge request libtiff/libtiff!533
|
||||
|
||||
(cherry picked from commit 668d2c1a52fa48658bbf69615924b42b5a059f9e)
|
||||
---
|
||||
tools/tiffcp.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/tools/tiffcp.c b/tools/tiffcp.c
|
||||
index 07ed0ebc..9973dd4e 100644
|
||||
--- a/tools/tiffcp.c
|
||||
+++ b/tools/tiffcp.c
|
||||
@@ -732,6 +732,8 @@ tiffcp(TIFF* in, TIFF* out)
|
||||
if( !TIFFIsCODECConfigured(compression) )
|
||||
return FALSE;
|
||||
TIFFGetFieldDefaulted(in, TIFFTAG_COMPRESSION, &input_compression);
|
||||
+ if (!TIFFIsCODECConfigured(input_compression))
|
||||
+ return FALSE;
|
||||
TIFFGetFieldDefaulted(in, TIFFTAG_PHOTOMETRIC, &input_photometric);
|
||||
if (input_compression == COMPRESSION_JPEG) {
|
||||
/* Force conversion to RGB */
|
@ -1,7 +1,7 @@
|
||||
Summary: Library of functions for manipulating TIFF format image files
|
||||
Name: libtiff
|
||||
Version: 4.4.0
|
||||
Release: 10%{?dist}
|
||||
Release: 12%{?dist}
|
||||
License: libtiff
|
||||
URL: http://www.simplesystems.org/libtiff/
|
||||
|
||||
@ -31,8 +31,10 @@ Patch0015: 0015-CVE-2023-26965-tiffcrop-Do-not-reuse-input-buffer-fo.patch
|
||||
Patch0016: 0016-CVE-2023-3316-TIFFClose-avoid-NULL-pointer-dereferen.patch
|
||||
Patch0017: 0017-CVE-2023-26966-tif_luv-Check-and-correct-for-NaN-dat.patch
|
||||
Patch0018: 0018-CVE-2023-3576-Fix-memory-leak-in-tiffcrop.c.patch
|
||||
|
||||
|
||||
Patch0019: 0019-CVE-2023-40090-Improved-IFD-Loop-Handling-fixes-455.patch
|
||||
Patch0020: 0020-CVE-2023-3618-tiffcrop-fix-553-by-considering-error-.patch
|
||||
Patch0021: 0021-CVE-2023-40745-CVE-2023-41175-raw2tiff-fix-integer-o.patch
|
||||
Patch0022: 0022-CVE-2023-6228-Merge-branch-fix_606_tiffcp_check_also.patch
|
||||
|
||||
BuildRequires: gcc, gcc-c++
|
||||
BuildRequires: zlib-devel libjpeg-devel jbigkit-devel libzstd-devel libwebp-devel
|
||||
@ -185,6 +187,14 @@ find html -name 'Makefile*' | xargs rm
|
||||
%{_mandir}/man1/*
|
||||
|
||||
%changelog
|
||||
* Thu Nov 23 2023 Matej Mužila <mmuzila@redhat.com> - 4.4.0-12
|
||||
- Fix CVE-2023-6228
|
||||
- Resolves: RHEL-10084
|
||||
|
||||
* Wed Oct 04 2023 Matej Mužila <mmuzila@redhat.com> - 4.4.0-11
|
||||
- Fix CVE-2023-40090 CVE-2023-3618 CVE-2023-40745 CVE-2023-41175
|
||||
- Resolves: RHEL-5458 RHEL-5455 RHEL-5405 RHEL-5450
|
||||
|
||||
* Tue Aug 08 2023 Matej Mužila <mmuzila@redhat.com> - 4.4.0-10
|
||||
- Fix CVE-2023-26965 CVE-2023-3316 CVE-2023-26966 CVE-2023-3576
|
||||
- Resolves: CVE-2023-26965 CVE-2023-3316 CVE-2023-26966 CVE-2023-3576
|
||||
|
Loading…
Reference in New Issue
Block a user