Blame SOURCES/0004-CVE-2018-7456-Fix-NULL-pointer-dereference-in-TIFFPr.patch

12208d
From 688dc47dfcbbc4e54dc617c9701cf46a03f8e069 Mon Sep 17 00:00:00 2001
12208d
From: Hugo Lefeuvre <hle@debian.org>
12208d
Date: Sun, 8 Apr 2018 14:07:08 -0400
12208d
Subject: [PATCH] (CVE-2018-7456) Fix NULL pointer dereference in
12208d
 TIFFPrintDirectory
21ff78
21ff78
The TIFFPrintDirectory function relies on the following assumptions,
21ff78
supposed to be guaranteed by the specification:
21ff78
21ff78
(a) A Transfer Function field is only present if the TIFF file has
21ff78
    photometric type < 3.
21ff78
21ff78
(b) If SamplesPerPixel > Color Channels, then the ExtraSamples field
21ff78
    has count SamplesPerPixel - (Color Channels) and contains
21ff78
    information about supplementary channels.
21ff78
21ff78
While respect of (a) and (b) are essential for the well functioning of
21ff78
TIFFPrintDirectory, no checks are realized neither by the callee nor
21ff78
by TIFFPrintDirectory itself. Hence, following scenarios might happen
21ff78
and trigger the NULL pointer dereference:
21ff78
21ff78
(1) TIFF File of photometric type 4 or more has illegal Transfer
21ff78
    Function field.
21ff78
21ff78
(2) TIFF File has photometric type 3 or less and defines a
21ff78
    SamplesPerPixel field such that SamplesPerPixel > Color Channels
21ff78
    without defining all extra samples in the ExtraSamples fields.
21ff78
21ff78
In this patch, we address both issues with respect of the following
21ff78
principles:
21ff78
21ff78
(A) In the case of (1), the defined transfer table should be printed
21ff78
    safely even if it isn't 'legal'. This allows us to avoid expensive
21ff78
    checks in TIFFPrintDirectory. Also, it is quite possible that
21ff78
    an alternative photometric type would be developed (not part of the
21ff78
    standard) and would allow definition of Transfer Table. We want
21ff78
    libtiff to be able to handle this scenario out of the box.
21ff78
21ff78
(B) In the case of (2), the transfer table should be printed at its
21ff78
    right size, that is if TIFF file has photometric type Palette
21ff78
    then the transfer table should have one row and not three, even
21ff78
    if two extra samples are declared.
21ff78
21ff78
In order to fulfill (A) we simply add a new 'i < 3' end condition to
21ff78
the broken TIFFPrintDirectory loop. This makes sure that in any case
21ff78
where (b) would be respected but not (a), everything stays fine.
21ff78
21ff78
(B) is fulfilled by the loop condition
21ff78
'i < td->td_samplesperpixel - td->td_extrasamples'. This is enough as
21ff78
long as (b) is respected.
21ff78
21ff78
Naturally, we also make sure (b) is respected. This is done in the
21ff78
TIFFReadDirectory function by making sure any non-color channel is
21ff78
counted in ExtraSamples.
21ff78
21ff78
This commit addresses CVE-2018-7456.
12208d
12208d
(cherry picked from commit be4c85b16e8801a16eec25e80eb9f3dd6a96731b)
21ff78
---
21ff78
 libtiff/tif_dirread.c | 62 +++++++++++++++++++++++++++++++++++++++++++
21ff78
 libtiff/tif_print.c   |  2 +-
21ff78
 2 files changed, 63 insertions(+), 1 deletion(-)
21ff78
21ff78
diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c
12208d
index 5e62e813..80aaf8d1 100644
21ff78
--- a/libtiff/tif_dirread.c
21ff78
+++ b/libtiff/tif_dirread.c
21ff78
@@ -167,6 +167,7 @@ static int TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, uint32 nstrips, uin
21ff78
 static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*);
21ff78
 static void ChopUpSingleUncompressedStrip(TIFF*);
21ff78
 static uint64 TIFFReadUInt64(const uint8 *value);
21ff78
+static int _TIFFGetMaxColorChannels(uint16 photometric);
21ff78
 
21ff78
 static int _TIFFFillStrilesInternal( TIFF *tif, int loadStripByteCount );
21ff78
 
21ff78
@@ -3506,6 +3507,35 @@ static void TIFFReadDirEntryOutputErr(TIFF* tif, enum TIFFReadDirEntryErr err, c
21ff78
 	}
21ff78
 }
21ff78
 
21ff78
+/*
21ff78
+ * Return the maximum number of color channels specified for a given photometric
21ff78
+ * type. 0 is returned if photometric type isn't supported or no default value
21ff78
+ * is defined by the specification.
21ff78
+ */
21ff78
+static int _TIFFGetMaxColorChannels( uint16 photometric )
21ff78
+{
21ff78
+    switch (photometric) {
21ff78
+	case PHOTOMETRIC_PALETTE:
21ff78
+	case PHOTOMETRIC_MINISWHITE:
21ff78
+	case PHOTOMETRIC_MINISBLACK:
21ff78
+            return 1;
21ff78
+	case PHOTOMETRIC_YCBCR:
21ff78
+	case PHOTOMETRIC_RGB:
21ff78
+	case PHOTOMETRIC_CIELAB:
21ff78
+            return 3;
21ff78
+	case PHOTOMETRIC_SEPARATED:
21ff78
+	case PHOTOMETRIC_MASK:
21ff78
+            return 4;
21ff78
+	case PHOTOMETRIC_LOGL:
21ff78
+	case PHOTOMETRIC_LOGLUV:
21ff78
+	case PHOTOMETRIC_CFA:
21ff78
+	case PHOTOMETRIC_ITULAB:
21ff78
+	case PHOTOMETRIC_ICCLAB:
21ff78
+	default:
21ff78
+            return 0;
21ff78
+    }
21ff78
+}
21ff78
+
21ff78
 /*
21ff78
  * Read the next TIFF directory from a file and convert it to the internal
21ff78
  * format. We read directories sequentially.
21ff78
@@ -3522,6 +3552,7 @@ TIFFReadDirectory(TIFF* tif)
21ff78
 	uint32 fii=FAILED_FII;
21ff78
         toff_t nextdiroff;
21ff78
     int bitspersample_read = FALSE;
21ff78
+        int color_channels;
21ff78
 
21ff78
 	tif->tif_diroff=tif->tif_nextdiroff;
21ff78
 	if (!TIFFCheckDirOffset(tif,tif->tif_nextdiroff))
21ff78
@@ -4026,6 +4057,37 @@ TIFFReadDirectory(TIFF* tif)
21ff78
 			}
21ff78
 		}
21ff78
 	}
21ff78
+
21ff78
+	/*
21ff78
+	 * Make sure all non-color channels are extrasamples.
21ff78
+	 * If it's not the case, define them as such.
21ff78
+	 */
21ff78
+        color_channels = _TIFFGetMaxColorChannels(tif->tif_dir.td_photometric);
21ff78
+        if (color_channels && tif->tif_dir.td_samplesperpixel - tif->tif_dir.td_extrasamples > color_channels) {
21ff78
+                uint16 old_extrasamples;
21ff78
+                uint16 *new_sampleinfo;
21ff78
+
21ff78
+                TIFFWarningExt(tif->tif_clientdata,module, "Sum of Photometric type-related "
21ff78
+                    "color channels and ExtraSamples doesn't match SamplesPerPixel. "
21ff78
+                    "Defining non-color channels as ExtraSamples.");
21ff78
+
21ff78
+                old_extrasamples = tif->tif_dir.td_extrasamples;
21ff78
+                tif->tif_dir.td_extrasamples = (tif->tif_dir.td_samplesperpixel - color_channels);
21ff78
+
21ff78
+                // sampleinfo should contain information relative to these new extra samples
21ff78
+                new_sampleinfo = (uint16*) _TIFFcalloc(tif->tif_dir.td_extrasamples, sizeof(uint16));
21ff78
+                if (!new_sampleinfo) {
21ff78
+                    TIFFErrorExt(tif->tif_clientdata, module, "Failed to allocate memory for "
21ff78
+                                "temporary new sampleinfo array (%d 16 bit elements)",
21ff78
+                                tif->tif_dir.td_extrasamples);
21ff78
+                    goto bad;
21ff78
+                }
21ff78
+
21ff78
+                memcpy(new_sampleinfo, tif->tif_dir.td_sampleinfo, old_extrasamples * sizeof(uint16));
21ff78
+                _TIFFsetShortArray(&tif->tif_dir.td_sampleinfo, new_sampleinfo, tif->tif_dir.td_extrasamples);
21ff78
+                _TIFFfree(new_sampleinfo);
21ff78
+        }
21ff78
+
21ff78
 	/*
21ff78
 	 * Verify Palette image has a Colormap.
21ff78
 	 */
21ff78
diff --git a/libtiff/tif_print.c b/libtiff/tif_print.c
12208d
index 24d4b98a..10a588ea 100644
21ff78
--- a/libtiff/tif_print.c
21ff78
+++ b/libtiff/tif_print.c
21ff78
@@ -546,7 +546,7 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags)
21ff78
 				uint16 i;
21ff78
 				fprintf(fd, "    %2ld: %5u",
21ff78
 				    l, td->td_transferfunction[0][l]);
21ff78
-				for (i = 1; i < td->td_samplesperpixel; i++)
21ff78
+				for (i = 1; i < td->td_samplesperpixel - td->td_extrasamples && i < 3; i++)
21ff78
 					fprintf(fd, " %5u",
21ff78
 					    td->td_transferfunction[i][l]);
21ff78
 				fputc('\n', fd);