1*4882a593SmuzhiyunFrom 281fa3cf0e0e8a44b93478c63d90dbfb64359e88 Mon Sep 17 00:00:00 2001 2*4882a593SmuzhiyunFrom: Even Rouault <even.rouault@spatialys.com> 3*4882a593SmuzhiyunDate: Sun, 5 Dec 2021 14:37:46 +0100 4*4882a593SmuzhiyunSubject: [PATCH] TIFFReadDirectory: fix OJPEG hack (fixes #319) 5*4882a593Smuzhiyun 6*4882a593Smuzhiyunto avoid having the size of the strip arrays inconsistent with the 7*4882a593Smuzhiyunnumber of strips returned by TIFFNumberOfStrips(), which may cause 8*4882a593Smuzhiyunout-ouf-bounds array read afterwards. 9*4882a593Smuzhiyun 10*4882a593SmuzhiyunOne of the OJPEG hack that alters SamplesPerPixel may influence the 11*4882a593Smuzhiyunnumber of strips. Hence compute tif_dir.td_nstrips only afterwards. 12*4882a593Smuzhiyun 13*4882a593SmuzhiyunCVE: CVE-2022-1354 14*4882a593Smuzhiyun 15*4882a593SmuzhiyunUpstream-Status: Backport 16*4882a593Smuzhiyun[https://gitlab.com/libtiff/libtiff/-/commit/87f580f39011109b3bb5f6eca13fac543a542798] 17*4882a593Smuzhiyun 18*4882a593SmuzhiyunSigned-off-by: Yi Zhao <yi.zhao@windriver.com> 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun--- 21*4882a593Smuzhiyun libtiff/tif_dirread.c | 162 ++++++++++++++++++++++-------------------- 22*4882a593Smuzhiyun 1 file changed, 83 insertions(+), 79 deletions(-) 23*4882a593Smuzhiyun 24*4882a593Smuzhiyundiff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c 25*4882a593Smuzhiyunindex a31109a..d7cccbe 100644 26*4882a593Smuzhiyun--- a/libtiff/tif_dirread.c 27*4882a593Smuzhiyun+++ b/libtiff/tif_dirread.c 28*4882a593Smuzhiyun@@ -3794,50 +3794,7 @@ TIFFReadDirectory(TIFF* tif) 29*4882a593Smuzhiyun MissingRequired(tif,"ImageLength"); 30*4882a593Smuzhiyun goto bad; 31*4882a593Smuzhiyun } 32*4882a593Smuzhiyun- /* 33*4882a593Smuzhiyun- * Setup appropriate structures (by strip or by tile) 34*4882a593Smuzhiyun- */ 35*4882a593Smuzhiyun- if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { 36*4882a593Smuzhiyun- tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif); 37*4882a593Smuzhiyun- tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth; 38*4882a593Smuzhiyun- tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip; 39*4882a593Smuzhiyun- tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth; 40*4882a593Smuzhiyun- tif->tif_flags &= ~TIFF_ISTILED; 41*4882a593Smuzhiyun- } else { 42*4882a593Smuzhiyun- tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif); 43*4882a593Smuzhiyun- tif->tif_flags |= TIFF_ISTILED; 44*4882a593Smuzhiyun- } 45*4882a593Smuzhiyun- if (!tif->tif_dir.td_nstrips) { 46*4882a593Smuzhiyun- TIFFErrorExt(tif->tif_clientdata, module, 47*4882a593Smuzhiyun- "Cannot handle zero number of %s", 48*4882a593Smuzhiyun- isTiled(tif) ? "tiles" : "strips"); 49*4882a593Smuzhiyun- goto bad; 50*4882a593Smuzhiyun- } 51*4882a593Smuzhiyun- tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips; 52*4882a593Smuzhiyun- if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE) 53*4882a593Smuzhiyun- tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel; 54*4882a593Smuzhiyun- if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) { 55*4882a593Smuzhiyun-#ifdef OJPEG_SUPPORT 56*4882a593Smuzhiyun- if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) && 57*4882a593Smuzhiyun- (isTiled(tif)==0) && 58*4882a593Smuzhiyun- (tif->tif_dir.td_nstrips==1)) { 59*4882a593Smuzhiyun- /* 60*4882a593Smuzhiyun- * XXX: OJPEG hack. 61*4882a593Smuzhiyun- * If a) compression is OJPEG, b) it's not a tiled TIFF, 62*4882a593Smuzhiyun- * and c) the number of strips is 1, 63*4882a593Smuzhiyun- * then we tolerate the absence of stripoffsets tag, 64*4882a593Smuzhiyun- * because, presumably, all required data is in the 65*4882a593Smuzhiyun- * JpegInterchangeFormat stream. 66*4882a593Smuzhiyun- */ 67*4882a593Smuzhiyun- TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); 68*4882a593Smuzhiyun- } else 69*4882a593Smuzhiyun-#endif 70*4882a593Smuzhiyun- { 71*4882a593Smuzhiyun- MissingRequired(tif, 72*4882a593Smuzhiyun- isTiled(tif) ? "TileOffsets" : "StripOffsets"); 73*4882a593Smuzhiyun- goto bad; 74*4882a593Smuzhiyun- } 75*4882a593Smuzhiyun- } 76*4882a593Smuzhiyun+ 77*4882a593Smuzhiyun /* 78*4882a593Smuzhiyun * Second pass: extract other information. 79*4882a593Smuzhiyun */ 80*4882a593Smuzhiyun@@ -4042,41 +3999,6 @@ TIFFReadDirectory(TIFF* tif) 81*4882a593Smuzhiyun } /* -- if (!dp->tdir_ignore) */ 82*4882a593Smuzhiyun } /* -- for-loop -- */ 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun- if( tif->tif_mode == O_RDWR && 85*4882a593Smuzhiyun- tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 && 86*4882a593Smuzhiyun- tif->tif_dir.td_stripoffset_entry.tdir_count == 0 && 87*4882a593Smuzhiyun- tif->tif_dir.td_stripoffset_entry.tdir_type == 0 && 88*4882a593Smuzhiyun- tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 && 89*4882a593Smuzhiyun- tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 && 90*4882a593Smuzhiyun- tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 && 91*4882a593Smuzhiyun- tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 && 92*4882a593Smuzhiyun- tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 ) 93*4882a593Smuzhiyun- { 94*4882a593Smuzhiyun- /* Directory typically created with TIFFDeferStrileArrayWriting() */ 95*4882a593Smuzhiyun- TIFFSetupStrips(tif); 96*4882a593Smuzhiyun- } 97*4882a593Smuzhiyun- else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) ) 98*4882a593Smuzhiyun- { 99*4882a593Smuzhiyun- if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 ) 100*4882a593Smuzhiyun- { 101*4882a593Smuzhiyun- if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry), 102*4882a593Smuzhiyun- tif->tif_dir.td_nstrips, 103*4882a593Smuzhiyun- &tif->tif_dir.td_stripoffset_p)) 104*4882a593Smuzhiyun- { 105*4882a593Smuzhiyun- goto bad; 106*4882a593Smuzhiyun- } 107*4882a593Smuzhiyun- } 108*4882a593Smuzhiyun- if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 ) 109*4882a593Smuzhiyun- { 110*4882a593Smuzhiyun- if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry), 111*4882a593Smuzhiyun- tif->tif_dir.td_nstrips, 112*4882a593Smuzhiyun- &tif->tif_dir.td_stripbytecount_p)) 113*4882a593Smuzhiyun- { 114*4882a593Smuzhiyun- goto bad; 115*4882a593Smuzhiyun- } 116*4882a593Smuzhiyun- } 117*4882a593Smuzhiyun- } 118*4882a593Smuzhiyun- 119*4882a593Smuzhiyun /* 120*4882a593Smuzhiyun * OJPEG hack: 121*4882a593Smuzhiyun * - If a) compression is OJPEG, and b) photometric tag is missing, 122*4882a593Smuzhiyun@@ -4147,6 +4069,88 @@ TIFFReadDirectory(TIFF* tif) 123*4882a593Smuzhiyun } 124*4882a593Smuzhiyun } 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun+ /* 127*4882a593Smuzhiyun+ * Setup appropriate structures (by strip or by tile) 128*4882a593Smuzhiyun+ * We do that only after the above OJPEG hack which alters SamplesPerPixel 129*4882a593Smuzhiyun+ * and thus influences the number of strips in the separate planarconfig. 130*4882a593Smuzhiyun+ */ 131*4882a593Smuzhiyun+ if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { 132*4882a593Smuzhiyun+ tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif); 133*4882a593Smuzhiyun+ tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth; 134*4882a593Smuzhiyun+ tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip; 135*4882a593Smuzhiyun+ tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth; 136*4882a593Smuzhiyun+ tif->tif_flags &= ~TIFF_ISTILED; 137*4882a593Smuzhiyun+ } else { 138*4882a593Smuzhiyun+ tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif); 139*4882a593Smuzhiyun+ tif->tif_flags |= TIFF_ISTILED; 140*4882a593Smuzhiyun+ } 141*4882a593Smuzhiyun+ if (!tif->tif_dir.td_nstrips) { 142*4882a593Smuzhiyun+ TIFFErrorExt(tif->tif_clientdata, module, 143*4882a593Smuzhiyun+ "Cannot handle zero number of %s", 144*4882a593Smuzhiyun+ isTiled(tif) ? "tiles" : "strips"); 145*4882a593Smuzhiyun+ goto bad; 146*4882a593Smuzhiyun+ } 147*4882a593Smuzhiyun+ tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips; 148*4882a593Smuzhiyun+ if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE) 149*4882a593Smuzhiyun+ tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel; 150*4882a593Smuzhiyun+ if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) { 151*4882a593Smuzhiyun+#ifdef OJPEG_SUPPORT 152*4882a593Smuzhiyun+ if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) && 153*4882a593Smuzhiyun+ (isTiled(tif)==0) && 154*4882a593Smuzhiyun+ (tif->tif_dir.td_nstrips==1)) { 155*4882a593Smuzhiyun+ /* 156*4882a593Smuzhiyun+ * XXX: OJPEG hack. 157*4882a593Smuzhiyun+ * If a) compression is OJPEG, b) it's not a tiled TIFF, 158*4882a593Smuzhiyun+ * and c) the number of strips is 1, 159*4882a593Smuzhiyun+ * then we tolerate the absence of stripoffsets tag, 160*4882a593Smuzhiyun+ * because, presumably, all required data is in the 161*4882a593Smuzhiyun+ * JpegInterchangeFormat stream. 162*4882a593Smuzhiyun+ */ 163*4882a593Smuzhiyun+ TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); 164*4882a593Smuzhiyun+ } else 165*4882a593Smuzhiyun+#endif 166*4882a593Smuzhiyun+ { 167*4882a593Smuzhiyun+ MissingRequired(tif, 168*4882a593Smuzhiyun+ isTiled(tif) ? "TileOffsets" : "StripOffsets"); 169*4882a593Smuzhiyun+ goto bad; 170*4882a593Smuzhiyun+ } 171*4882a593Smuzhiyun+ } 172*4882a593Smuzhiyun+ 173*4882a593Smuzhiyun+ if( tif->tif_mode == O_RDWR && 174*4882a593Smuzhiyun+ tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 && 175*4882a593Smuzhiyun+ tif->tif_dir.td_stripoffset_entry.tdir_count == 0 && 176*4882a593Smuzhiyun+ tif->tif_dir.td_stripoffset_entry.tdir_type == 0 && 177*4882a593Smuzhiyun+ tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 && 178*4882a593Smuzhiyun+ tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 && 179*4882a593Smuzhiyun+ tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 && 180*4882a593Smuzhiyun+ tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 && 181*4882a593Smuzhiyun+ tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 ) 182*4882a593Smuzhiyun+ { 183*4882a593Smuzhiyun+ /* Directory typically created with TIFFDeferStrileArrayWriting() */ 184*4882a593Smuzhiyun+ TIFFSetupStrips(tif); 185*4882a593Smuzhiyun+ } 186*4882a593Smuzhiyun+ else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) ) 187*4882a593Smuzhiyun+ { 188*4882a593Smuzhiyun+ if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 ) 189*4882a593Smuzhiyun+ { 190*4882a593Smuzhiyun+ if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry), 191*4882a593Smuzhiyun+ tif->tif_dir.td_nstrips, 192*4882a593Smuzhiyun+ &tif->tif_dir.td_stripoffset_p)) 193*4882a593Smuzhiyun+ { 194*4882a593Smuzhiyun+ goto bad; 195*4882a593Smuzhiyun+ } 196*4882a593Smuzhiyun+ } 197*4882a593Smuzhiyun+ if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 ) 198*4882a593Smuzhiyun+ { 199*4882a593Smuzhiyun+ if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry), 200*4882a593Smuzhiyun+ tif->tif_dir.td_nstrips, 201*4882a593Smuzhiyun+ &tif->tif_dir.td_stripbytecount_p)) 202*4882a593Smuzhiyun+ { 203*4882a593Smuzhiyun+ goto bad; 204*4882a593Smuzhiyun+ } 205*4882a593Smuzhiyun+ } 206*4882a593Smuzhiyun+ } 207*4882a593Smuzhiyun+ 208*4882a593Smuzhiyun /* 209*4882a593Smuzhiyun * Make sure all non-color channels are extrasamples. 210*4882a593Smuzhiyun * If it's not the case, define them as such. 211