Upgrade libtiff from 4.6.0 to 4.7.0 Also empty out the entries in third_party/libtiff/METADATA, since 4.7.0 has fixes for all of them. Change-Id: Ic2de828554cbb785aa59243e31ccbe4f43085339 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/125130 Commit-Queue: Lei Zhang <thestig@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org> Reviewed-by: Tom Sepez <tsepez@google.com>
diff --git a/third_party/libtiff/0000-build-config.patch b/third_party/libtiff/0000-build-config.patch index c3925b0..4312834 100644 --- a/third_party/libtiff/0000-build-config.patch +++ b/third_party/libtiff/0000-build-config.patch
@@ -35,7 +35,7 @@ diff a/third_party/libtiff/tiffconf.h b/third_party/libtiff/tiffconf.h --- /dev/null +++ b/third_party/libtiff/tiffconf.h -@@ -0,0 +1,244 @@ +@@ -0,0 +1,240 @@ +/* libtiff/tiffconf.h. Generated by configure. */ +/* + Configuration defines for installed libtiff. @@ -211,11 +211,7 @@ + +/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian + (Intel) */ -+#if _FX_ENDIAN_ == _FX_BIG_ENDIAN_ -+# define HOST_BIGENDIAN 1 -+#else -+# define HOST_BIGENDIAN 0 -+#endif ++#define HOST_BIGENDIAN 0 + +/* Support CCITT Group 3 & 4 algorithms */ +#define CCITT_SUPPORT 1 @@ -249,7 +245,7 @@ +/* #undef ZIP_SUPPORT */ + +/* Support strip chopping (whether or not to convert single-strip uncompressed -+ images to mutiple strips of ~8Kb to reduce memory usage) */ ++ images to multiple strips of ~8Kb to reduce memory usage) */ +#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP + +/* Enable SubIFD tag (330) support */
diff --git a/third_party/libtiff/METADATA b/third_party/libtiff/METADATA index 6cbd8cf..7b31b74 100644 --- a/third_party/libtiff/METADATA +++ b/third_party/libtiff/METADATA
@@ -6,18 +6,5 @@ third_party { security { - # PDFium's copy of libtiff does not ship tools like tiffcrop. - mitigated_security_patch: "CVE-2022-48281" - mitigated_security_patch: "CVE-2023-1916" - mitigated_security_patch: "CVE-2023-3164" - mitigated_security_patch: "CVE-2023-25433" - mitigated_security_patch: "CVE-2023-25434" - mitigated_security_patch: "CVE-2023-25435" - mitigated_security_patch: "CVE-2023-26965" - mitigated_security_patch: "CVE-2023-40745" - mitigated_security_patch: "CVE-2023-41175" - - # There are no callers to TIFFRasterScanlineSize() in PDFium's code base. - mitigated_security_patch: "CVE-2023-52355" } }
diff --git a/third_party/libtiff/README.pdfium b/third_party/libtiff/README.pdfium index fc60596..cfe60c6 100644 --- a/third_party/libtiff/README.pdfium +++ b/third_party/libtiff/README.pdfium
@@ -1,7 +1,7 @@ Name: LibTIFF URL: http://www.simplesystems.org/libtiff/ -Version: 4.6.0 -CPEPrefix: cpe:/a:libtiff:libtiff:4.6.0 +Version: 4.7.0 +CPEPrefix: cpe:/a:libtiff:libtiff:4.7.0 Security Critical: yes Shipped: yes License: BSD
diff --git a/third_party/libtiff/tif_aux.c b/third_party/libtiff/tif_aux.c index 49855bb..e9606a4 100644 --- a/third_party/libtiff/tif_aux.c +++ b/third_party/libtiff/tif_aux.c
@@ -385,53 +385,6 @@ return (ok); } -struct _Int64Parts -{ - int32_t low, high; -}; - -typedef union -{ - struct _Int64Parts part; - int64_t value; -} _Int64; - -float _TIFFUInt64ToFloat(uint64_t ui64) -{ - _Int64 i; - - i.value = ui64; - if (i.part.high >= 0) - { - return (float)i.value; - } - else - { - long double df; - df = (long double)i.value; - df += 18446744073709551616.0; /* adding 2**64 */ - return (float)df; - } -} - -double _TIFFUInt64ToDouble(uint64_t ui64) -{ - _Int64 i; - - i.value = ui64; - if (i.part.high >= 0) - { - return (double)i.value; - } - else - { - long double df; - df = (long double)i.value; - df += 18446744073709551616.0; /* adding 2**64 */ - return (double)df; - } -} - float _TIFFClampDoubleToFloat(double val) { if (val > FLT_MAX)
diff --git a/third_party/libtiff/tif_close.c b/third_party/libtiff/tif_close.c index 907d7f1..d6bb7f1 100644 --- a/third_party/libtiff/tif_close.c +++ b/third_party/libtiff/tif_close.c
@@ -110,6 +110,14 @@ _TIFFfreeExt(tif, tif->tif_fieldscompat); } + if (tif->tif_cur_cumulated_mem_alloc != 0) + { + TIFFErrorExtR(tif, "TIFFCleanup", + "tif_cur_cumulated_mem_alloc = %" PRIu64 " whereas it " + "should be 0", + (uint64_t)tif->tif_cur_cumulated_mem_alloc); + } + _TIFFfreeExt(NULL, tif); }
diff --git a/third_party/libtiff/tif_color.c b/third_party/libtiff/tif_color.c index 2d7dcac..a52fdac 100644 --- a/third_party/libtiff/tif_color.c +++ b/third_party/libtiff/tif_color.c
@@ -89,7 +89,7 @@ void TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z, uint32_t *r, uint32_t *g, uint32_t *b) { - int i; + size_t i; float Yr, Yg, Yb; float *matrix = &cielab->display.d_mat[0][0]; @@ -109,16 +109,16 @@ Yb = TIFFmin(Yb, cielab->display.d_YCB); /* Turn luminosity to colour value. */ - i = (int)((Yr - cielab->display.d_Y0R) / cielab->rstep); - i = TIFFmin(cielab->range, i); + i = (size_t)((Yr - cielab->display.d_Y0R) / cielab->rstep); + i = TIFFmin((size_t)cielab->range, i); *r = RINT(cielab->Yr2r[i]); - i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep); - i = TIFFmin(cielab->range, i); + i = (size_t)((Yg - cielab->display.d_Y0G) / cielab->gstep); + i = TIFFmin((size_t)cielab->range, i); *g = RINT(cielab->Yg2g[i]); - i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep); - i = TIFFmin(cielab->range, i); + i = (size_t)((Yb - cielab->display.d_Y0B) / cielab->bstep); + i = TIFFmin((size_t)cielab->range, i); *b = RINT(cielab->Yb2b[i]); /* Clip output. */ @@ -135,7 +135,7 @@ int TIFFCIELabToRGBInit(TIFFCIELabToRGB *cielab, const TIFFDisplay *display, float *refWhite) { - int i; + size_t i; double dfGamma; cielab->range = CIELABTORGB_TABLE_RANGE; @@ -146,7 +146,7 @@ dfGamma = 1.0 / cielab->display.d_gammaR; cielab->rstep = (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; - for (i = 0; i <= cielab->range; i++) + for (i = 0; i <= (size_t)cielab->range; i++) { cielab->Yr2r[i] = cielab->display.d_Vrwr * ((float)pow((double)i / cielab->range, dfGamma)); @@ -156,7 +156,7 @@ dfGamma = 1.0 / cielab->display.d_gammaG; cielab->gstep = (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; - for (i = 0; i <= cielab->range; i++) + for (i = 0; i <= (size_t)cielab->range; i++) { cielab->Yg2g[i] = cielab->display.d_Vrwg * ((float)pow((double)i / cielab->range, dfGamma)); @@ -166,7 +166,7 @@ dfGamma = 1.0 / cielab->display.d_gammaB; cielab->bstep = (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; - for (i = 0; i <= cielab->range; i++) + for (i = 0; i <= (size_t)cielab->range; i++) { cielab->Yb2b[i] = cielab->display.d_Vrwb * ((float)pow((double)i / cielab->range, dfGamma));
diff --git a/third_party/libtiff/tif_dir.c b/third_party/libtiff/tif_dir.c index 85006218..459f969 100644 --- a/third_party/libtiff/tif_dir.c +++ b/third_party/libtiff/tif_dir.c
@@ -211,7 +211,7 @@ } bad: TIFFErrorExtR(tif, "TIFFSetField", - "%s: Invalid InkNames value; no NUL at given buffer end " + "%s: Invalid InkNames value; no null at given buffer end " "location %" PRIu32 ", after %" PRIu16 " ink", tif->tif_name, slen, i); return (0); @@ -1652,6 +1652,17 @@ _TIFFmemset(&(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); _TIFFmemset(&(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); + + /* Reset some internal parameters for IFD data size checking. */ + tif->tif_dir.td_dirdatasize_read = 0; + tif->tif_dir.td_dirdatasize_write = 0; + if (tif->tif_dir.td_dirdatasize_offsets != NULL) + { + _TIFFfreeExt(tif, tif->tif_dir.td_dirdatasize_offsets); + tif->tif_dir.td_dirdatasize_offsets = NULL; + tif->tif_dir.td_dirdatasize_Noffsets = 0; + } + tif->tif_dir.td_iswrittentofile = FALSE; } #undef CleanupField @@ -1676,18 +1687,23 @@ */ int TIFFCreateDirectory(TIFF *tif) { + /* Free previously allocated memory and setup default values. */ + TIFFFreeDirectory(tif); TIFFDefaultDirectory(tif); tif->tif_diroff = 0; tif->tif_nextdiroff = 0; tif->tif_curoff = 0; tif->tif_row = (uint32_t)-1; tif->tif_curstrip = (uint32_t)-1; + tif->tif_dir.td_iswrittentofile = FALSE; return 0; } int TIFFCreateCustomDirectory(TIFF *tif, const TIFFFieldArray *infoarray) { + /* Free previously allocated memory and setup default values. */ + TIFFFreeDirectory(tif); TIFFDefaultDirectory(tif); /* @@ -1848,7 +1864,9 @@ if (((uint64_t)poffa != poff) || (poffb < poffa) || (poffb < (tmsize_t)sizeof(uint16_t)) || (poffb > tif->tif_size)) { - TIFFErrorExtR(tif, module, "Error fetching directory count"); + TIFFErrorExtR(tif, module, + "%s:%d: %s: Error fetching directory count", + __FILE__, __LINE__, tif->tif_name); *nextdiroff = 0; return (0); } @@ -1877,14 +1895,18 @@ uint16_t dircount16; if (poff > (uint64_t)TIFF_TMSIZE_T_MAX - sizeof(uint64_t)) { - TIFFErrorExtR(tif, module, "Error fetching directory count"); + TIFFErrorExtR(tif, module, + "%s:%d: %s: Error fetching directory count", + __FILE__, __LINE__, tif->tif_name); return (0); } poffa = (tmsize_t)poff; poffb = poffa + sizeof(uint64_t); if (poffb > tif->tif_size) { - TIFFErrorExtR(tif, module, "Error fetching directory count"); + TIFFErrorExtR(tif, module, + "%s:%d: %s: Error fetching directory count", + __FILE__, __LINE__, tif->tif_name); return (0); } _TIFFmemcpy(&dircount64, tif->tif_base + poffa, sizeof(uint64_t)); @@ -1926,8 +1948,9 @@ if (!SeekOK(tif, *nextdiroff) || !ReadOK(tif, &dircount, sizeof(uint16_t))) { - TIFFErrorExtR(tif, module, "%s: Error fetching directory count", - tif->tif_name); + TIFFErrorExtR(tif, module, + "%s:%d: %s: Error fetching directory count", + __FILE__, __LINE__, tif->tif_name); return (0); } if (tif->tif_flags & TIFF_SWAB) @@ -1953,15 +1976,18 @@ if (!SeekOK(tif, *nextdiroff) || !ReadOK(tif, &dircount64, sizeof(uint64_t))) { - TIFFErrorExtR(tif, module, "%s: Error fetching directory count", - tif->tif_name); + TIFFErrorExtR(tif, module, + "%s:%d: %s: Error fetching directory count", + __FILE__, __LINE__, tif->tif_name); return (0); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong8(&dircount64); if (dircount64 > 0xFFFF) { - TIFFErrorExtR(tif, module, "Error fetching directory count"); + TIFFErrorExtR(tif, module, + "%s:%d: %s: Error fetching directory count", + __FILE__, __LINE__, tif->tif_name); return (0); } dircount16 = (uint16_t)dircount64; @@ -2018,6 +2044,8 @@ { ++n; } + /* Update number of main-IFDs in file. */ + tif->tif_curdircount = n; return (n); } @@ -2100,7 +2128,19 @@ tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; else tif->tif_curdir--; - return (TIFFReadDirectory(tif)); + + tdir_t curdir = tif->tif_curdir; + + int retval = TIFFReadDirectory(tif); + + if (!retval && tif->tif_curdir == curdir) + { + /* If tif_curdir has not be incremented, TIFFFetchDirectory() in + * TIFFReadDirectory() has failed and tif_curdir shall be set + * specifically. */ + tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; + } + return (retval); } /* @@ -2125,8 +2165,11 @@ int8_t probablySubIFD = 0; if (diroff == 0) { - /* Special case to invalidate the tif_lastdiroff member. */ + /* Special case to set tif_diroff=0, which is done in + * TIFFReadDirectory() below to indicate that the currently read IFD is + * treated as a new, fresh IFD. */ tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; + tif->tif_dir.td_iswrittentofile = FALSE; } else { @@ -2136,32 +2179,40 @@ probablySubIFD = 1; } /* -1 because TIFFReadDirectory() will increment tif_curdir. */ - tif->tif_curdir = - curdir == 0 ? TIFF_NON_EXISTENT_DIR_NUMBER : curdir - 1; + if (curdir >= 1) + tif->tif_curdir = curdir - 1; + else + tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; } + curdir = tif->tif_curdir; tif->tif_nextdiroff = diroff; retval = TIFFReadDirectory(tif); - /* If failed, curdir was not incremented in TIFFReadDirectory(), so set it - * back, but leave it for diroff==0. */ - if (!retval && diroff != 0) + + /* tif_curdir is incremented in TIFFReadDirectory(), but if it has not been + * incremented, TIFFFetchDirectory() has failed there and tif_curdir shall + * be set specifically. */ + if (!retval && diroff != 0 && tif->tif_curdir == curdir) { - if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER) - tif->tif_curdir = 0; - else - tif->tif_curdir++; + tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; } - if (retval && probablySubIFD) + + if (probablySubIFD) { - /* Reset IFD list to start new one for SubIFD chain and also start - * SubIFD chain with tif_curdir=0. */ - _TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */ - tif->tif_curdir = 0; /* first directory of new chain */ - /* add this offset to new IFD list */ - _TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff); + if (retval) + { + /* Reset IFD list to start new one for SubIFD chain and also start + * SubIFD chain with tif_curdir=0 for IFD loop checking. */ + /* invalidate IFD loop lists */ + _TIFFCleanupIFDOffsetAndNumberMaps(tif); + tif->tif_curdir = 0; /* first directory of new chain */ + /* add this offset to new IFD list */ + _TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff); + } /* To be able to return from SubIFD or custom-IFD to main-IFD */ tif->tif_setdirectory_force_absolute = TRUE; } + return (retval); } @@ -2257,9 +2308,11 @@ } else { + /* Need local swap because nextdir has to be used unswapped below. */ + uint64_t nextdir64 = nextdir; if (tif->tif_flags & TIFF_SWAB) - TIFFSwabLong8(&nextdir); - if (!WriteOK(tif, &nextdir, sizeof(uint64_t))) + TIFFSwabLong8(&nextdir64); + if (!WriteOK(tif, &nextdir64, sizeof(uint64_t))) { TIFFErrorExtR(tif, module, "Error writing directory link"); return (0); @@ -2303,6 +2356,10 @@ tif->tif_row = (uint32_t)-1; tif->tif_curstrip = (uint32_t)-1; tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; + if (tif->tif_curdircount > 0) + tif->tif_curdircount--; + else + tif->tif_curdircount = TIFF_NON_EXISTENT_DIR_NUMBER; _TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */ return (1); }
diff --git a/third_party/libtiff/tif_dir.h b/third_party/libtiff/tif_dir.h index 9eaf22f..ffad085 100644 --- a/third_party/libtiff/tif_dir.h +++ b/third_party/libtiff/tif_dir.h
@@ -65,6 +65,12 @@ tif_dirread.c */ } TIFFDirEntry; +typedef struct +{ + uint64_t offset; + uint64_t length; +} TIFFEntryOffsetAndLength; /* auxiliary for evaluating size of IFD data */ + /* * Internal format of a TIFF directory entry. */ @@ -115,6 +121,9 @@ #ifdef STRIPBYTECOUNTSORTED_UNUSED int td_stripbytecountsorted; /* is the bytecount array sorted ascending? */ #endif + /* Be aware that the parameters of td_stripoffset_entry and + * td_stripbytecount_entry are swapped but tdir_offset is not + * and has to be swapped when used. */ TIFFDirEntry td_stripoffset_entry; /* for deferred loading */ TIFFDirEntry td_stripbytecount_entry; /* for deferred loading */ uint16_t td_nsubifd; @@ -135,6 +144,24 @@ unsigned char td_deferstrilearraywriting; /* see TIFFDeferStrileArrayWriting() */ + + unsigned char + td_iswrittentofile; /* indicates if current IFD is present on file */ + + /* LibTIFF writes all data that does not fit into the IFD entries directly + * after the IFD tag entry part. When reading, only the IFD data directly + * and continuously behind the IFD tags is taken into account for the IFD + * data size.*/ + uint64_t td_dirdatasize_write; /* auxiliary for evaluating size of IFD data + to be written */ + uint64_t td_dirdatasize_read; /* auxiliary for evaluating size of IFD data + read from file */ + uint32_t td_dirdatasize_Noffsets; /* auxiliary counter for + tif_dir.td_dirdatasize_offsets array */ + TIFFEntryOffsetAndLength + *td_dirdatasize_offsets; /* auxiliary array for all offsets of IFD tag + entries with data outside the IFD tag + entries. */ } TIFFDirectory; /* @@ -308,11 +335,10 @@ TIFFDataType field_type; /* type of associated data */ uint32_t field_anonymous; /* if true, this is a unknown / anonymous tag */ - TIFFSetGetFieldType - set_field_type; /* type to be passed to TIFFSetField */ - TIFFSetGetFieldType - get_field_type; /* type to be passed to TIFFGetField */ - unsigned short field_bit; /* bit in fieldsset bit vector */ + TIFFSetGetFieldType set_field_type; /* type to be passed to TIFFSetField + and TIFFGetField*/ + TIFFSetGetFieldType get_field_type; /* not used */ + unsigned short field_bit; /* bit in fieldsset bit vector */ unsigned char field_oktochange; /* if true, can change while writing */ unsigned char field_passcount; /* if true, pass dir count on set */ char *field_name; /* ASCII name */
diff --git a/third_party/libtiff/tif_dirinfo.c b/third_party/libtiff/tif_dirinfo.c index 0e705e8..432e6e1 100644 --- a/third_party/libtiff/tif_dirinfo.c +++ b/third_party/libtiff/tif_dirinfo.c
@@ -213,8 +213,6 @@ {TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CurrentPreProfileMatrix", NULL}, {TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL}, #if 0 - /* TODO: revert above #if 0 for TIFF 4.6.0 */ - /* begin DNG 1.2.0.0 tags */ {TIFFTAG_COLORIMETRICREFERENCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorimetricReference", NULL}, {TIFFTAG_CAMERACALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibrationSignature", NULL}, @@ -282,9 +280,11 @@ {TIFFTAG_ILLUMINANTDATA2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData2", NULL}, {TIFFTAG_ILLUMINANTDATA3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData3", NULL}, /* end DNG tags */ +#endif /* begin TIFF/EP tags */ {TIFFTAG_EP_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP CFARepeatPatternDim", NULL}, {TIFFTAG_EP_CFAPATTERN, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP CFAPattern", NULL}, +#if 0 /* TIFFTAG_EP_BATTERYLEVEL can be RATIONAL or ASCII. * LibTiff defines it as ASCII and converts RATIONAL to an ASCII string. */ {TIFFTAG_EP_BATTERYLEVEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP BatteryLevel", NULL}, @@ -374,7 +374,7 @@ {EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL}, {EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL}, {EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL}, - /*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance! + /*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance! * However, there are two other EXIF tags where numerator indicates a special value and six other cases where the denominator indicates special values, * which are not treated within LibTiff!! */ {EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistance", NULL}, @@ -887,7 +887,7 @@ if (fld == NULL) { fld = _TIFFCreateAnonField(tif, tag, dt); - if (!_TIFFMergeFields(tif, fld, 1)) + if (fld == NULL || !_TIFFMergeFields(tif, fld, 1)) return NULL; } @@ -1197,12 +1197,24 @@ for (i = 0; i < n; i++) { tp->field_tag = info[i].field_tag; + if (info[i].field_readcount < TIFF_VARIABLE2 || + info[i].field_readcount == 0 || + info[i].field_writecount < TIFF_VARIABLE2 || + info[i].field_writecount == 0) + { + /* The fields (field_readcount) and (field_writecount) may use the + * values TIFF_VARIABLE (-1), TIFF_SPP (-2), TIFF_VARIABLE2 (-3). */ + TIFFErrorExtR(tif, module, + "The value of field_readcount and field_writecount " + "must be greater than or equal to -3 and not zero."); + return -1; + } tp->field_readcount = info[i].field_readcount; tp->field_writecount = info[i].field_writecount; tp->field_type = info[i].field_type; tp->field_anonymous = 0; tp->set_field_type = - _TIFFSetGetType(info[i].field_type, info[i].field_readcount, + _TIFFSetGetType(info[i].field_type, info[i].field_writecount, info[i].field_passcount); tp->get_field_type = _TIFFSetGetType(info[i].field_type, info[i].field_readcount,
diff --git a/third_party/libtiff/tif_dirread.c b/third_party/libtiff/tif_dirread.c index 4a5015e..2b6e0b4 100644 --- a/third_party/libtiff/tif_dirread.c +++ b/third_party/libtiff/tif_dirread.c
@@ -1016,16 +1016,7 @@ err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); if (err != TIFFReadDirEntryErrOk) return (err); -#if defined(__WIN32__) && (_MSC_VER < 1500) - /* - * XXX: MSVC 6.0 does not support conversion - * of 64-bit integers into floating point - * values. - */ - *value = _TIFFUInt64ToFloat(m); -#else *value = (float)m; -#endif return (TIFFReadDirEntryErrOk); } case TIFF_SLONG8: @@ -1130,16 +1121,7 @@ err = TIFFReadDirEntryCheckedLong8(tif, direntry, &m); if (err != TIFFReadDirEntryErrOk) return (err); -#if defined(__WIN32__) && (_MSC_VER < 1500) - /* - * XXX: MSVC 6.0 does not support conversion - * of 64-bit integers into floating point - * values. - */ - *value = _TIFFUInt64ToDouble(m); -#else *value = (double)m; -#endif return (TIFFReadDirEntryErrOk); } case TIFF_SLONG8: @@ -1308,6 +1290,24 @@ datasize = (*count) * typesize; assert((tmsize_t)datasize > 0); + if (datasize > 100 * 1024 * 1024) + { + /* Before allocating a huge amount of memory for corrupted files, check + * if size of requested memory is not greater than file size. + */ + const uint64_t filesize = TIFFGetFileSize(tif); + if (datasize > filesize) + { + TIFFWarningExtR(tif, "ReadDirEntryArray", + "Requested memory size for tag %d (0x%x) %" PRIu32 + " is greater 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; @@ -2886,16 +2886,7 @@ { if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong8(ma); -#if defined(__WIN32__) && (_MSC_VER < 1500) - /* - * XXX: MSVC 6.0 does not support - * conversion of 64-bit integers into - * floating point values. - */ - *mb++ = _TIFFUInt64ToFloat(*ma++); -#else *mb++ = (float)(*ma++); -#endif } } break; @@ -3131,16 +3122,7 @@ { if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong8(ma); -#if defined(__WIN32__) && (_MSC_VER < 1500) - /* - * XXX: MSVC 6.0 does not support - * conversion of 64-bit integers into - * floating point values. - */ - *mb++ = _TIFFUInt64ToDouble(*ma++); -#else *mb++ = (double)(*ma++); -#endif } } break; @@ -4096,6 +4078,155 @@ } /* + * To evaluate the IFD data size when reading, save the offset and data size of + * all data that does not fit into the IFD entries themselves. + */ +static bool EvaluateIFDdatasizeReading(TIFF *tif, TIFFDirEntry *dp) +{ + const uint64_t data_width = TIFFDataWidth(dp->tdir_type); + if (data_width != 0 && dp->tdir_count > UINT64_MAX / data_width) + { + TIFFErrorExtR(tif, "EvaluateIFDdatasizeReading", + "Too large IFD data size"); + return false; + } + const uint64_t datalength = dp->tdir_count * data_width; + if (datalength > ((tif->tif_flags & TIFF_BIGTIFF) ? 0x8U : 0x4U)) + { + if (tif->tif_dir.td_dirdatasize_read > UINT64_MAX - datalength) + { + TIFFErrorExtR(tif, "EvaluateIFDdatasizeReading", + "Too large IFD data size"); + return false; + } + tif->tif_dir.td_dirdatasize_read += datalength; + if (!(tif->tif_flags & TIFF_BIGTIFF)) + { + /* The offset of TIFFDirEntry are not swapped when read in. That has + * to be done when used. */ + uint32_t offset = dp->tdir_offset.toff_long; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&offset); + tif->tif_dir + .td_dirdatasize_offsets[tif->tif_dir.td_dirdatasize_Noffsets] + .offset = (uint64_t)offset; + } + else + { + tif->tif_dir + .td_dirdatasize_offsets[tif->tif_dir.td_dirdatasize_Noffsets] + .offset = dp->tdir_offset.toff_long8; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong8( + &tif->tif_dir + .td_dirdatasize_offsets[tif->tif_dir + .td_dirdatasize_Noffsets] + .offset); + } + tif->tif_dir + .td_dirdatasize_offsets[tif->tif_dir.td_dirdatasize_Noffsets] + .length = datalength; + tif->tif_dir.td_dirdatasize_Noffsets++; + } + return true; +} + +/* + * Compare function for qsort() sorting TIFFEntryOffsetAndLength array entries. + */ +static int cmpTIFFEntryOffsetAndLength(const void *a, const void *b) +{ + const TIFFEntryOffsetAndLength *ta = (const TIFFEntryOffsetAndLength *)a; + const TIFFEntryOffsetAndLength *tb = (const TIFFEntryOffsetAndLength *)b; + /* Compare offsets */ + if (ta->offset > tb->offset) + return 1; + else if (ta->offset < tb->offset) + return -1; + else + return 0; +} + +/* + * Determine the IFD data size after reading an IFD from the file that can be + * overwritten and saving it in tif_dir.td_dirdatasize_read. This data size + * includes the IFD entries themselves as well as the data that does not fit + * directly into the IFD entries but is located directly after the IFD entries + * in the file. + */ +static void CalcFinalIFDdatasizeReading(TIFF *tif, uint16_t dircount) +{ + /* IFD data size is only needed if file-writing is enabled. + * This also avoids the seek() to EOF to determine the file size, which + * causes the stdin-streaming-friendly mode of libtiff for GDAL to fail. */ + if (tif->tif_mode == O_RDONLY) + return; + + /* Sort TIFFEntryOffsetAndLength array in ascending order. */ + qsort(tif->tif_dir.td_dirdatasize_offsets, + tif->tif_dir.td_dirdatasize_Noffsets, + sizeof(TIFFEntryOffsetAndLength), cmpTIFFEntryOffsetAndLength); + + /* Get offset of end of IFD entry space. */ + uint64_t IFDendoffset; + if (!(tif->tif_flags & TIFF_BIGTIFF)) + IFDendoffset = tif->tif_diroff + 2 + dircount * 12 + 4; + else + IFDendoffset = tif->tif_diroff + 8 + dircount * 20 + 8; + + /* Check which offsets are right behind IFD entries. However, LibTIFF + * increments the writing address for every external data to an even offset. + * Thus gaps of 1 byte can occur. */ + uint64_t size = 0; + uint64_t offset; + uint32_t i; + for (i = 0; i < tif->tif_dir.td_dirdatasize_Noffsets; i++) + { + offset = tif->tif_dir.td_dirdatasize_offsets[i].offset; + if (offset == IFDendoffset) + { + size += tif->tif_dir.td_dirdatasize_offsets[i].length; + IFDendoffset += tif->tif_dir.td_dirdatasize_offsets[i].length; + } + else if (offset == IFDendoffset + 1) + { + /* Add gap byte after previous IFD data set. */ + size += tif->tif_dir.td_dirdatasize_offsets[i].length + 1; + IFDendoffset += tif->tif_dir.td_dirdatasize_offsets[i].length; + } + else + { + /* Further data is no more continuously after IFD */ + break; + } + } + /* Check for gap byte of some easy cases. This should cover 90% of cases. + * Otherwise, IFD will be re-written even it might be safely overwritten. */ + if (tif->tif_nextdiroff != 0) + { + if (tif->tif_nextdiroff == IFDendoffset + 1) + size++; + } + else + { + /* Check for IFD data ends at EOF. Then IFD can always be safely + * overwritten. */ + offset = TIFFSeekFile(tif, 0, SEEK_END); + if (offset == IFDendoffset) + { + tif->tif_dir.td_dirdatasize_read = UINT64_MAX; + return; + } + } + + /* Finally, add the size of the IFD tag entries themselves. */ + if (!(tif->tif_flags & TIFF_BIGTIFF)) + tif->tif_dir.td_dirdatasize_read = 2 + dircount * 12 + 4 + size; + else + tif->tif_dir.td_dirdatasize_read = 8 + dircount * 20 + 8 + size; +} /*-- CalcFinalIFDdatasizeReading() --*/ + +/* * Read the next TIFF directory from a file and convert it to the internal * format. We read directories sequentially. */ @@ -4150,7 +4281,6 @@ tif->tif_curdir = 0; else tif->tif_curdir++; - (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ TIFFReadDirectoryCheckOrder(tif, dir, dircount); @@ -4180,8 +4310,27 @@ tif->tif_flags &= ~TIFF_CHOPPEDUPARRAYS; /* free any old stuff and reinit */ + (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ TIFFFreeDirectory(tif); TIFFDefaultDirectory(tif); + + /* After setup a fresh directory indicate that now active IFD is also + * present on file, even if its entries could not be read successfully + * below. */ + tif->tif_dir.td_iswrittentofile = TRUE; + + /* Allocate arrays for offset values outside IFD entry for IFD data size + * checking. Note: Counter are reset within TIFFFreeDirectory(). */ + tif->tif_dir.td_dirdatasize_offsets = + (TIFFEntryOffsetAndLength *)_TIFFmallocExt( + tif, dircount * sizeof(TIFFEntryOffsetAndLength)); + if (tif->tif_dir.td_dirdatasize_offsets == NULL) + { + TIFFErrorExtR( + tif, module, + "Failed to allocate memory for counting IFD data size at reading"); + goto bad; + } /* * Electronic Arts writes gray-scale TIFF files * without a PlanarConfiguration directory entry. @@ -4260,11 +4409,9 @@ dp->tdir_tag, dp->tdir_tag); /* the following knowingly leaks the anonymous field structure */ - if (!_TIFFMergeFields( - tif, - _TIFFCreateAnonField(tif, dp->tdir_tag, - (TIFFDataType)dp->tdir_type), - 1)) + const TIFFField *fld = _TIFFCreateAnonField( + tif, dp->tdir_tag, (TIFFDataType)dp->tdir_type); + if (fld == NULL || !_TIFFMergeFields(tif, fld, 1)) { TIFFWarningExtR( tif, module, @@ -4381,6 +4528,8 @@ uint16_t value; enum TIFFReadDirEntryErr err; err = TIFFReadDirEntryShort(tif, dp, &value); + if (!EvaluateIFDdatasizeReading(tif, dp)) + goto bad; if (err == TIFFReadDirEntryErrCount) err = TIFFReadDirEntryPersampleShort(tif, dp, &value); @@ -4411,6 +4560,8 @@ err = TIFFReadDirEntryErrCount; else err = TIFFReadDirEntryDoubleArray(tif, dp, &data); + if (!EvaluateIFDdatasizeReading(tif, dp)) + goto bad; if (err != TIFFReadDirEntryErrOk) { fip = TIFFFieldWithTag(tif, dp->tdir_tag); @@ -4430,6 +4581,7 @@ break; case TIFFTAG_STRIPOFFSETS: case TIFFTAG_TILEOFFSETS: + { switch (dp->tdir_type) { case TIFF_SHORT: @@ -4452,9 +4604,13 @@ } _TIFFmemcpy(&(tif->tif_dir.td_stripoffset_entry), dp, sizeof(TIFFDirEntry)); - break; + if (!EvaluateIFDdatasizeReading(tif, dp)) + goto bad; + } + break; case TIFFTAG_STRIPBYTECOUNTS: case TIFFTAG_TILEBYTECOUNTS: + { switch (dp->tdir_type) { case TIFF_SHORT: @@ -4477,7 +4633,10 @@ } _TIFFmemcpy(&(tif->tif_dir.td_stripbytecount_entry), dp, sizeof(TIFFDirEntry)); - break; + if (!EvaluateIFDdatasizeReading(tif, dp)) + goto bad; + } + break; case TIFFTAG_COLORMAP: case TIFFTAG_TRANSFERFUNCTION: { @@ -4531,6 +4690,8 @@ err = TIFFReadDirEntryErrCount; else err = TIFFReadDirEntryShortArray(tif, dp, &value); + if (!EvaluateIFDdatasizeReading(tif, dp)) + goto bad; if (err != TIFFReadDirEntryErrOk) { fip = TIFFFieldWithTag(tif, dp->tdir_tag); @@ -4621,9 +4782,12 @@ default: (void)TIFFFetchNormalTag(tif, dp, TRUE); break; - } - } /* -- if (!dp->tdir_ignore) */ - } /* -- for-loop -- */ + } /* -- switch (dp->tdir_tag) -- */ + } /* -- if (!dp->tdir_ignore) */ + } /* -- for-loop -- */ + + /* Evaluate final IFD data size. */ + CalcFinalIFDdatasizeReading(tif, dircount); /* * OJPEG hack: @@ -5040,7 +5204,7 @@ if (dir) _TIFFfreeExt(tif, dir); return (0); -} +} /*-- TIFFReadDirectory() --*/ static void TIFFReadDirectoryCheckOrder(TIFF *tif, TIFFDirEntry *dir, uint16_t dircount) @@ -5124,8 +5288,7 @@ uint16_t di; const TIFFField *fip; uint32_t fii; - (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ - _TIFFSetupFields(tif, infoarray); + dircount = TIFFFetchDirectory(tif, diroff, &dir, NULL); if (!dircount) { @@ -5134,9 +5297,56 @@ diroff); return 0; } - TIFFFreeDirectory(tif); - _TIFFmemset(&tif->tif_dir, 0, sizeof(TIFFDirectory)); TIFFReadDirectoryCheckOrder(tif, dir, dircount); + + /* + * Mark duplicates of any tag to be ignored (bugzilla 1994) + * to avoid certain pathological problems. + */ + { + TIFFDirEntry *ma; + uint16_t mb; + for (ma = dir, mb = 0; mb < dircount; ma++, mb++) + { + TIFFDirEntry *na; + uint16_t nb; + for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++) + { + if (ma->tdir_tag == na->tdir_tag) + { + na->tdir_ignore = TRUE; + } + } + } + } + + /* Free any old stuff and reinit. */ + (*tif->tif_cleanup)(tif); /* cleanup any previous compression state */ + TIFFFreeDirectory(tif); + /* Even if custom directories do not need the default settings of a standard + * IFD, the pointer to the TIFFSetField() and TIFFGetField() (i.e. + * tif->tif_tagmethods.vsetfield and tif->tif_tagmethods.vgetfield) need to + * be initialized, which is done in TIFFDefaultDirectory(). + * After that, the field array for the custom tags needs to be setup again. + */ + TIFFDefaultDirectory(tif); + _TIFFSetupFields(tif, infoarray); + + /* Allocate arrays for offset values outside IFD entry for IFD data size + * checking. Note: Counter are reset within TIFFFreeDirectory(). */ + tif->tif_dir.td_dirdatasize_offsets = + (TIFFEntryOffsetAndLength *)_TIFFmallocExt( + tif, dircount * sizeof(TIFFEntryOffsetAndLength)); + if (tif->tif_dir.td_dirdatasize_offsets == NULL) + { + TIFFErrorExtR( + tif, module, + "Failed to allocate memory for counting IFD data size at reading"); + if (dir) + _TIFFfreeExt(tif, dir); + return 0; + } + for (di = 0, dp = dir; di < dircount; di++, dp++) { TIFFReadDirectoryFindFieldInfo(tif, dp->tdir_tag, &fii); @@ -5146,11 +5356,9 @@ "Unknown field with tag %" PRIu16 " (0x%" PRIx16 ") encountered", dp->tdir_tag, dp->tdir_tag); - if (!_TIFFMergeFields( - tif, - _TIFFCreateAnonField(tif, dp->tdir_tag, - (TIFFDataType)dp->tdir_type), - 1)) + const TIFFField *fld = _TIFFCreateAnonField( + tif, dp->tdir_tag, (TIFFDataType)dp->tdir_type); + if (fld == NULL || !_TIFFMergeFields(tif, fld, 1)) { TIFFWarningExtR(tif, module, "Registering anonymous field with tag %" PRIu16 @@ -5233,6 +5441,9 @@ } /*-- if (!dp->tdir_ignore) */ } } + /* Evaluate final IFD data size. */ + CalcFinalIFDdatasizeReading(tif, dircount); + /* To be able to return from SubIFD or custom-IFD to main-IFD */ tif->tif_setdirectory_force_absolute = TRUE; if (dir) @@ -5246,9 +5457,7 @@ */ int TIFFReadEXIFDirectory(TIFF *tif, toff_t diroff) { - const TIFFFieldArray *exifFieldArray; - exifFieldArray = _TIFFGetExifFields(); - return TIFFReadCustomDirectory(tif, diroff, exifFieldArray); + return TIFFReadCustomDirectory(tif, diroff, _TIFFGetExifFields()); } /* @@ -5256,9 +5465,7 @@ */ int TIFFReadGPSDirectory(TIFF *tif, toff_t diroff) { - const TIFFFieldArray *gpsFieldArray; - gpsFieldArray = _TIFFGetGpsFields(); - return TIFFReadCustomDirectory(tif, diroff, gpsFieldArray); + return TIFFReadCustomDirectory(tif, diroff, _TIFFGetGpsFields()); } static int EstimateStripByteCounts(TIFF *tif, TIFFDirEntry *dir, @@ -5274,6 +5481,24 @@ if (!_TIFFFillStrilesInternal(tif, 0)) return -1; + const uint64_t allocsize = (uint64_t)td->td_nstrips * sizeof(uint64_t); + uint64_t filesize = 0; + if (allocsize > 100 * 1024 * 1024) + { + /* Before allocating a huge amount of memory for corrupted files, check + * if size of requested memory is not greater than file size. */ + filesize = TIFFGetFileSize(tif); + if (allocsize > filesize) + { + TIFFWarningExtR( + tif, module, + "Requested memory size for StripByteCounts of %" PRIu64 + " is greater than filesize %" PRIu64 ". Memory not allocated", + allocsize, filesize); + return -1; + } + } + if (td->td_stripbytecount_p) _TIFFfreeExt(tif, td->td_stripbytecount_p); td->td_stripbytecount_p = (uint64_t *)_TIFFCheckMalloc( @@ -5284,9 +5509,7 @@ 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 @@ -5322,6 +5545,8 @@ return -1; space += datasize; } + if (filesize == 0) + filesize = TIFFGetFileSize(tif); if (filesize < space) /* we should perhaps return in error ? */ space = filesize; @@ -5929,6 +6154,20 @@ "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) + { + TIFFWarningExtR( + tif, module, + "Requested memory size for TIFF directory of %" PRIu64 + " is greater 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) @@ -5976,6 +6215,8 @@ } } } + /* 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"); if (dir == 0) @@ -6088,6 +6329,12 @@ } } } + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != NULL) + _TIFFfreeExt(tif, data); + return (0); + } if (mb + 1 < (uint32_t)dp->tdir_count) TIFFWarningExtR( tif, module, @@ -6097,15 +6344,15 @@ fip->field_name); else if (mb + 1 > (uint32_t)dp->tdir_count) { - uint8_t *o; - TIFFWarningExtR( - tif, module, - "ASCII value for tag \"%s\" does not end in null byte", - fip->field_name); + TIFFWarningExtR(tif, module, + "ASCII value for tag \"%s\" does not end " + "in null byte. Forcing it to be null", + fip->field_name); /* TIFFReadDirEntryArrayWithLimit() ensures this can't be * larger than MAX_SIZE_TAG_DATA */ assert((uint32_t)dp->tdir_count + 1 == dp->tdir_count + 1); - o = _TIFFmallocExt(tif, (uint32_t)dp->tdir_count + 1); + uint8_t *o = + _TIFFmallocExt(tif, (uint32_t)dp->tdir_count + 1); if (o == NULL) { if (data != NULL) @@ -6215,6 +6462,8 @@ err = TIFFReadDirEntryLong8(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + return 0; if (!TIFFSetField(tif, dp->tdir_tag, data)) return (0); } @@ -6228,6 +6477,8 @@ err = TIFFReadDirEntrySlong8(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + return 0; if (!TIFFSetField(tif, dp->tdir_tag, data)) return (0); } @@ -6241,6 +6492,8 @@ err = TIFFReadDirEntryFloat(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + return 0; if (!TIFFSetField(tif, dp->tdir_tag, data)) return (0); } @@ -6254,6 +6507,8 @@ err = TIFFReadDirEntryDouble(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + return 0; if (!TIFFSetField(tif, dp->tdir_tag, data)) return (0); } @@ -6267,6 +6522,8 @@ err = TIFFReadDirEntryIfd8(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + return 0; if (!TIFFSetField(tif, dp->tdir_tag, data)) return (0); } @@ -6316,6 +6573,12 @@ err = TIFFReadDirEntryByteArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, data); if (data != 0) @@ -6345,6 +6608,12 @@ err = TIFFReadDirEntrySbyteArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, data); if (data != 0) @@ -6374,6 +6643,12 @@ err = TIFFReadDirEntryShortArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, data); if (data != 0) @@ -6403,6 +6678,12 @@ err = TIFFReadDirEntrySshortArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, data); if (data != 0) @@ -6432,6 +6713,12 @@ err = TIFFReadDirEntryLongArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, data); if (data != 0) @@ -6461,6 +6748,12 @@ err = TIFFReadDirEntrySlongArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, data); if (data != 0) @@ -6490,6 +6783,12 @@ err = TIFFReadDirEntryLong8Array(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, data); if (data != 0) @@ -6519,6 +6818,12 @@ err = TIFFReadDirEntrySlong8Array(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, data); if (data != 0) @@ -6548,6 +6853,12 @@ err = TIFFReadDirEntryFloatArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, data); if (data != 0) @@ -6579,6 +6890,12 @@ err = TIFFReadDirEntryDoubleArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, data); if (data != 0) @@ -6601,16 +6918,39 @@ err = TIFFReadDirEntryByteArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; if (data != 0 && dp->tdir_count > 0 && data[dp->tdir_count - 1] != '\0') { - TIFFWarningExtR( - tif, module, - "ASCII value for tag \"%s\" does not end in null " - "byte. Forcing it to be null", - fip->field_name); - data[dp->tdir_count - 1] = '\0'; + TIFFWarningExtR(tif, module, + "ASCII value for ASCII array tag " + "\"%s\" does not end in null " + "byte. Forcing it to be null", + fip->field_name); + /* Enlarge buffer and add terminating null. */ + uint8_t *o = + _TIFFmallocExt(tif, (uint32_t)dp->tdir_count + 1); + if (o == NULL) + { + if (data != NULL) + _TIFFfreeExt(tif, data); + return (0); + } + if (dp->tdir_count > 0) + { + _TIFFmemcpy(o, data, (uint32_t)dp->tdir_count); + } + o[(uint32_t)dp->tdir_count] = 0; + dp->tdir_count++; /* Increment for added null. */ + if (data != 0) + _TIFFfreeExt(tif, data); + data = o; } m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6634,6 +6974,12 @@ err = TIFFReadDirEntryByteArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6657,6 +7003,12 @@ err = TIFFReadDirEntrySbyteArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6680,6 +7032,12 @@ err = TIFFReadDirEntryShortArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6703,6 +7061,12 @@ err = TIFFReadDirEntrySshortArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6726,6 +7090,12 @@ err = TIFFReadDirEntryLongArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6749,6 +7119,12 @@ err = TIFFReadDirEntrySlongArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6772,6 +7148,12 @@ err = TIFFReadDirEntryLong8Array(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6795,6 +7177,12 @@ err = TIFFReadDirEntrySlong8Array(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6818,6 +7206,12 @@ err = TIFFReadDirEntryFloatArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6841,6 +7235,12 @@ err = TIFFReadDirEntryDoubleArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6864,6 +7264,12 @@ err = TIFFReadDirEntryIfd8Array(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint16_t)(dp->tdir_count), data); @@ -6883,15 +7289,39 @@ err = TIFFReadDirEntryByteArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; if (data != 0 && dp->tdir_count > 0 && data[dp->tdir_count - 1] != '\0') { - TIFFWarningExtR(tif, module, - "ASCII value for tag \"%s\" does not end " - "in null byte. Forcing it to be null", - fip->field_name); - data[dp->tdir_count - 1] = '\0'; + TIFFWarningExtR( + tif, module, + "ASCII value for ASCII array tag \"%s\" does not end " + "in null byte. Forcing it to be null", + fip->field_name); + /* Enlarge buffer and add terminating null. */ + uint8_t *o = + _TIFFmallocExt(tif, (uint32_t)dp->tdir_count + 1); + if (o == NULL) + { + if (data != NULL) + _TIFFfreeExt(tif, data); + return (0); + } + if (dp->tdir_count > 0) + { + _TIFFmemcpy(o, data, (uint32_t)dp->tdir_count); + } + o[(uint32_t)dp->tdir_count] = 0; + dp->tdir_count++; /* Increment for added null. */ + if (data != 0) + _TIFFfreeExt(tif, data); + data = o; } m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -6935,6 +7365,12 @@ } if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, count, data); if (data != 0) @@ -6952,6 +7388,12 @@ err = TIFFReadDirEntrySbyteArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -6970,6 +7412,12 @@ err = TIFFReadDirEntryShortArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -6988,6 +7436,12 @@ err = TIFFReadDirEntrySshortArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -7006,6 +7460,12 @@ err = TIFFReadDirEntryLongArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -7024,6 +7484,12 @@ err = TIFFReadDirEntrySlongArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -7042,6 +7508,12 @@ err = TIFFReadDirEntryLong8Array(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -7060,6 +7532,12 @@ err = TIFFReadDirEntrySlong8Array(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -7078,6 +7556,12 @@ err = TIFFReadDirEntryFloatArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -7096,6 +7580,12 @@ err = TIFFReadDirEntryDoubleArray(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -7114,6 +7604,12 @@ err = TIFFReadDirEntryIfd8Array(tif, dp, &data); if (err == TIFFReadDirEntryErrOk) { + if (!EvaluateIFDdatasizeReading(tif, dp)) + { + if (data != 0) + _TIFFfreeExt(tif, data); + return 0; + } int m; m = TIFFSetField(tif, dp->tdir_tag, (uint32_t)(dp->tdir_count), data); @@ -7172,6 +7668,25 @@ return (0); } + const uint64_t allocsize = (uint64_t)nstrips * sizeof(uint64_t); + if (allocsize > 100 * 1024 * 1024) + { + /* Before allocating a huge amount of memory for corrupted files, + * check if size of requested memory is not greater than file size. + */ + const uint64_t filesize = TIFFGetFileSize(tif); + if (allocsize > filesize) + { + TIFFWarningExtR( + tif, module, + "Requested memory size for StripArray of %" PRIu64 + " is greater than filesize %" PRIu64 + ". Memory not allocated", + allocsize, filesize); + _TIFFfreeExt(tif, data); + return (0); + } + } resizeddata = (uint64_t *)_TIFFCheckMalloc( tif, nstrips, sizeof(uint64_t), "for strip array"); if (resizeddata == 0) @@ -7271,6 +7786,26 @@ } 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. + */ + const uint64_t allocsize = (uint64_t)nstrips * sizeof(uint64_t) * 2; + if (allocsize > 100 * 1024 * 1024) + { + const uint64_t filesize = TIFFGetFileSize(tif); + if (allocsize > filesize) + { + TIFFWarningExtR(tif, "allocChoppedUpStripArrays", + "Requested memory size for StripByteCount and " + "StripOffsets %" PRIu64 + " is greater than filesize %" PRIu64 + ". Memory not allocated", + allocsize, filesize); + return; + } + } + newcounts = (uint64_t *)_TIFFCheckMalloc(tif, nstrips, sizeof(uint64_t), "for chopped \"StripByteCounts\" array"); @@ -7371,7 +7906,7 @@ /* * never increase the number of rows per strip */ - if (rowsperstrip >= td->td_rowsperstrip) + if (rowsperstrip >= td->td_rowsperstrip || rowsperstrip == 0) return; nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip); if (nstrips == 0) @@ -7467,6 +8002,8 @@ stripbytes = rowblocksperstrip * rowblockbytes; assert(stripbytes <= 0x7FFFFFFFUL); + if (rowsperstrip == 0) + return; nstrips = TIFFhowmany_32(td->td_imagelength, rowsperstrip); if (nstrips == 0) return;
diff --git a/third_party/libtiff/tif_dirwrite.c b/third_party/libtiff/tif_dirwrite.c index d8844bb..facdeaf 100644 --- a/third_party/libtiff/tif_dirwrite.c +++ b/third_party/libtiff/tif_dirwrite.c
@@ -303,12 +303,14 @@ } /* - * Similar to TIFFWriteDirectory(), but if the directory has already + * Similar to TIFFWriteDirectorySec(), but if the directory has already * been written once, it is relocated to the end of the file, in case it * has changed in size. Note that this will result in the loss of the * previously used directory space. */ -int TIFFRewriteDirectory(TIFF *tif) + +static int TIFFRewriteDirectorySec(TIFF *tif, int isimage, int imagedone, + uint64_t *pdiroff) { static const char module[] = "TIFFRewriteDirectory"; @@ -464,10 +466,20 @@ } /* - * Now use TIFFWriteDirectory() normally. + * Now use TIFFWriteDirectorySec() normally. */ + return TIFFWriteDirectorySec(tif, isimage, imagedone, pdiroff); +} /*-- TIFFRewriteDirectorySec() --*/ - return TIFFWriteDirectory(tif); +/* + * Similar to TIFFWriteDirectory(), but if the directory has already + * been written once, it is relocated to the end of the file, in case it + * has changed in size. Note that this will result in the loss of the + * previously used directory space. + */ +int TIFFRewriteDirectory(TIFF *tif) +{ + return TIFFRewriteDirectorySec(tif, TRUE, TRUE, NULL); } static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone, @@ -542,7 +554,12 @@ dirsize = 0; while (1) { + /* The first loop only determines "ndir" and uses TIFFLinkDirectory() to + * set the offset at which the IFD is to be written to the file. + * The second loop writes IFD entries to the file. */ ndir = 0; + if (dir == NULL) + tif->tif_dir.td_dirdatasize_write = 0; if (isimage) { if (TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) @@ -852,7 +869,7 @@ if ((o->field_bit >= FIELD_CODEC) && (TIFFFieldSet(tif, o->field_bit))) { - switch (o->get_field_type) + switch (o->set_field_type) { case TIFF_SETGET_ASCII: { @@ -1085,8 +1102,18 @@ break; } } + /* "break" if IFD has been written above in second pass.*/ if (dir != NULL) break; + + /* Evaluate IFD data size: Finally, add the size of the IFD tag entries + * themselves. */ + if (!(tif->tif_flags & TIFF_BIGTIFF)) + tif->tif_dir.td_dirdatasize_write += 2 + ndir * 12 + 4; + else + tif->tif_dir.td_dirdatasize_write += 8 + ndir * 20 + 8; + + /* Setup a new directory within first pass. */ dir = _TIFFmallocExt(tif, ndir * sizeof(TIFFDirEntry)); if (dir == NULL) { @@ -1095,18 +1122,58 @@ } if (isimage) { - if ((tif->tif_diroff == 0) && (!TIFFLinkDirectory(tif))) - goto bad; + /* Check, weather the IFD to be written is new or an already written + * IFD can be overwritten or needs to be re-written to a different + * location in the file because the IFD is extended with additional + * tags or the IFD data size is increased. + * - tif_diroff == 0, if a new directory has to be linked. + * - tif_diroff != 0, IFD has been re-read from file and will be + * overwritten or re-written. + */ + if (tif->tif_diroff == 0) + { + if (!TIFFLinkDirectory(tif)) + goto bad; + } + else if (tif->tif_dir.td_dirdatasize_write > + tif->tif_dir.td_dirdatasize_read) + { + if (dir != NULL) + { + _TIFFfreeExt(tif, dir); + dir = NULL; + } + if (!TIFFRewriteDirectorySec(tif, isimage, imagedone, pdiroff)) + goto bad; + return (1); + } } else - tif->tif_diroff = - (TIFFSeekFile(tif, 0, SEEK_END) + 1) & (~((toff_t)1)); + { + /* For !isimage, which means custom-IFD like EXIFIFD or + * checkpointing an IFD, determine whether to overwrite or append at + * the end of the file. + */ + if (!((tif->tif_dir.td_dirdatasize_read > 0) && + (tif->tif_dir.td_dirdatasize_write <= + tif->tif_dir.td_dirdatasize_read))) + { + /* Append at end of file and increment to an even offset. */ + tif->tif_diroff = + (TIFFSeekFile(tif, 0, SEEK_END) + 1) & (~((toff_t)1)); + } + } + /* Return IFD offset */ if (pdiroff != NULL) *pdiroff = tif->tif_diroff; if (!(tif->tif_flags & TIFF_BIGTIFF)) dirsize = 2 + ndir * 12 + 4; else dirsize = 8 + ndir * 20 + 8; + /* Append IFD data stright after the IFD tag entries. + * Data that does not fit into an IFD tag entry is written to the file + * in the second pass of the while loop. That offset is stored in "dir". + */ tif->tif_dataoff = tif->tif_diroff + dirsize; if (!(tif->tif_flags & TIFF_BIGTIFF)) tif->tif_dataoff = (uint32_t)tif->tif_dataoff; @@ -1118,16 +1185,12 @@ } if (tif->tif_dataoff & 1) tif->tif_dataoff++; - if (isimage) - { - if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER) - tif->tif_curdir = 0; - else - tif->tif_curdir++; - } - } + } /* while() */ if (isimage) { + /* For SubIFDs remember offset of SubIFD tag within main IFD. + * However, might be already done in TIFFWriteDirectoryTagSubifd() if + * there are more than one SubIFD. */ if (TIFFFieldSet(tif, FIELD_SUBIFD) && (tif->tif_subifdoff == 0)) { uint32_t na; @@ -1148,6 +1211,8 @@ tif->tif_subifdoff = tif->tif_diroff + 8 + na * 20 + 12; } } + /* Copy/swab IFD entries from "dir" into "dirmem", + * which is then written to file. */ dirmem = _TIFFmallocExt(tif, dirsize); if (dirmem == NULL) { @@ -1227,7 +1292,8 @@ dir = NULL; if (!SeekOK(tif, tif->tif_diroff)) { - TIFFErrorExtR(tif, module, "IO error writing directory"); + TIFFErrorExtR(tif, module, + "IO error writing directory at seek to offset"); goto bad; } if (!WriteOK(tif, dirmem, (tmsize_t)dirsize)) @@ -1236,18 +1302,83 @@ goto bad; } _TIFFfreeExt(tif, dirmem); + + /* Increment tif_curdir if IFD wasn't already written to file and no error + * occurred during IFD writing above. */ + if (isimage && !tif->tif_dir.td_iswrittentofile) + { + if (!((tif->tif_flags & TIFF_INSUBIFD) && + !(TIFFFieldSet(tif, FIELD_SUBIFD)))) + { + /*-- Normal main-IFD case --*/ + if (tif->tif_curdircount != TIFF_NON_EXISTENT_DIR_NUMBER) + { + tif->tif_curdir = tif->tif_curdircount; + } + else + { + /*ToDo SU: NEW_IFD_CURDIR_INCREMENTING: Delete this + * unexpected case after some testing time. */ + /* Attention: tif->tif_curdircount is already set within + * TIFFNumberOfDirectories() */ + tif->tif_curdircount = TIFFNumberOfDirectories(tif); + tif->tif_curdir = tif->tif_curdircount; + TIFFErrorExtR( + tif, module, + "tif_curdircount is TIFF_NON_EXISTENT_DIR_NUMBER, " + "not expected !! Line %d", + __LINE__); + goto bad; + } + } + else + { + /*-- SubIFD case -- */ + /* tif_curdir is always set to 0 for all SubIFDs. */ + tif->tif_curdir = 0; + } + } + /* Increment tif_curdircount only if main-IFD of an image was not already + * present on file. */ + /* Check in combination with (... && !(TIFFFieldSet(tif, FIELD_SUBIFD))) + * is necessary here because TIFF_INSUBIFD was already set above for the + * next SubIFD when this main-IFD (with FIELD_SUBIFD) is currently being + * written. */ + if (isimage && !tif->tif_dir.td_iswrittentofile && + !((tif->tif_flags & TIFF_INSUBIFD) && + !(TIFFFieldSet(tif, FIELD_SUBIFD)))) + tif->tif_curdircount++; + + tif->tif_dir.td_iswrittentofile = TRUE; + + /* Reset SubIFD writing stage after last SubIFD has been written. */ + if (imagedone && (tif->tif_flags & TIFF_INSUBIFD) && tif->tif_nsubifd == 0) + tif->tif_flags &= ~TIFF_INSUBIFD; + + /* Add or update this directory to the IFD list. */ + if (!_TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, tif->tif_diroff)) + { + TIFFErrorExtR(tif, module, + "Starting directory %u at offset 0x%" PRIx64 " (%" PRIu64 + ") might cause an IFD loop", + tif->tif_curdir, tif->tif_diroff, tif->tif_diroff); + } + if (imagedone) { TIFFFreeDirectory(tif); tif->tif_flags &= ~TIFF_DIRTYDIRECT; tif->tif_flags &= ~TIFF_DIRTYSTRIP; (*tif->tif_cleanup)(tif); - /* - * Reset directory-related state for subsequent - * directories. - */ + /* Reset directory-related state for subsequent directories. */ TIFFCreateDirectory(tif); } + else + { + /* IFD is only checkpointed to file (or a custom IFD like EXIF is + * written), thus set IFD data size written to file. */ + tif->tif_dir.td_dirdatasize_read = tif->tif_dir.td_dirdatasize_write; + } return (1); bad: if (dir != NULL) @@ -1401,11 +1532,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, char *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return ( TIFFWriteDirectoryTagCheckedAscii(tif, ndir, dir, tag, count, value)); } @@ -1414,11 +1540,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, uint8_t *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedUndefinedArray(tif, ndir, dir, tag, count, value)); } @@ -1427,11 +1548,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, uint8_t *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedByteArray(tif, ndir, dir, tag, count, value)); } @@ -1440,11 +1556,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, int8_t *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedSbyteArray(tif, ndir, dir, tag, count, value)); } @@ -1453,11 +1564,6 @@ TIFFDirEntry *dir, uint16_t tag, uint16_t value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedShort(tif, ndir, dir, tag, value)); } @@ -1465,11 +1571,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, uint16_t *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedShortArray(tif, ndir, dir, tag, count, value)); } @@ -1485,8 +1586,9 @@ int o; if (dir == NULL) { - (*ndir)++; - return (1); + /* only evaluate IFD data size and inc. ndir */ + return (TIFFWriteDirectoryTagCheckedShortArray( + tif, ndir, dir, tag, tif->tif_dir.td_samplesperpixel, NULL)); } m = _TIFFmallocExt(tif, tif->tif_dir.td_samplesperpixel * sizeof(uint16_t)); if (m == NULL) @@ -1506,11 +1608,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, int16_t *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedSshortArray(tif, ndir, dir, tag, count, value)); } @@ -1519,11 +1616,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedLong(tif, ndir, dir, tag, value)); } @@ -1531,11 +1623,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, uint32_t *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedLongArray(tif, ndir, dir, tag, count, value)); } @@ -1544,11 +1631,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, int32_t *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedSlongArray(tif, ndir, dir, tag, count, value)); } @@ -1572,8 +1654,9 @@ /* is this just a counting pass? */ if (dir == NULL) { - (*ndir)++; - return (1); + /* only evaluate IFD data size and inc. ndir */ + return (TIFFWriteDirectoryTagCheckedLong8Array(tif, ndir, dir, tag, + count, value)); } /* We always write Long8 for BigTIFF, no checking needed. */ @@ -1632,8 +1715,9 @@ /* is this just a counting pass? */ if (dir == NULL) { - (*ndir)++; - return (1); + /* only evaluate IFD data size and inc. ndir */ + return (TIFFWriteDirectoryTagCheckedSlong8Array(tif, ndir, dir, tag, + count, value)); } /* We always write SLong8 for BigTIFF, no checking needed. */ if (tif->tif_flags & TIFF_BIGTIFF) @@ -1686,11 +1770,6 @@ TIFFDirEntry *dir, uint16_t tag, double value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedRational(tif, ndir, dir, tag, value)); } @@ -1698,11 +1777,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, float *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedRationalArray(tif, ndir, dir, tag, count, value)); } @@ -1711,11 +1785,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, float *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedSrationalArray(tif, ndir, dir, tag, count, value)); } @@ -1727,11 +1796,6 @@ uint32_t count, double *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedRationalDoubleArray(tif, ndir, dir, tag, count, value)); } @@ -1742,11 +1806,6 @@ uint32_t count, double *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedSrationalDoubleArray( tif, ndir, dir, tag, count, value)); } @@ -1755,11 +1814,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, float *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedFloatArray(tif, ndir, dir, tag, count, value)); } @@ -1768,11 +1822,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, double *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedDoubleArray(tif, ndir, dir, tag, count, value)); } @@ -1781,11 +1830,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t count, uint32_t *value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } return (TIFFWriteDirectoryTagCheckedIfdArray(tif, ndir, dir, tag, count, value)); } @@ -1794,11 +1838,6 @@ TIFFDirEntry *dir, uint16_t tag, uint32_t value) { - if (dir == NULL) - { - (*ndir)++; - return (1); - } if (value <= 0xFFFF) return (TIFFWriteDirectoryTagCheckedShort(tif, ndir, dir, tag, (uint16_t)value)); @@ -1824,7 +1863,7 @@ compression == COMPRESSION_WEBP || compression == COMPRESSION_JXL) { /* For a few select compression types, we assume that in the worst */ - /* case the compressed size will be 10 times the uncompressed size */ + /* case the compressed size will be 10 times the uncompressed size. */ /* This is overly pessismistic ! */ return strile_size >= uncompressed_threshold / 10; } @@ -1856,15 +1895,16 @@ int o; int write_aslong4; - /* is this just a counting pass? */ - if (dir == NULL) - { - (*ndir)++; - return (1); - } - if (tif->tif_dir.td_deferstrilearraywriting) { + if (dir == NULL) + { + /* This is just a counting pass to count IFD entries. + * For deferstrilearraywriting no extra bytes will be written + * into IFD space. */ + (*ndir)++; + return 1; + } return TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_NOTYPE, 0, 0, NULL); } @@ -1872,12 +1912,10 @@ if (tif->tif_flags & TIFF_BIGTIFF) { int write_aslong8 = 1; - /* In the case of ByteCounts array, we may be able to write them on */ - /* LONG if the strip/tilesize is not too big. */ - /* Also do that for count > 1 in the case someone would want to create - */ - /* a single-strip file with a growing height, in which case using */ - /* LONG8 will be safer. */ + /* In the case of ByteCounts array, we may be able to write them on LONG + * if the strip/tilesize is not too big. Also do that for count > 1 in + * the case someone would want to create a single-strip file with a + * growing height, in which case using LONG8 will be safer. */ if (count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS) { write_aslong8 = WriteAsLong8(tif, TIFFStripSize64(tif)); @@ -1989,13 +2027,6 @@ uint32_t *q; int o; - /* is this just a counting pass? */ - if (dir == NULL) - { - (*ndir)++; - return (1); - } - /* We always write IFD8 for BigTIFF, no checking needed. */ if (tif->tif_flags & TIFF_BIGTIFF) return TIFFWriteDirectoryTagCheckedIfd8Array(tif, ndir, dir, tag, count, @@ -2032,6 +2063,26 @@ return (o); } +/* + * Auxiliary function to determine the IFD data size to be written to the file. + * The IFD data size is finally the size of the IFD tag entries plus the IFD + * data that is written directly after the IFD tag entries. + */ +static void EvaluateIFDdatasizeWrite(TIFF *tif, uint32_t count, + uint32_t typesize, uint32_t *ndir) +{ + uint64_t datalength = (uint64_t)count * typesize; + if (datalength > ((tif->tif_flags & TIFF_BIGTIFF) ? 0x8U : 0x4U)) + { + /* LibTIFF increments write address to an even offset, thus datalength + * written is also incremented. */ + if (datalength & 1) + datalength++; + tif->tif_dir.td_dirdatasize_write += datalength; + } + (*ndir)++; +} + static int TIFFWriteDirectoryTagColormap(TIFF *tif, uint32_t *ndir, TIFFDirEntry *dir) { @@ -2039,12 +2090,13 @@ uint32_t m; uint16_t *n; int o; - if (dir == NULL) - { - (*ndir)++; - return (1); - } m = (1 << tif->tif_dir.td_bitspersample); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, 3 * m, sizeof(uint16_t), ndir); + return 1; + } + n = _TIFFmallocExt(tif, 3 * m * sizeof(uint16_t)); if (n == NULL) { @@ -2068,11 +2120,6 @@ uint16_t n; uint16_t *o; int p; - if (dir == NULL) - { - (*ndir)++; - return (1); - } /* TIFFTAG_TRANSFERFUNCTION expects (1 or 3) pointer to arrays with * (1 << BitsPerSample) * uint16_t values. */ @@ -2086,9 +2133,9 @@ { if (tif->tif_dir.td_transferfunction[i] == NULL) { - TIFFWarningExtR( - tif, module, - "Too few TransferFunctions provided. Tag not written to file"); + TIFFWarningExtR(tif, module, + "Too few TransferFunctions provided. Tag " + "not written to file"); return (1); /* Not an error; only tag is not written. */ } } @@ -2108,6 +2155,12 @@ m * sizeof(uint16_t))) n = 1; } + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, n * m, 2, ndir); + return 1; + } + o = _TIFFmallocExt(tif, n * m * sizeof(uint16_t)); if (o == NULL) { @@ -2136,11 +2189,6 @@ int n; if (tif->tif_dir.td_nsubifd == 0) return (1); - if (dir == NULL) - { - (*ndir)++; - return (1); - } m = tif->tif_dataoff; if (!(tif->tif_flags & TIFF_BIGTIFF)) { @@ -2178,6 +2226,12 @@ n = TIFFWriteDirectoryTagCheckedIfd8Array( tif, ndir, dir, TIFFTAG_SUBIFD, tif->tif_dir.td_nsubifd, tif->tif_dir.td_subifd); + + if (dir == NULL) + /* Just have evaluated IFD data size and incremented ndir + * above in sub-functions. */ + return (n); + if (!n) return (0); /* @@ -2202,6 +2256,11 @@ uint32_t count, char *value) { assert(sizeof(char) == 1); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 1, ndir); + return 1; + } return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_ASCII, count, count, value)); } @@ -2213,6 +2272,11 @@ uint8_t *value) { assert(sizeof(uint8_t) == 1); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 1, ndir); + return 1; + } return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_UNDEFINED, count, count, value)); } @@ -2223,6 +2287,11 @@ uint8_t *value) { assert(sizeof(uint8_t) == 1); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 1, ndir); + return 1; + } return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_BYTE, count, count, value)); } @@ -2233,6 +2302,11 @@ int8_t *value) { assert(sizeof(int8_t) == 1); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 1, ndir); + return 1; + } return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SBYTE, count, count, value)); } @@ -2243,6 +2317,12 @@ { uint16_t m; assert(sizeof(uint16_t) == 2); + if (dir == NULL) + { + /* No additional data to IFD data size just increment ndir. */ + (*ndir)++; + return 1; + } m = value; if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&m); @@ -2257,6 +2337,11 @@ { assert(count < 0x80000000); assert(sizeof(uint16_t) == 2); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 2, ndir); + return 1; + } if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfShort(value, count); return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SHORT, count, @@ -2270,6 +2355,11 @@ { assert(count < 0x80000000); assert(sizeof(int16_t) == 2); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 2, ndir); + return 1; + } if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfShort((uint16_t *)value, count); return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SSHORT, count, @@ -2282,6 +2372,12 @@ { uint32_t m; assert(sizeof(uint32_t) == 4); + if (dir == NULL) + { + /* No additional data to IFD data size just increment ndir. */ + (*ndir)++; + return 1; + } m = value; if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong(&m); @@ -2296,6 +2392,11 @@ { assert(count < 0x40000000); assert(sizeof(uint32_t) == 4); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 4, ndir); + return 1; + } if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfLong(value, count); return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_LONG, count, @@ -2309,6 +2410,11 @@ { assert(count < 0x40000000); assert(sizeof(int32_t) == 4); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 4, ndir); + return 1; + } if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfLong((uint32_t *)value, count); return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SLONG, count, @@ -2328,6 +2434,11 @@ "LONG8 not allowed for ClassicTIFF"); return (0); } + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 8, ndir); + return 1; + } if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfLong8(value, count); return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_LONG8, count, @@ -2347,6 +2458,11 @@ "SLONG8 not allowed for ClassicTIFF"); return (0); } + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 8, ndir); + return 1; + } if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfLong8((uint64_t *)value, count); return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_SLONG8, count, @@ -2370,16 +2486,17 @@ TIFFErrorExtR(tif, module, "Not-a-number value is illegal"); return 0; } - /*--Rational2Double: New function also used for non-custom rational tags. - * However, could be omitted here, because - * TIFFWriteDirectoryTagCheckedRational() is not used by code for custom - * tags, only by code for named-tiff-tags like FIELD_RESOLUTION and - * FIELD_POSITION */ - else + + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ { - DoubleToRational(value, &m[0], &m[1]); + tif->tif_dir.td_dirdatasize_write += + (tif->tif_flags & TIFF_BIGTIFF) ? 0 : 0x8U; + (*ndir)++; + return 1; } + DoubleToRational(value, &m[0], &m[1]); + if (tif->tif_flags & TIFF_SWAB) { TIFFSwabLong(&m[0]); @@ -2402,6 +2519,11 @@ uint32_t nc; int o; assert(sizeof(uint32_t) == 4); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(uint32_t), ndir); + return 1; + } m = _TIFFmallocExt(tif, count * 2 * sizeof(uint32_t)); if (m == NULL) { @@ -2433,6 +2555,11 @@ uint32_t nc; int o; assert(sizeof(int32_t) == 4); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(int32_t), ndir); + return 1; + } m = _TIFFmallocExt(tif, count * 2 * sizeof(int32_t)); if (m == NULL) { @@ -2465,6 +2592,11 @@ uint32_t nc; int o; assert(sizeof(uint32_t) == 4); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(uint32_t), ndir); + return 1; + } m = _TIFFmallocExt(tif, count * 2 * sizeof(uint32_t)); if (m == NULL) { @@ -2495,6 +2627,11 @@ uint32_t nc; int o; assert(sizeof(int32_t) == 4); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count * 2, sizeof(int32_t), ndir); + return 1; + } m = _TIFFmallocExt(tif, count * 2 * sizeof(int32_t)); if (m == NULL) { @@ -2816,6 +2953,11 @@ { assert(count < 0x40000000); assert(sizeof(float) == 4); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 4, ndir); + return 1; + } TIFFCvtNativeToIEEEFloat(tif, count, &value); if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfFloat(value, count); @@ -2830,6 +2972,11 @@ { assert(count < 0x20000000); assert(sizeof(double) == 8); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 8, ndir); + return 1; + } TIFFCvtNativeToIEEEDouble(tif, count, &value); if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfDouble(value, count); @@ -2843,6 +2990,11 @@ { assert(count < 0x40000000); assert(sizeof(uint32_t) == 4); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 4, ndir); + return 1; + } if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfLong(value, count); return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_IFD, count, @@ -2857,6 +3009,11 @@ assert(count < 0x20000000); assert(sizeof(uint64_t) == 8); assert(tif->tif_flags & TIFF_BIGTIFF); + if (dir == NULL) /* Just evaluate IFD data size and increment ndir. */ + { + EvaluateIFDdatasizeWrite(tif, count, 8, ndir); + return 1; + } if (tif->tif_flags & TIFF_SWAB) TIFFSwabArrayOfLong8(value, count); return (TIFFWriteDirectoryTagData(tif, ndir, dir, tag, TIFF_IFD8, count, @@ -2973,15 +3130,15 @@ "Error writing SubIFD directory link"); return (0); } + /* * Advance to the next SubIFD or, if this is - * the last one configured, revert back to the - * normal directory linkage. + * the last one configured, reverting back to the + * normal directory linkage is done in TIFFWriteDirectorySec() + * by tif->tif_flags &= ~TIFF_INSUBIFD;. */ if (--tif->tif_nsubifd) tif->tif_subifdoff += 4; - else - tif->tif_flags &= ~TIFF_INSUBIFD; return (1); } else @@ -2997,19 +3154,23 @@ "Error writing SubIFD directory link"); return (0); } + /* * Advance to the next SubIFD or, if this is - * the last one configured, revert back to the - * normal directory linkage. + * the last one configured, reverting back to the + * normal directory linkage is done in TIFFWriteDirectorySec() + * by tif->tif_flags &= ~TIFF_INSUBIFD;. */ if (--tif->tif_nsubifd) tif->tif_subifdoff += 8; - else - tif->tif_flags &= ~TIFF_INSUBIFD; return (1); } } + /* + * Handle main-IFDs + */ + tdir_t ndir = 1; /* count current number of main-IFDs */ if (!(tif->tif_flags & TIFF_BIGTIFF)) { uint32_t m; @@ -3030,18 +3191,26 @@ TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header"); return (0); } + if (!tif->tif_dir.td_iswrittentofile) + tif->tif_curdircount = 0; return (1); } /* * Not the first directory, search to the last and append. */ - if (tif->tif_lastdiroff != 0) + tdir_t dirn = 0; + if (tif->tif_lastdiroff != 0 && + _TIFFGetDirNumberFromOffset(tif, tif->tif_lastdiroff, &dirn)) { + /* Start searching from the lastely written IFD. Thus get its IFD + * number. */ nextdir = (uint32_t)tif->tif_lastdiroff; + ndir = dirn + 1; } else { nextdir = tif->tif_header.classic.tiff_diroff; + ndir = 1; /* start searching from the first IFD */ } while (1) @@ -3076,10 +3245,12 @@ break; } nextdir = nextnextdir; + ndir++; } } else { + /*- BigTIFF -*/ uint64_t m; uint64_t nextdir; m = tif->tif_diroff; @@ -3098,18 +3269,26 @@ TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header"); return (0); } + if (!tif->tif_dir.td_iswrittentofile) + tif->tif_curdircount = 0; return (1); } /* * Not the first directory, search to the last and append. */ - if (tif->tif_lastdiroff != 0) + tdir_t dirn = 0; + if (tif->tif_lastdiroff != 0 && + _TIFFGetDirNumberFromOffset(tif, tif->tif_lastdiroff, &dirn)) { + /* Start searching from the lastely written IFD. Thus get its IFD + * number. */ nextdir = tif->tif_lastdiroff; + ndir = dirn + 1; } else { nextdir = tif->tif_header.big.tiff_diroff; + ndir = 1; /* start searching from the first IFD */ } while (1) { @@ -3126,9 +3305,9 @@ TIFFSwabLong8(&dircount64); if (dircount64 > 0xFFFF) { - TIFFErrorExtR( - tif, module, - "Sanity check on tag count failed, likely corrupt TIFF"); + TIFFErrorExtR(tif, module, + "Sanity check on tag count failed, " + "likely corrupt TIFF"); return (0); } dircount = (uint16_t)dircount64; @@ -3152,8 +3331,20 @@ break; } nextdir = nextnextdir; + ndir++; } } + /* Offset of next IFD is written to file. + * Update number of main-IFDs in file. + * However, tif_curdircount shall count only newly written main-IFDs with + * entries and not only number of linked offsets! Thus, tif_curdircount is + * incremented at the end of TIFFWriteDirectorySec(). + * TIFF_NON_EXISTENT_DIR_NUMBER means 'dont know number of IFDs' + * 0 means 'empty file opened for writing, but no IFD written yet' */ + if (!tif->tif_dir.td_iswrittentofile && !(tif->tif_flags & TIFF_INSUBIFD)) + { + tif->tif_curdircount = ndir; + } return (1); } @@ -3197,9 +3388,9 @@ /* -------------------------------------------------------------------- */ if (isMapped(tif)) { - TIFFErrorExtR( - tif, module, - "Memory mapped files not currently supported for this operation."); + TIFFErrorExtR(tif, module, + "Memory mapped files not currently supported for " + "this operation."); return 0; }
diff --git a/third_party/libtiff/tif_fax3.c b/third_party/libtiff/tif_fax3.c index a3c645c..01a7847 100644 --- a/third_party/libtiff/tif_fax3.c +++ b/third_party/libtiff/tif_fax3.c
@@ -41,6 +41,14 @@ #include "t4.h" #include <stdio.h> +#ifndef EOF_REACHED_COUNT_THRESHOLD +/* Arbitrary threshold to avoid corrupted single-strip files with extremely + * large imageheight to cause apparently endless looping, such as in + * https://gitlab.com/libtiff/libtiff/-/issues/583 + */ +#define EOF_REACHED_COUNT_THRESHOLD 8192 +#endif + /* * Compression+decompression state blocks are * derived from this ``base state'' block. @@ -77,6 +85,8 @@ uint32_t data; /* current i/o byte/word */ int bit; /* current i/o bit in byte */ int EOLcnt; /* count of EOL codes recognized */ + int eofReachedCount; /* number of times decode has been called with + EOF already reached */ TIFFFaxFillFunc fill; /* fill routine */ uint32_t *runs; /* b&w runs for current/previous row */ uint32_t nruns; /* size of the refruns / curruns arrays */ @@ -120,6 +130,7 @@ int EOLcnt; /* # EOL codes recognized */ \ const unsigned char *bitmap = sp->bitmap; /* input data bit reverser */ \ const TIFFFaxTabEnt *TabEnt + #define DECLARE_STATE_2D(tif, sp, mod) \ DECLARE_STATE(tif, sp, mod); \ int b1; /* next change on prev line */ \ @@ -162,6 +173,7 @@ sp->bit = 0; /* force initial read */ sp->data = 0; sp->EOLcnt = 0; /* force initial scan for EOL */ + sp->eofReachedCount = 0; /* * Decoder assumes lsb-to-msb bit order. Note that we select * this here rather than in Fax3SetupState so that viewers can @@ -232,7 +244,12 @@ line, isTiled(tif) ? "tile" : "strip", (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), a0); } -#define prematureEOF(a0) Fax3PrematureEOF(module, tif, sp->line, a0) +#define prematureEOF(a0) \ + do \ + { \ + Fax3PrematureEOF(module, tif, sp->line, a0); \ + ++sp->eofReachedCount; \ + } while (0) #define Nop @@ -252,6 +269,14 @@ TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); return (-1); } + if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD) + { + TIFFErrorExtR( + tif, module, + "End of file has already been reached %d times within that strip", + sp->eofReachedCount); + return (-1); + } CACHE_STATE(tif, sp); thisrun = sp->curruns; while (occ > 0) @@ -302,6 +327,14 @@ TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); return (-1); } + if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD) + { + TIFFErrorExtR( + tif, module, + "End of file has already been reached %d times within that strip", + sp->eofReachedCount); + return (-1); + } CACHE_STATE(tif, sp); while (occ > 0) { @@ -536,7 +569,11 @@ TIFFroundup and TIFFSafeMultiply return zero on integer overflow */ - dsp->runs = (uint32_t *)NULL; + if (dsp->runs != NULL) + { + _TIFFfreeExt(tif, dsp->runs); + dsp->runs = (uint32_t *)NULL; + } dsp->nruns = TIFFroundup_32(rowpixels + 1, 32); if (needsRefLine) { @@ -578,6 +615,10 @@ * is referenced. The reference line must * be initialized to be ``white'' (done elsewhere). */ + if (esp->refline != NULL) + { + _TIFFfreeExt(tif, esp->refline); + } esp->refline = (unsigned char *)_TIFFmallocExt(tif, rowbytes); if (esp->refline == NULL) { @@ -1514,7 +1555,16 @@ TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); return (-1); } + if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD) + { + TIFFErrorExtR( + tif, module, + "End of file has already been reached %d times within that strip", + sp->eofReachedCount); + return (-1); + } CACHE_STATE(tif, sp); + int start = sp->line; while (occ > 0) { a0 = 0; @@ -1563,7 +1613,9 @@ } (*sp->fill)(buf, thisrun, pa, lastx); UNCACHE_STATE(tif, sp); - return (sp->line ? 1 : -1); /* don't error on badly-terminated strips */ + return (sp->line != start + ? 1 + : -1); /* don't error on badly-terminated strips */ } UNCACHE_STATE(tif, sp); return (1);
diff --git a/third_party/libtiff/tif_getimage.c b/third_party/libtiff/tif_getimage.c index f5a05e5..3ee0626 100644 --- a/third_party/libtiff/tif_getimage.c +++ b/third_party/libtiff/tif_getimage.c
@@ -761,6 +761,12 @@ toskew = -(int32_t)(tw - w); } + if (tw == 0 || th == 0) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "tile width or height is zero"); + return (0); + } + /* * Leftmost tile is clipped on left side if col_offset > 0. */ @@ -936,6 +942,12 @@ break; } + if (tw == 0 || th == 0) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "tile width or height is zero"); + return (0); + } + /* * Leftmost tile is clipped on left side if col_offset > 0. */ @@ -1118,6 +1130,11 @@ } TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + if (rowsperstrip == 0) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero"); + return (0); + } scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0); @@ -1242,6 +1259,12 @@ } TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + if (rowsperstrip == 0) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero"); + return (0); + } + scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0); for (row = 0; row < h; row += nrow) @@ -3239,6 +3262,13 @@ } TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + + if (rowsperstrip == 0) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero"); + return (0); + } + if ((row % rowsperstrip) != 0) { TIFFErrorExtR( @@ -3250,6 +3280,13 @@ if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg)) { + if (row >= img.height) + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Invalid row passed to TIFFReadRGBAStrip()."); + TIFFRGBAImageEnd(&img); + return (0); + } img.row_offset = row; img.col_offset = 0; @@ -3308,6 +3345,13 @@ TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize); TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize); + if (tile_xsize == 0 || tile_ysize == 0) + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "tile_xsize or tile_ysize is zero"); + return (0); + } + if ((col % tile_xsize) != 0 || (row % tile_ysize) != 0) { TIFFErrorExtR(tif, TIFFFileName(tif), @@ -3327,6 +3371,14 @@ return (0); } + if (col >= img.width || row >= img.height) + { + TIFFErrorExtR(tif, 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
diff --git a/third_party/libtiff/tif_hash_set.c b/third_party/libtiff/tif_hash_set.c index cec22ab..9be488e 100644 --- a/third_party/libtiff/tif_hash_set.c +++ b/third_party/libtiff/tif_hash_set.c
@@ -146,7 +146,7 @@ set->fnEqualFunc = fnEqualFunc ? fnEqualFunc : TIFFHashSetEqualPointer; set->fnFreeEltFunc = fnFreeEltFunc; set->nSize = 0; - set->tabList = (TIFFList **)(calloc(sizeof(TIFFList *), 53)); + set->tabList = (TIFFList **)(calloc(53, sizeof(TIFFList *))); if (set->tabList == NULL) { free(set); @@ -367,7 +367,7 @@ { int nNewAllocatedSize = anPrimes[set->nIndiceAllocatedSize]; TIFFList **newTabList = - (TIFFList **)(calloc(sizeof(TIFFList *), nNewAllocatedSize)); + (TIFFList **)(calloc(nNewAllocatedSize, sizeof(TIFFList *))); if (newTabList == NULL) return false; #ifdef HASH_DEBUG
diff --git a/third_party/libtiff/tif_jpeg.c b/third_party/libtiff/tif_jpeg.c index a7dbde7..8eb2f74 100644 --- a/third_party/libtiff/tif_jpeg.c +++ b/third_party/libtiff/tif_jpeg.c
@@ -73,43 +73,6 @@ int scheme, int is_encode); int TIFFJPEGIsFullStripRequired_12(TIFF *tif); -/* We undefine FAR to avoid conflict with JPEG definition */ - -#ifdef FAR -#undef FAR -#endif - -/* - Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is - not defined. Unfortunately, the MinGW and Borland compilers include - a typedef for INT32, which causes a conflict. MSVC does not include - a conflicting typedef given the headers which are included. -*/ -#if defined(__BORLANDC__) || defined(__MINGW32__) -#define XMD_H 1 -#endif - -/* - The windows RPCNDR.H file defines boolean, but defines it with the - unsigned char size. You should compile JPEG library using appropriate - definitions in jconfig.h header, but many users compile library in wrong - way. That causes errors of the following type: - - "JPEGLib: JPEG parameter struct mismatch: library thinks size is 432, - caller expects 464" - - For such users we will fix the problem here. See install.doc file from - the JPEG library distribution for details. -*/ - -/* Define "boolean" as unsigned char, not int, per Windows custom. */ -#if defined(__WIN32__) && !defined(__MINGW32__) -#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ -typedef unsigned char boolean; -#endif -#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ -#endif - #if defined(USE_SYSTEM_LIBJPEG) #include <jerror.h> #include <jpeglib.h> @@ -133,18 +96,18 @@ * 16bit value? */ -/* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 2.2 which +/* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 3.0 which * adds a dual-mode 8/12 bit API in the same library. */ #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) #define JPEG_DUAL_MODE_8_12 /* Start by undefining BITS_IN_JSAMPLE which is always set to 8 in libjpeg-turbo - * >= 2.2 Cf + * >= 3.0 Cf * https://github.com/libjpeg-turbo/libjpeg-turbo/commit/8b9bc4b9635a2a047fb23ebe70c9acd728d3f99b */ #undef BITS_IN_JSAMPLE -/* libjpeg-turbo >= 2.2 adds J12xxxx datatypes for the 12-bit mode. */ +/* libjpeg-turbo >= 3.0 adds J12xxxx datatypes for the 12-bit mode. */ #if defined(FROM_TIF_JPEG_12) #define BITS_IN_JSAMPLE 12 #define TIFF_JSAMPLE J12SAMPLE @@ -190,9 +153,20 @@ #define LONGJMP(jbuf, code) longjmp(jbuf, code) #define JMP_BUF jmp_buf +#ifndef TIFF_jpeg_destination_mgr_defined +#define TIFF_jpeg_destination_mgr_defined typedef struct jpeg_destination_mgr jpeg_destination_mgr; +#endif + +#ifndef TIFF_jpeg_source_mgr_defined +#define TIFF_jpeg_source_mgr_defined typedef struct jpeg_source_mgr jpeg_source_mgr; +#endif + +#ifndef TIFF_jpeg_error_mgr_defined +#define TIFF_jpeg_error_mgr_defined typedef struct jpeg_error_mgr jpeg_error_mgr; +#endif /* * State block for each open TIFF file using @@ -1249,6 +1223,12 @@ * For PC 2, scale down the expected strip/tile size * to match a downsampled component */ + if (sp->h_sampling == 0 || sp->v_sampling == 0) + { + TIFFErrorExtR(tif, module, + "JPEG horizontal or vertical sampling is zero"); + return (0); + } segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); segment_height = TIFFhowmany_32(segment_height, sp->v_sampling); } @@ -1479,7 +1459,10 @@ sp->src.bytes_in_buffer = (size_t)tif->tif_rawcc; if (sp->bytesperline == 0) + { + memset(buf, 0, (size_t)cc); return 0; + } nrows = cc / sp->bytesperline; if (cc % sp->bytesperline) @@ -1500,7 +1483,10 @@ JSAMPROW bufptr = (JSAMPROW)buf; if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1) + { + memset(buf, 0, (size_t)cc); return (0); + } ++tif->tif_row; buf += sp->bytesperline; @@ -1534,7 +1520,10 @@ sp->src.bytes_in_buffer = (size_t)tif->tif_rawcc; if (sp->bytesperline == 0) + { + memset(buf, 0, (size_t)cc); return 0; + } nrows = cc / sp->bytesperline; if (cc % sp->bytesperline) @@ -1570,7 +1559,10 @@ * for 12bit data, which we need to repack. */ if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1) + { + memset(buf, 0, (size_t)cc); return (0); + } if (sp->cinfo.d.data_precision == 12) { @@ -2198,6 +2190,12 @@ /* for PC 2, scale down the strip/tile size * to match a downsampled component */ + if (sp->h_sampling == 0 || sp->v_sampling == 0) + { + TIFFErrorExtR(tif, module, + "JPEG horizontal or vertical sampling is zero"); + return (0); + } segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); segment_height = TIFFhowmany_32(segment_height, sp->v_sampling); }
diff --git a/third_party/libtiff/tif_luv.c b/third_party/libtiff/tif_luv.c index 021756d..d196535 100644 --- a/third_party/libtiff/tif_luv.c +++ b/third_party/libtiff/tif_luv.c
@@ -951,7 +951,8 @@ int uv_encode(double u, double v, int em) /* encode (u',v') coordinates */ { - register int vi, ui; + unsigned int vi; + int ui; /* check for NaN */ if (u != u || v != v) @@ -980,8 +981,9 @@ int uv_decode(double *up, double *vp, int c) /* decode (u',v') index */ { - int upper, lower; - register int ui, vi; + unsigned int upper, lower; + int ui; + unsigned int vi; if (c < 0 || c >= UV_NDIVS) return (-1);
diff --git a/third_party/libtiff/tif_lzw.c b/third_party/libtiff/tif_lzw.c index d631fa1..4baf78e 100644 --- a/third_party/libtiff/tif_lzw.c +++ b/third_party/libtiff/tif_lzw.c
@@ -161,8 +161,8 @@ } LZWCodecState; #define LZWState(tif) ((LZWBaseState *)(tif)->tif_data) -#define DecoderState(tif) ((LZWCodecState *)LZWState(tif)) -#define EncoderState(tif) ((LZWCodecState *)LZWState(tif)) +#define LZWDecoderState(tif) ((LZWCodecState *)LZWState(tif)) +#define LZWEncoderState(tif) ((LZWCodecState *)LZWState(tif)) static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s); #ifdef LZW_COMPAT @@ -183,7 +183,7 @@ static int LZWSetupDecode(TIFF *tif) { static const char module[] = "LZWSetupDecode"; - LZWCodecState *sp = DecoderState(tif); + LZWCodecState *sp = LZWDecoderState(tif); int code; if (sp == NULL) @@ -199,7 +199,7 @@ return (0); } - sp = DecoderState(tif); + sp = LZWDecoderState(tif); sp->dec_codetab = NULL; sp->dec_decode = NULL; @@ -245,7 +245,7 @@ static int LZWPreDecode(TIFF *tif, uint16_t s) { static const char module[] = "LZWPreDecode"; - LZWCodecState *sp = DecoderState(tif); + LZWCodecState *sp = LZWDecoderState(tif); (void)s; assert(sp != NULL); @@ -329,10 +329,7 @@ #ifdef WORDS_BIGENDIAN #define GetNextData(nextdata, bp) memcpy(&nextdata, bp, sizeof(nextdata)) #elif SIZEOF_WORDTYPE == 8 -#if defined(__GNUC__) && defined(__x86_64__) -#define GetNextData(nextdata, bp) \ - nextdata = __builtin_bswap64(*(uint64_t *)(bp)) -#elif defined(_M_X64) +#if defined(_M_X64) #define GetNextData(nextdata, bp) nextdata = _byteswap_uint64(*(uint64_t *)(bp)) #elif defined(__GNUC__) #define GetNextData(nextdata, bp) \ @@ -346,10 +343,7 @@ (((uint64_t)bp[6]) << 8) | (((uint64_t)bp[7])) #endif #elif SIZEOF_WORDTYPE == 4 -#if defined(__GNUC__) && defined(__i386__) -#define GetNextData(nextdata, bp) \ - nextdata = __builtin_bswap32(*(uint32_t *)(bp)) -#elif defined(_M_X86) +#if defined(_M_X86) #define GetNextData(nextdata, bp) \ nextdata = _byteswap_ulong(*(unsigned long *)(bp)) #elif defined(__GNUC__) @@ -409,7 +403,7 @@ static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s) { static const char module[] = "LZWDecode"; - LZWCodecState *sp = DecoderState(tif); + LZWCodecState *sp = LZWDecoderState(tif); uint8_t *op = (uint8_t *)op0; tmsize_t occ = occ0; uint8_t *bp; @@ -423,6 +417,7 @@ if (sp->read_error) { + memset(op, 0, (size_t)occ); TIFFErrorExtR(tif, module, "LZWDecode: Scanline %" PRIu32 " cannot be read due to " "previous error", @@ -737,6 +732,7 @@ if (occ > 0) { + memset(op, 0, (size_t)occ); TIFFErrorExtR(tif, module, "Not enough data at scanline %" PRIu32 " (short %" PRIu64 " bytes)", @@ -746,12 +742,14 @@ return (1); no_eoi: + memset(op, 0, (size_t)occ); sp->read_error = 1; TIFFErrorExtR(tif, module, "LZWDecode: Strip %" PRIu32 " not terminated with EOI code", tif->tif_curstrip); return 0; error_code: + memset(op, 0, (size_t)occ); sp->read_error = 1; TIFFErrorExtR(tif, tif->tif_name, "Using code not yet in table"); return 0; @@ -800,7 +798,7 @@ static int LZWDecodeCompat(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s) { static const char module[] = "LZWDecodeCompat"; - LZWCodecState *sp = DecoderState(tif); + LZWCodecState *sp = LZWDecoderState(tif); uint8_t *op = (uint8_t *)op0; tmsize_t occ = occ0; uint8_t *tp; @@ -1026,7 +1024,7 @@ static int LZWSetupEncode(TIFF *tif) { static const char module[] = "LZWSetupEncode"; - LZWCodecState *sp = EncoderState(tif); + LZWCodecState *sp = LZWEncoderState(tif); assert(sp != NULL); sp->enc_hashtab = (hash_t *)_TIFFmallocExt(tif, HSIZE * sizeof(hash_t)); @@ -1043,7 +1041,7 @@ */ static int LZWPreEncode(TIFF *tif, uint16_t s) { - LZWCodecState *sp = EncoderState(tif); + LZWCodecState *sp = LZWEncoderState(tif); (void)s; assert(sp != NULL); @@ -1114,7 +1112,7 @@ */ static int LZWEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) { - register LZWCodecState *sp = EncoderState(tif); + register LZWCodecState *sp = LZWEncoderState(tif); register long fcode; register hash_t *hp; register int h, c; @@ -1299,7 +1297,7 @@ */ static int LZWPostEncode(TIFF *tif) { - register LZWCodecState *sp = EncoderState(tif); + register LZWCodecState *sp = LZWEncoderState(tif); uint8_t *op = tif->tif_rawcp; long nextbits = sp->lzw_nextbits; WordType nextdata = sp->lzw_nextdata; @@ -1381,11 +1379,11 @@ assert(tif->tif_data != 0); - if (DecoderState(tif)->dec_codetab) - _TIFFfreeExt(tif, DecoderState(tif)->dec_codetab); + if (LZWDecoderState(tif)->dec_codetab) + _TIFFfreeExt(tif, LZWDecoderState(tif)->dec_codetab); - if (EncoderState(tif)->enc_hashtab) - _TIFFfreeExt(tif, EncoderState(tif)->enc_hashtab); + if (LZWEncoderState(tif)->enc_hashtab) + _TIFFfreeExt(tif, LZWEncoderState(tif)->enc_hashtab); _TIFFfreeExt(tif, tif->tif_data); tif->tif_data = NULL; @@ -1404,9 +1402,9 @@ tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(LZWCodecState)); if (tif->tif_data == NULL) goto bad; - DecoderState(tif)->dec_codetab = NULL; - DecoderState(tif)->dec_decode = NULL; - EncoderState(tif)->enc_hashtab = NULL; + LZWDecoderState(tif)->dec_codetab = NULL; + LZWDecoderState(tif)->dec_decode = NULL; + LZWEncoderState(tif)->enc_hashtab = NULL; LZWState(tif)->rw_mode = tif->tif_mode; /*
diff --git a/third_party/libtiff/tif_open.c b/third_party/libtiff/tif_open.c index 23fcf81..59a07be 100644 --- a/third_party/libtiff/tif_open.c +++ b/third_party/libtiff/tif_open.c
@@ -25,7 +25,13 @@ /* * TIFF Library. */ + +#ifdef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS +#undef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS +#endif + #include "tiffiop.h" +#include <assert.h> #include <limits.h> /* @@ -81,8 +87,9 @@ void TIFFOpenOptionsFree(TIFFOpenOptions *opts) { _TIFFfree(opts); } /** Define a limit in bytes for a single memory allocation done by libtiff. - * If max_single_mem_alloc is set to 0, no other limit that the underlying - * _TIFFmalloc() will be applied, which is the default. + * If max_single_mem_alloc is set to 0, which is the default, no other limit + * that the underlying _TIFFmalloc() or + * TIFFOpenOptionsSetMaxCumulatedMemAlloc() will be applied. */ void TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts, tmsize_t max_single_mem_alloc) @@ -90,6 +97,18 @@ opts->max_single_mem_alloc = max_single_mem_alloc; } +/** Define a limit in bytes for the cumulated memory allocations done by libtiff + * on a given TIFF handle. + * If max_cumulated_mem_alloc is set to 0, which is the default, no other limit + * that the underlying _TIFFmalloc() or + * TIFFOpenOptionsSetMaxSingleMemAlloc() will be applied. + */ +void TIFFOpenOptionsSetMaxCumulatedMemAlloc(TIFFOpenOptions *opts, + tmsize_t max_cumulated_mem_alloc) +{ + opts->max_cumulated_mem_alloc = max_cumulated_mem_alloc; +} + void TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts, TIFFErrorHandlerExtR handler, void *errorhandler_user_data) @@ -117,6 +136,30 @@ (uint64_t)s, (uint64_t)tif->tif_max_single_mem_alloc); } +static void _TIFFEmitErrorAboveMaxCumulatedMemAlloc(TIFF *tif, + const char *pszFunction, + tmsize_t s) +{ + TIFFErrorExtR(tif, pszFunction, + "Cumulated memory allocation of %" PRIu64 " + %" PRIu64 + " bytes is beyond the %" PRIu64 + " cumulated byte limit defined in open options", + (uint64_t)tif->tif_cur_cumulated_mem_alloc, (uint64_t)s, + (uint64_t)tif->tif_max_cumulated_mem_alloc); +} + +/* When allocating memory, we write at the beginning of the buffer it size. + * This allows us to keep track of the total memory allocated when we + * malloc/calloc/realloc and free. In theory we need just SIZEOF_SIZE_T bytes + * for that, but on x86_64, allocations of more than 16 bytes are aligned on + * 16 bytes. Hence using 2 * SIZEOF_SIZE_T. + * It is critical that _TIFFmallocExt/_TIFFcallocExt/_TIFFreallocExt are + * paired with _TIFFfreeExt. + * CMakeLists.txt defines TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS, which in + * turn disables the definition of the non Ext version in tiffio.h + */ +#define LEADING_AREA_TO_STORE_ALLOC_SIZE (2 * SIZEOF_SIZE_T) + /** malloc() version that takes into account memory-specific open options */ void *_TIFFmallocExt(TIFF *tif, tmsize_t s) { @@ -126,16 +169,32 @@ _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFmallocExt", s); return NULL; } + if (tif != NULL && tif->tif_max_cumulated_mem_alloc > 0) + { + if (s > tif->tif_max_cumulated_mem_alloc - + tif->tif_cur_cumulated_mem_alloc || + s > TIFF_TMSIZE_T_MAX - LEADING_AREA_TO_STORE_ALLOC_SIZE) + { + _TIFFEmitErrorAboveMaxCumulatedMemAlloc(tif, "_TIFFmallocExt", s); + return NULL; + } + void *ptr = _TIFFmalloc(LEADING_AREA_TO_STORE_ALLOC_SIZE + s); + if (!ptr) + return NULL; + tif->tif_cur_cumulated_mem_alloc += s; + memcpy(ptr, &s, sizeof(s)); + return (char *)ptr + LEADING_AREA_TO_STORE_ALLOC_SIZE; + } return _TIFFmalloc(s); } /** calloc() version that takes into account memory-specific open options */ void *_TIFFcallocExt(TIFF *tif, tmsize_t nmemb, tmsize_t siz) { + if (nmemb <= 0 || siz <= 0 || nmemb > TIFF_TMSIZE_T_MAX / siz) + return NULL; if (tif != NULL && tif->tif_max_single_mem_alloc > 0) { - if (nmemb <= 0 || siz <= 0 || nmemb > TIFF_TMSIZE_T_MAX / siz) - return NULL; if (nmemb * siz > tif->tif_max_single_mem_alloc) { _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFcallocExt", @@ -143,6 +202,23 @@ return NULL; } } + if (tif != NULL && tif->tif_max_cumulated_mem_alloc > 0) + { + const tmsize_t s = nmemb * siz; + if (s > tif->tif_max_cumulated_mem_alloc - + tif->tif_cur_cumulated_mem_alloc || + s > TIFF_TMSIZE_T_MAX - LEADING_AREA_TO_STORE_ALLOC_SIZE) + { + _TIFFEmitErrorAboveMaxCumulatedMemAlloc(tif, "_TIFFcallocExt", s); + return NULL; + } + void *ptr = _TIFFcalloc(LEADING_AREA_TO_STORE_ALLOC_SIZE + s, 1); + if (!ptr) + return NULL; + tif->tif_cur_cumulated_mem_alloc += s; + memcpy(ptr, &s, sizeof(s)); + return (char *)ptr + LEADING_AREA_TO_STORE_ALLOC_SIZE; + } return _TIFFcalloc(nmemb, siz); } @@ -155,13 +231,49 @@ _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFreallocExt", s); return NULL; } + if (tif != NULL && tif->tif_max_cumulated_mem_alloc > 0) + { + void *oldPtr = p; + tmsize_t oldSize = 0; + if (p) + { + oldPtr = (char *)p - LEADING_AREA_TO_STORE_ALLOC_SIZE; + memcpy(&oldSize, oldPtr, sizeof(oldSize)); + assert(oldSize <= tif->tif_cur_cumulated_mem_alloc); + } + if (s > oldSize && + (s > tif->tif_max_cumulated_mem_alloc - + (tif->tif_cur_cumulated_mem_alloc - oldSize) || + s > TIFF_TMSIZE_T_MAX - LEADING_AREA_TO_STORE_ALLOC_SIZE)) + { + _TIFFEmitErrorAboveMaxCumulatedMemAlloc(tif, "_TIFFreallocExt", + s - oldSize); + return NULL; + } + void *newPtr = + _TIFFrealloc(oldPtr, LEADING_AREA_TO_STORE_ALLOC_SIZE + s); + if (newPtr == NULL) + return NULL; + tif->tif_cur_cumulated_mem_alloc -= oldSize; + tif->tif_cur_cumulated_mem_alloc += s; + memcpy(newPtr, &s, sizeof(s)); + return (char *)newPtr + LEADING_AREA_TO_STORE_ALLOC_SIZE; + } return _TIFFrealloc(p, s); } /** free() version that takes into account memory-specific open options */ void _TIFFfreeExt(TIFF *tif, void *p) { - (void)tif; + if (p != NULL && tif != NULL && tif->tif_max_cumulated_mem_alloc > 0) + { + void *oldPtr = (char *)p - LEADING_AREA_TO_STORE_ALLOC_SIZE; + tmsize_t oldSize; + memcpy(&oldSize, oldPtr, sizeof(oldSize)); + assert(oldSize <= tif->tif_cur_cumulated_mem_alloc); + tif->tif_cur_cumulated_mem_alloc -= oldSize; + p = oldPtr; + } _TIFFfree(p); } @@ -231,6 +343,17 @@ (uint64_t)opts->max_single_mem_alloc); goto bad2; } + if (opts && opts->max_cumulated_mem_alloc > 0 && + size_to_alloc > opts->max_cumulated_mem_alloc) + { + _TIFFErrorEarly(opts, clientdata, module, + "%s: Memory allocation of %" PRIu64 + " bytes is beyond the %" PRIu64 + " cumulated byte limit defined in open options", + name, (uint64_t)size_to_alloc, + (uint64_t)opts->max_cumulated_mem_alloc); + goto bad2; + } tif = (TIFF *)_TIFFmallocExt(NULL, size_to_alloc); if (tif == NULL) { @@ -243,6 +366,7 @@ strcpy(tif->tif_name, name); tif->tif_mode = m & ~(O_CREAT | O_TRUNC); tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; /* non-existent directory */ + tif->tif_curdircount = TIFF_NON_EXISTENT_DIR_NUMBER; tif->tif_curoff = 0; tif->tif_curstrip = (uint32_t)-1; /* invalid strip */ tif->tif_row = (uint32_t)-1; /* read/write pre-increment */ @@ -261,6 +385,7 @@ tif->tif_warnhandler = opts->warnhandler; tif->tif_warnhandler_user_data = opts->warnhandler_user_data; tif->tif_max_single_mem_alloc = opts->max_single_mem_alloc; + tif->tif_max_cumulated_mem_alloc = opts->max_cumulated_mem_alloc; } if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) @@ -423,9 +548,9 @@ TIFFErrorExtR(tif, name, "Cannot read TIFF header"); goto bad; } -/* - * Setup header and write. - */ + /* + * Setup header and write. + */ #ifdef WORDS_BIGENDIAN tif->tif_header.common.tiff_magic = (tif->tif_flags & TIFF_SWAB) ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN; @@ -433,13 +558,17 @@ tif->tif_header.common.tiff_magic = (tif->tif_flags & TIFF_SWAB) ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN; #endif + TIFFHeaderUnion tif_header_swapped; if (!(tif->tif_flags & TIFF_BIGTIFF)) { tif->tif_header.common.tiff_version = TIFF_VERSION_CLASSIC; tif->tif_header.classic.tiff_diroff = 0; - if (tif->tif_flags & TIFF_SWAB) - TIFFSwabShort(&tif->tif_header.common.tiff_version); tif->tif_header_size = sizeof(TIFFHeaderClassic); + /* Swapped copy for writing */ + _TIFFmemcpy(&tif_header_swapped, &tif->tif_header, + sizeof(TIFFHeaderUnion)); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&tif_header_swapped.common.tiff_version); } else { @@ -447,12 +576,15 @@ tif->tif_header.big.tiff_offsetsize = 8; tif->tif_header.big.tiff_unused = 0; tif->tif_header.big.tiff_diroff = 0; + tif->tif_header_size = sizeof(TIFFHeaderBig); + /* Swapped copy for writing */ + _TIFFmemcpy(&tif_header_swapped, &tif->tif_header, + sizeof(TIFFHeaderUnion)); if (tif->tif_flags & TIFF_SWAB) { - TIFFSwabShort(&tif->tif_header.common.tiff_version); - TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize); + TIFFSwabShort(&tif_header_swapped.common.tiff_version); + TIFFSwabShort(&tif_header_swapped.big.tiff_offsetsize); } - tif->tif_header_size = sizeof(TIFFHeaderBig); } /* * The doc for "fopen" for some STD_C_LIBs says that if you @@ -462,27 +594,13 @@ * on Solaris. */ TIFFSeekFile(tif, 0, SEEK_SET); - if (!WriteOK(tif, &tif->tif_header, (tmsize_t)(tif->tif_header_size))) + if (!WriteOK(tif, &tif_header_swapped, + (tmsize_t)(tif->tif_header_size))) { TIFFErrorExtR(tif, name, "Error writing TIFF header"); goto bad; } /* - * Setup the byte order handling. - */ - if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN) - { -#ifndef WORDS_BIGENDIAN - tif->tif_flags |= TIFF_SWAB; -#endif - } - else - { -#ifdef WORDS_BIGENDIAN - tif->tif_flags |= TIFF_SWAB; -#endif - } - /* * Setup default directory. */ if (!TIFFDefaultDirectory(tif)) @@ -490,10 +608,14 @@ tif->tif_diroff = 0; tif->tif_lastdiroff = 0; tif->tif_setdirectory_force_absolute = FALSE; + /* tif_curdircount = 0 means 'empty file opened for writing, but no IFD + * written yet' */ + tif->tif_curdircount = 0; return (tif); } + /* - * Setup the byte order handling. + * Setup the byte order handling according to the opened file for reading. */ if (tif->tif_header.common.tiff_magic != TIFF_BIGENDIAN && tif->tif_header.common.tiff_magic != TIFF_LITTLEENDIAN @@ -619,9 +741,17 @@ * example, it may be broken) and want to proceed to other * directories. I this case we use the TIFF_HEADERONLY flag to open * file and return immediately after reading TIFF header. + * However, the pointer to TIFFSetField() and TIFFGetField() + * (i.e. tif->tif_tagmethods.vsetfield and + * tif->tif_tagmethods.vgetfield) need to be initialized, which is + * done in TIFFDefaultDirectory(). */ if (tif->tif_flags & TIFF_HEADERONLY) + { + if (!TIFFDefaultDirectory(tif)) + goto bad; return (tif); + } /* * Setup initial directory. @@ -764,10 +894,7 @@ /* * Return nonzero if given file is BigTIFF style. */ -int TIFFIsBigTIFF(TIFF *tif) -{ - return (tif->tif_header.common.tiff_version == TIFF_VERSION_BIG); -} +int TIFFIsBigTIFF(TIFF *tif) { return ((tif->tif_flags & TIFF_BIGTIFF) != 0); } /* * Return pointer to file read method.
diff --git a/third_party/libtiff/tif_packbits.c b/third_party/libtiff/tif_packbits.c index 62849f8..1ae50cb 100644 --- a/third_party/libtiff/tif_packbits.c +++ b/third_party/libtiff/tif_packbits.c
@@ -300,6 +300,7 @@ tif->tif_rawcc = cc; if (occ > 0) { + memset(op, 0, (size_t)occ); TIFFErrorExtR(tif, module, "Not enough data for scanline %" PRIu32, tif->tif_row); return (0);
diff --git a/third_party/libtiff/tif_pixarlog.c b/third_party/libtiff/tif_pixarlog.c index 2e22b33..b4c4c9c 100644 --- a/third_party/libtiff/tif_pixarlog.c +++ b/third_party/libtiff/tif_pixarlog.c
@@ -670,8 +670,8 @@ return 1; } -#define DecoderState(tif) ((PixarLogState *)(tif)->tif_data) -#define EncoderState(tif) ((PixarLogState *)(tif)->tif_data) +#define PixarLogDecoderState(tif) ((PixarLogState *)(tif)->tif_data) +#define PixarLogEncoderState(tif) ((PixarLogState *)(tif)->tif_data) static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); @@ -740,7 +740,7 @@ { static const char module[] = "PixarLogSetupDecode"; TIFFDirectory *td = &tif->tif_dir; - PixarLogState *sp = DecoderState(tif); + PixarLogState *sp = PixarLogDecoderState(tif); tmsize_t tbuf_size; uint32_t strip_height; @@ -813,7 +813,7 @@ static int PixarLogPreDecode(TIFF *tif, uint16_t s) { static const char module[] = "PixarLogPreDecode"; - PixarLogState *sp = DecoderState(tif); + PixarLogState *sp = PixarLogDecoderState(tif); (void)s; assert(sp != NULL); @@ -835,7 +835,7 @@ { static const char module[] = "PixarLogDecode"; TIFFDirectory *td = &tif->tif_dir; - PixarLogState *sp = DecoderState(tif); + PixarLogState *sp = PixarLogDecoderState(tif); tmsize_t i; tmsize_t nsamples; int llen; @@ -859,6 +859,7 @@ TIFFErrorExtR(tif, module, "%" PRIu16 " bit input not supported in PixarLog", td->td_bitspersample); + memset(op, 0, (size_t)occ); return 0; } @@ -879,12 +880,14 @@ if (sp->stream.avail_out != nsamples * sizeof(uint16_t)) { TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size"); + memset(op, 0, (size_t)occ); return (0); } /* Check that we will not fill more than what was allocated */ if (sp->tbuf_size < 0 || sp->stream.avail_out > (uInt) sp->tbuf_size) { TIFFErrorExtR(tif, module, "sp->stream.avail_out > sp->tbuf_size"); + memset(op, 0, (size_t)occ); return (0); } do @@ -899,12 +902,14 @@ TIFFErrorExtR( tif, module, "Decoding error at scanline %" PRIu32 ", %s", tif->tif_row, sp->stream.msg ? sp->stream.msg : "(null)"); + memset(op, 0, (size_t)occ); return (0); } if (state != Z_OK) { TIFFErrorExtR(tif, module, "ZLib error: %s", sp->stream.msg ? sp->stream.msg : "(null)"); + memset(op, 0, (size_t)occ); return (0); } } while (sp->stream.avail_out > 0); @@ -916,6 +921,7 @@ "Not enough data at scanline %" PRIu32 " (short %u bytes)", tif->tif_row, sp->stream.avail_out); + memset(op, 0, (size_t)occ); return (0); } @@ -977,6 +983,7 @@ default: TIFFErrorExtR(tif, module, "Unsupported bits/sample: %" PRIu16, td->td_bitspersample); + memset(op, 0, (size_t)occ); return (0); } } @@ -988,7 +995,7 @@ { static const char module[] = "PixarLogSetupEncode"; TIFFDirectory *td = &tif->tif_dir; - PixarLogState *sp = EncoderState(tif); + PixarLogState *sp = PixarLogEncoderState(tif); tmsize_t tbuf_size; assert(sp != NULL); @@ -1038,7 +1045,7 @@ static int PixarLogPreEncode(TIFF *tif, uint16_t s) { static const char module[] = "PixarLogPreEncode"; - PixarLogState *sp = EncoderState(tif); + PixarLogState *sp = PixarLogEncoderState(tif); (void)s; assert(sp != NULL); @@ -1294,7 +1301,7 @@ { static const char module[] = "PixarLogEncode"; TIFFDirectory *td = &tif->tif_dir; - PixarLogState *sp = EncoderState(tif); + PixarLogState *sp = PixarLogEncoderState(tif); tmsize_t i; tmsize_t n; int llen; @@ -1401,7 +1408,7 @@ static int PixarLogPostEncode(TIFF *tif) { static const char module[] = "PixarLogPostEncode"; - PixarLogState *sp = EncoderState(tif); + PixarLogState *sp = PixarLogEncoderState(tif); int state; sp->stream.avail_in = 0;
diff --git a/third_party/libtiff/tif_read.c b/third_party/libtiff/tif_read.c index 4fec839..7efab59 100644 --- a/third_party/libtiff/tif_read.c +++ b/third_party/libtiff/tif_read.c
@@ -105,8 +105,8 @@ TIFFErrorExtR(tif, module, "Invalid buffer size"); return 0; } - new_rawdata = - (uint8_t *)_TIFFrealloc(tif->tif_rawdata, tif->tif_rawdatasize); + new_rawdata = (uint8_t *)_TIFFreallocExt(tif, tif->tif_rawdata, + tif->tif_rawdatasize); if (new_rawdata == 0) { TIFFErrorExtR(tif, module, @@ -464,6 +464,10 @@ if (e) (*tif->tif_postdecode)(tif, (uint8_t *)buf, tif->tif_scanlinesize); } + else + { + memset(buf, 0, (size_t)tif->tif_scanlinesize); + } return (e > 0 ? 1 : -1); } @@ -495,6 +499,11 @@ rowsperstrip = td->td_rowsperstrip; if (rowsperstrip > td->td_imagelength) rowsperstrip = td->td_imagelength; + if (rowsperstrip == 0) + { + TIFFErrorExtR(tif, module, "rowsperstrip is zero"); + return ((tmsize_t)(-1)); + } stripsperplane = TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip); stripinplane = (strip % stripsperplane); @@ -544,7 +553,10 @@ if ((size != (tmsize_t)(-1)) && (size < stripsize)) stripsize = size; if (!TIFFFillStrip(tif, strip)) + { + memset(buf, 0, (size_t)stripsize); return ((tmsize_t)(-1)); + } if ((*tif->tif_decodestrip)(tif, buf, stripsize, plane) <= 0) return ((tmsize_t)(-1)); (*tif->tif_postdecode)(tif, buf, stripsize); @@ -962,9 +974,13 @@ size = tilesize; else if (size > tilesize) size = tilesize; - if (TIFFFillTile(tif, tile) && - (*tif->tif_decodetile)(tif, (uint8_t *)buf, size, - (uint16_t)(tile / td->td_stripsperimage))) + if (!TIFFFillTile(tif, tile)) + { + memset(buf, 0, (size_t)size); + return ((tmsize_t)(-1)); + } + else if ((*tif->tif_decodetile)(tif, (uint8_t *)buf, size, + (uint16_t)(tile / td->td_stripsperimage))) { (*tif->tif_postdecode)(tif, (uint8_t *)buf, size); return (size); @@ -1449,6 +1465,11 @@ tif->tif_flags |= TIFF_CODERSETUP; } tif->tif_curtile = tile; + if (td->td_tilewidth == 0) + { + TIFFErrorExtR(tif, module, "Zero tilewidth"); + return 0; + } howmany32 = TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth); if (howmany32 == 0) { @@ -1545,9 +1566,14 @@ if (TIFFIsTiled(tif)) { - if (!TIFFStartTile(tif, strile) || - !(*tif->tif_decodetile)(tif, (uint8_t *)outbuf, outsize, - (uint16_t)(strile / td->td_stripsperimage))) + if (!TIFFStartTile(tif, strile)) + { + ret = 0; + memset(outbuf, 0, (size_t)outsize); + } + else if (!(*tif->tif_decodetile)( + tif, (uint8_t *)outbuf, outsize, + (uint16_t)(strile / td->td_stripsperimage))) { ret = 0; } @@ -1558,14 +1584,27 @@ uint32_t stripsperplane; if (rowsperstrip > td->td_imagelength) rowsperstrip = td->td_imagelength; - stripsperplane = - TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip); - if (!TIFFStartStrip(tif, strile) || - !(*tif->tif_decodestrip)(tif, (uint8_t *)outbuf, outsize, - (uint16_t)(strile / stripsperplane))) + if (rowsperstrip == 0) { + TIFFErrorExtR(tif, module, "rowsperstrip is zero"); ret = 0; } + else + { + stripsperplane = + TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip); + if (!TIFFStartStrip(tif, strile)) + { + ret = 0; + memset(outbuf, 0, (size_t)outsize); + } + else if (!(*tif->tif_decodestrip)( + tif, (uint8_t *)outbuf, outsize, + (uint16_t)(strile / stripsperplane))) + { + ret = 0; + } + } } if (ret) {
diff --git a/third_party/libtiff/tif_strip.c b/third_party/libtiff/tif_strip.c index 820a254..4dbcf37 100644 --- a/third_party/libtiff/tif_strip.c +++ b/third_party/libtiff/tif_strip.c
@@ -38,6 +38,11 @@ TIFFDirectory *td = &tif->tif_dir; uint32_t strip; + if (td->td_rowsperstrip == 0) + { + TIFFErrorExtR(tif, module, "Cannot compute strip: RowsPerStrip is zero"); + return 0; + } strip = row / td->td_rowsperstrip; if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { @@ -61,6 +66,11 @@ TIFFDirectory *td = &tif->tif_dir; uint32_t nstrips; + if (td->td_rowsperstrip == 0) + { + TIFFWarningExtR(tif, "TIFFNumberOfStrips", "RowsPerStrip is zero"); + return 0; + } nstrips = (td->td_rowsperstrip == (uint32_t)-1 ? 1 : TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip)); @@ -107,7 +117,8 @@ if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && ycbcrsubsampling[0] != 4) || (ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && - ycbcrsubsampling[1] != 4)) + ycbcrsubsampling[1] != 4) || + (ycbcrsubsampling[0] == 0 || ycbcrsubsampling[1] == 0)) { TIFFErrorExtR(tif, module, "Invalid YCbCr subsampling (%dx%d)", ycbcrsubsampling[0], ycbcrsubsampling[1]); @@ -267,7 +278,8 @@ if (((ycbcrsubsampling[0] != 1) && (ycbcrsubsampling[0] != 2) && (ycbcrsubsampling[0] != 4)) || ((ycbcrsubsampling[1] != 1) && (ycbcrsubsampling[1] != 2) && - (ycbcrsubsampling[1] != 4))) + (ycbcrsubsampling[1] != 4)) || + ((ycbcrsubsampling[0] == 0) || (ycbcrsubsampling[1] == 0))) { TIFFErrorExtR(tif, module, "Invalid YCbCr subsampling"); return 0; @@ -287,7 +299,25 @@ else { uint64_t scanline_samples; - scanline_samples = _TIFFMultiply64(tif, td->td_imagewidth, + uint32_t scanline_width = td->td_imagewidth; + +#if 0 + // Tries to fix https://gitlab.com/libtiff/libtiff/-/merge_requests/564 + // but causes regression when decoding legit files with tiffcp -c none + // Cf https://gitlab.com/libtiff/libtiff/-/merge_requests/644 + if (td->td_photometric == PHOTOMETRIC_YCBCR) + { + uint16_t subsampling_hor; + uint16_t ignored; + TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, + &subsampling_hor, &ignored); + if (subsampling_hor > 1) // roundup width for YCbCr + scanline_width = + TIFFroundup_32(scanline_width, subsampling_hor); + } +#endif + + scanline_samples = _TIFFMultiply64(tif, scanline_width, td->td_samplesperpixel, module); scanline_size = TIFFhowmany_64(_TIFFMultiply64(tif, scanline_samples,
diff --git a/third_party/libtiff/tif_thunder.c b/third_party/libtiff/tif_thunder.c index 1f97362..bac0607 100644 --- a/third_party/libtiff/tif_thunder.c +++ b/third_party/libtiff/tif_thunder.c
@@ -82,13 +82,14 @@ return (1); } -static int ThunderDecode(TIFF *tif, uint8_t *op, tmsize_t maxpixels) +static int ThunderDecode(TIFF *tif, uint8_t *op0, tmsize_t maxpixels) { static const char module[] = "ThunderDecode"; register unsigned char *bp; register tmsize_t cc; unsigned int lastpixel; tmsize_t npixels; + uint8_t *op = op0; bp = (unsigned char *)tif->tif_rawcp; cc = tif->tif_rawcc; @@ -107,6 +108,8 @@ * Replicate the last pixel n times, * where n is the lower-order 6 bits. */ + if (n == 0) + break; if (npixels & 1) { op[0] |= lastpixel; @@ -117,11 +120,10 @@ else lastpixel |= lastpixel << 4; npixels += n; - if (npixels < maxpixels) - { - for (; n > 0; n -= 2) - *op++ = (uint8_t)lastpixel; - } + if (npixels > maxpixels) + break; + for (; n > 0; n -= 2) + *op++ = (uint8_t)lastpixel; if (n == -1) *--op &= 0xf0; lastpixel &= 0xf; @@ -154,6 +156,8 @@ tif->tif_rawcc = cc; if (npixels != maxpixels) { + uint8_t *op_end = op0 + (maxpixels + 1) / 2; + memset(op, 0, (size_t)(op_end - op)); TIFFErrorExtR(tif, module, "%s data at scanline %lu (%" PRIu64 " != %" PRIu64 ")", npixels < maxpixels ? "Not enough" : "Too much",
diff --git a/third_party/libtiff/tiffconf.h b/third_party/libtiff/tiffconf.h index 289f175..beba8b8 100644 --- a/third_party/libtiff/tiffconf.h +++ b/third_party/libtiff/tiffconf.h
@@ -175,11 +175,7 @@ /* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian (Intel) */ -#if _FX_ENDIAN_ == _FX_BIG_ENDIAN_ -# define HOST_BIGENDIAN 1 -#else -# define HOST_BIGENDIAN 0 -#endif +#define HOST_BIGENDIAN 0 /* Support CCITT Group 3 & 4 algorithms */ #define CCITT_SUPPORT 1 @@ -213,7 +209,7 @@ /* #undef ZIP_SUPPORT */ /* Support strip chopping (whether or not to convert single-strip uncompressed - images to mutiple strips of ~8Kb to reduce memory usage) */ + images to multiple strips of ~8Kb to reduce memory usage) */ #define STRIPCHOP_DEFAULT TIFF_STRIPCHOP /* Enable SubIFD tag (330) support */
diff --git a/third_party/libtiff/tiffio.h b/third_party/libtiff/tiffio.h index 2046054..225f3c1 100644 --- a/third_party/libtiff/tiffio.h +++ b/third_party/libtiff/tiffio.h
@@ -77,10 +77,6 @@ typedef tmsize_t tsize_t; /* i/o size in bytes */ typedef void *tdata_t; /* image data ref */ -#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32)) -#define __WIN32__ -#endif - /* * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c). @@ -88,7 +84,7 @@ * By default tif_unix.c is assumed. */ -#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) +#if defined(_WIN32) #if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && \ !defined(USE_WIN32_FILEIO) #define AVOID_WIN32_FILEIO @@ -98,11 +94,11 @@ #if defined(USE_WIN32_FILEIO) #define VC_EXTRALEAN #include <windows.h> -#ifdef __WIN32__ +#ifdef _WIN32 DECLARE_HANDLE(thandle_t); /* Win32 file handle */ #else typedef HFILE thandle_t; /* client data handle */ -#endif /* __WIN32__ */ +#endif /* _WIN32 */ #else typedef void *thandle_t; /* client data handle */ #endif /* USE_WIN32_FILEIO */ @@ -311,14 +307,15 @@ /* * Auxiliary functions. */ - +#ifndef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS extern void *_TIFFmalloc(tmsize_t s); extern void *_TIFFcalloc(tmsize_t nmemb, tmsize_t siz); extern void *_TIFFrealloc(void *p, tmsize_t s); + extern void _TIFFfree(void *p); +#endif extern void _TIFFmemset(void *p, int v, tmsize_t c); extern void _TIFFmemcpy(void *d, const void *s, tmsize_t c); extern int _TIFFmemcmp(const void *p1, const void *p2, tmsize_t c); - extern void _TIFFfree(void *p); /* ** Stuff, related to tag handling and creating custom tags. @@ -508,6 +505,9 @@ TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts, tmsize_t max_single_mem_alloc); extern void + TIFFOpenOptionsSetMaxCumulatedMemAlloc(TIFFOpenOptions *opts, + tmsize_t max_cumulated_mem_alloc); + extern void TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts, TIFFErrorHandlerExtR handler, void *errorhandler_user_data); @@ -518,11 +518,11 @@ extern TIFF *TIFFOpen(const char *, const char *); extern TIFF *TIFFOpenExt(const char *, const char *, TIFFOpenOptions *opts); -#ifdef __WIN32__ +#ifdef _WIN32 extern TIFF *TIFFOpenW(const wchar_t *, const char *); extern TIFF *TIFFOpenWExt(const wchar_t *, const char *, TIFFOpenOptions *opts); -#endif /* __WIN32__ */ +#endif /* _WIN32 */ extern TIFF *TIFFFdOpen(int, const char *, const char *); extern TIFF *TIFFFdOpenExt(int, const char *, const char *, TIFFOpenOptions *opts);
diff --git a/third_party/libtiff/tiffiop.h b/third_party/libtiff/tiffiop.h index a7cc12b..d861fd5 100644 --- a/third_party/libtiff/tiffiop.h +++ b/third_party/libtiff/tiffiop.h
@@ -102,6 +102,13 @@ }; typedef struct TIFFOffsetAndDirNumber TIFFOffsetAndDirNumber; +typedef union +{ + TIFFHeaderCommon common; + TIFFHeaderClassic classic; + TIFFHeaderBig big; +} TIFFHeaderUnion; + struct tiff { char *tif_name; /* name of open file */ @@ -153,20 +160,35 @@ TIFFDirectory tif_dir; /* internal rep of current directory */ TIFFDirectory tif_customdir; /* custom IFDs are separated from the main ones */ - union - { - TIFFHeaderCommon common; - TIFFHeaderClassic classic; - TIFFHeaderBig big; - } tif_header; - uint16_t tif_header_size; /* file's header block and its length */ - uint32_t tif_row; /* current scanline */ - tdir_t tif_curdir; /* current directory (index) */ + TIFFHeaderUnion tif_header; /* file's header block Classic/BigTIFF union */ + uint16_t tif_header_size; /* file's header block and its length */ + uint32_t tif_row; /* current scanline */ + + /* There are IFDs in the file and an "active" IFD in memory, + * from which fields are "set" and "get". + * tif_curdir is set to: + * a) TIFF_NON_EXISTENT_DIR_NUMBER if there is no IFD in the file + * or the state is unknown, + * or the last read (i.e. TIFFFetchDirectory()) failed, + * or a custom directory was written. + * b) IFD index of last IFD written in the file. In this case the + * active IFD is a new (empty) one and tif_diroff is zero. + * If writing fails, tif_curdir is not changed. + * c) IFD index of IFD read from file into memory (=active IFD), + * even if IFD is corrupt and TIFFReadDirectory() returns 0. + * Then tif_diroff contains the offset of the IFD in the file. + * d) IFD index 0, whenever a custom directory or an unchained SubIFD + * was read. */ + tdir_t tif_curdir; /* current directory (index) */ + /* tif_curdircount: number of directories (main-IFDs) in file: + * - TIFF_NON_EXISTENT_DIR_NUMBER means 'dont know number of IFDs'. + * - 0 means 'empty file opened for writing, but no IFD written yet' */ + tdir_t tif_curdircount; uint32_t tif_curstrip; /* current strip for read/write */ uint64_t tif_curoff; /* current offset for read/write */ uint64_t tif_lastvalidoff; /* last valid offset allowed for rewrite in place. Used only by TIFFAppendToStrip() */ - uint64_t tif_dataoff; /* current offset for writing dir */ + uint64_t tif_dataoff; /* current offset for writing dir (IFD) */ /* SubIFD support */ uint16_t tif_nsubifd; /* remaining subifds to write */ uint64_t tif_subifdoff; /* offset for patching SubIFD link */ @@ -233,7 +255,9 @@ void *tif_errorhandler_user_data; TIFFErrorHandlerExtR tif_warnhandler; void *tif_warnhandler_user_data; - tmsize_t tif_max_single_mem_alloc; /* in bytes. 0 for unlimited */ + tmsize_t tif_max_single_mem_alloc; /* in bytes. 0 for unlimited */ + tmsize_t tif_max_cumulated_mem_alloc; /* in bytes. 0 for unlimited */ + tmsize_t tif_cur_cumulated_mem_alloc; /* in bytes */ }; struct TIFFOpenOptions @@ -243,6 +267,7 @@ TIFFErrorHandlerExtR warnhandler; /* may be NULL */ void *warnhandler_user_data; /* may be NULL */ tmsize_t max_single_mem_alloc; /* in bytes. 0 for unlimited */ + tmsize_t max_cumulated_mem_alloc; /* in bytes. 0 for unlimited */ }; #define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */ @@ -331,7 +356,7 @@ #define ftell(stream, offset, whence) ftello(stream, offset, whence) #endif #endif -#if defined(__WIN32__) && !(defined(_MSC_VER) && _MSC_VER < 1400) && \ +#if defined(_WIN32) && \ !(defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x800) typedef unsigned int TIFFIOSize_t; #define _TIFF_lseek_f(fildes, offset, whence) \ @@ -437,9 +462,6 @@ extern void *_TIFFCheckRealloc(TIFF *, void *, tmsize_t, tmsize_t, const char *); - extern double _TIFFUInt64ToDouble(uint64_t); - extern float _TIFFUInt64ToFloat(uint64_t); - extern float _TIFFClampDoubleToFloat(double); extern uint32_t _TIFFClampDoubleToUInt32(double);
diff --git a/third_party/libtiff/tiffvers.h b/third_party/libtiff/tiffvers.h index 5741347..3ded6ac 100644 --- a/third_party/libtiff/tiffvers.h +++ b/third_party/libtiff/tiffvers.h
@@ -3,7 +3,7 @@ /* clang-format disabled because FindTIFF.cmake is very sensitive to the * formatting of below line being a single line. */ -#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.6.0\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." +#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.7.0\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc." /* * This define can be used in code that requires * compilation-related definitions specific to a @@ -11,11 +11,11 @@ * version checking should be done based on the * string returned by TIFFGetVersion. */ -#define TIFFLIB_VERSION 20230908 +#define TIFFLIB_VERSION 20240911 /* The following defines have been added in 4.5.0 */ #define TIFFLIB_MAJOR_VERSION 4 -#define TIFFLIB_MINOR_VERSION 6 +#define TIFFLIB_MINOR_VERSION 7 #define TIFFLIB_MICRO_VERSION 0 /* Macro added in 4.5.0. Returns TRUE if the current libtiff version is