211 lines
7.8 KiB
Diff
211 lines
7.8 KiB
Diff
From 281fa3cf0e0e8a44b93478c63d90dbfb64359e88 Mon Sep 17 00:00:00 2001
|
|
From: Even Rouault <even.rouault@spatialys.com>
|
|
Date: Sun, 5 Dec 2021 14:37:46 +0100
|
|
Subject: [PATCH] TIFFReadDirectory: fix OJPEG hack (fixes #319)
|
|
|
|
to avoid having the size of the strip arrays inconsistent with the
|
|
number of strips returned by TIFFNumberOfStrips(), which may cause
|
|
out-ouf-bounds array read afterwards.
|
|
|
|
One of the OJPEG hack that alters SamplesPerPixel may influence the
|
|
number of strips. Hence compute tif_dir.td_nstrips only afterwards.
|
|
|
|
CVE: CVE-2022-1354
|
|
|
|
Upstream-Status: Backport
|
|
[https://gitlab.com/libtiff/libtiff/-/commit/87f580f39011109b3bb5f6eca13fac543a542798]
|
|
|
|
Signed-off-by: Yi Zhao <yi.zhao@windriver.com>
|
|
|
|
---
|
|
libtiff/tif_dirread.c | 162 ++++++++++++++++++++++--------------------
|
|
1 file changed, 83 insertions(+), 79 deletions(-)
|
|
|
|
diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c
|
|
index a31109a..d7cccbe 100644
|
|
--- a/libtiff/tif_dirread.c
|
|
+++ b/libtiff/tif_dirread.c
|
|
@@ -3794,50 +3794,7 @@ TIFFReadDirectory(TIFF* tif)
|
|
MissingRequired(tif,"ImageLength");
|
|
goto bad;
|
|
}
|
|
- /*
|
|
- * Setup appropriate structures (by strip or by tile)
|
|
- */
|
|
- if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
|
|
- tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif);
|
|
- tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth;
|
|
- tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip;
|
|
- tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth;
|
|
- tif->tif_flags &= ~TIFF_ISTILED;
|
|
- } else {
|
|
- tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif);
|
|
- tif->tif_flags |= TIFF_ISTILED;
|
|
- }
|
|
- if (!tif->tif_dir.td_nstrips) {
|
|
- TIFFErrorExt(tif->tif_clientdata, module,
|
|
- "Cannot handle zero number of %s",
|
|
- isTiled(tif) ? "tiles" : "strips");
|
|
- goto bad;
|
|
- }
|
|
- tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips;
|
|
- if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE)
|
|
- tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel;
|
|
- if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
|
|
-#ifdef OJPEG_SUPPORT
|
|
- if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) &&
|
|
- (isTiled(tif)==0) &&
|
|
- (tif->tif_dir.td_nstrips==1)) {
|
|
- /*
|
|
- * XXX: OJPEG hack.
|
|
- * If a) compression is OJPEG, b) it's not a tiled TIFF,
|
|
- * and c) the number of strips is 1,
|
|
- * then we tolerate the absence of stripoffsets tag,
|
|
- * because, presumably, all required data is in the
|
|
- * JpegInterchangeFormat stream.
|
|
- */
|
|
- TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
|
|
- } else
|
|
-#endif
|
|
- {
|
|
- MissingRequired(tif,
|
|
- isTiled(tif) ? "TileOffsets" : "StripOffsets");
|
|
- goto bad;
|
|
- }
|
|
- }
|
|
+
|
|
/*
|
|
* Second pass: extract other information.
|
|
*/
|
|
@@ -4042,41 +3999,6 @@ TIFFReadDirectory(TIFF* tif)
|
|
} /* -- if (!dp->tdir_ignore) */
|
|
} /* -- for-loop -- */
|
|
|
|
- if( tif->tif_mode == O_RDWR &&
|
|
- tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 &&
|
|
- tif->tif_dir.td_stripoffset_entry.tdir_count == 0 &&
|
|
- tif->tif_dir.td_stripoffset_entry.tdir_type == 0 &&
|
|
- tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 &&
|
|
- tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 &&
|
|
- tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 &&
|
|
- tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 &&
|
|
- tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 )
|
|
- {
|
|
- /* Directory typically created with TIFFDeferStrileArrayWriting() */
|
|
- TIFFSetupStrips(tif);
|
|
- }
|
|
- else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) )
|
|
- {
|
|
- if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 )
|
|
- {
|
|
- if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry),
|
|
- tif->tif_dir.td_nstrips,
|
|
- &tif->tif_dir.td_stripoffset_p))
|
|
- {
|
|
- goto bad;
|
|
- }
|
|
- }
|
|
- if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 )
|
|
- {
|
|
- if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry),
|
|
- tif->tif_dir.td_nstrips,
|
|
- &tif->tif_dir.td_stripbytecount_p))
|
|
- {
|
|
- goto bad;
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
/*
|
|
* OJPEG hack:
|
|
* - If a) compression is OJPEG, and b) photometric tag is missing,
|
|
@@ -4147,6 +4069,88 @@ TIFFReadDirectory(TIFF* tif)
|
|
}
|
|
}
|
|
|
|
+ /*
|
|
+ * Setup appropriate structures (by strip or by tile)
|
|
+ * We do that only after the above OJPEG hack which alters SamplesPerPixel
|
|
+ * and thus influences the number of strips in the separate planarconfig.
|
|
+ */
|
|
+ if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
|
|
+ tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif);
|
|
+ tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth;
|
|
+ tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip;
|
|
+ tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth;
|
|
+ tif->tif_flags &= ~TIFF_ISTILED;
|
|
+ } else {
|
|
+ tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif);
|
|
+ tif->tif_flags |= TIFF_ISTILED;
|
|
+ }
|
|
+ if (!tif->tif_dir.td_nstrips) {
|
|
+ TIFFErrorExt(tif->tif_clientdata, module,
|
|
+ "Cannot handle zero number of %s",
|
|
+ isTiled(tif) ? "tiles" : "strips");
|
|
+ goto bad;
|
|
+ }
|
|
+ tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips;
|
|
+ if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE)
|
|
+ tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel;
|
|
+ if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
|
|
+#ifdef OJPEG_SUPPORT
|
|
+ if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) &&
|
|
+ (isTiled(tif)==0) &&
|
|
+ (tif->tif_dir.td_nstrips==1)) {
|
|
+ /*
|
|
+ * XXX: OJPEG hack.
|
|
+ * If a) compression is OJPEG, b) it's not a tiled TIFF,
|
|
+ * and c) the number of strips is 1,
|
|
+ * then we tolerate the absence of stripoffsets tag,
|
|
+ * because, presumably, all required data is in the
|
|
+ * JpegInterchangeFormat stream.
|
|
+ */
|
|
+ TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
|
|
+ } else
|
|
+#endif
|
|
+ {
|
|
+ MissingRequired(tif,
|
|
+ isTiled(tif) ? "TileOffsets" : "StripOffsets");
|
|
+ goto bad;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( tif->tif_mode == O_RDWR &&
|
|
+ tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 &&
|
|
+ tif->tif_dir.td_stripoffset_entry.tdir_count == 0 &&
|
|
+ tif->tif_dir.td_stripoffset_entry.tdir_type == 0 &&
|
|
+ tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 &&
|
|
+ tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 &&
|
|
+ tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 &&
|
|
+ tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 &&
|
|
+ tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 )
|
|
+ {
|
|
+ /* Directory typically created with TIFFDeferStrileArrayWriting() */
|
|
+ TIFFSetupStrips(tif);
|
|
+ }
|
|
+ else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) )
|
|
+ {
|
|
+ if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 )
|
|
+ {
|
|
+ if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry),
|
|
+ tif->tif_dir.td_nstrips,
|
|
+ &tif->tif_dir.td_stripoffset_p))
|
|
+ {
|
|
+ goto bad;
|
|
+ }
|
|
+ }
|
|
+ if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 )
|
|
+ {
|
|
+ if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry),
|
|
+ tif->tif_dir.td_nstrips,
|
|
+ &tif->tif_dir.td_stripbytecount_p))
|
|
+ {
|
|
+ goto bad;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
/*
|
|
* Make sure all non-color channels are extrasamples.
|
|
* If it's not the case, define them as such.
|