Sorry, I'm attaching the debdiff file
--
cheers,
Emmanuel Arias
⢀⣴⠾⠻⢶⣦⠀
⣾⠁⢠⠒⠀⣿⡁ [email protected]
⢿⡄⠘⠷⠚⠋⠀ OpenPGP: 13796755BBC72BB8ABE2AEB5 FA9DEC5DE11C63F1
⠈⠳⣄
diff -Nru tiff-4.7.0/debian/changelog tiff-4.7.0/debian/changelog --- tiff-4.7.0/debian/changelog 2026-07-10 14:34:09.000000000 +0000 +++ tiff-4.7.0/debian/changelog 2026-10-05 21:59:47.000000000 +0000 @@ -1,3 +1,15 @@ +tiff (4.7.0-3+deb13u4) trixie; urgency=medium + + * Non-maintainer upload. + * CVE-2026-52490: Integer overflow in the tiffcrop -S subdivision count + computation, which could lead to out-of-bounds access (Closes: #1147247) + * CVE-2026-18495: fix heap-based buffer overflow caused by + truncation of 64-bit StripByteCounts values in crafted BigTIFF files. + * CVE-2026-36849: denial of service via large SamplesPerPixel tag + (Closes: #1140300). + + -- Emmanuel Arias <[email protected]> Mon, 05 Oct 2026 18:59:47 -0300 + tiff (4.7.0-3+deb13u3) trixie-security; urgency=high * Non-maintainer upload by the Security Team. diff -Nru tiff-4.7.0/debian/libtiff6.symbols tiff-4.7.0/debian/libtiff6.symbols --- tiff-4.7.0/debian/libtiff6.symbols 2026-07-10 14:19:28.000000000 +0000 +++ tiff-4.7.0/debian/libtiff6.symbols 2026-10-05 21:59:47.000000000 +0000 @@ -62,6 +62,7 @@ TIFFGetField@LIBTIFF_4.0 4.0.3 TIFFGetFieldDefaulted@LIBTIFF_4.0 4.0.3 TIFFGetMapFileProc@LIBTIFF_4.0 4.0.3 + TIFFGetMaxCompressionRatio@LIBTIFF_4.5 4.5.0 TIFFGetMode@LIBTIFF_4.0 4.0.3 TIFFGetReadProc@LIBTIFF_4.0 4.0.3 TIFFGetSeekProc@LIBTIFF_4.0 4.0.3 diff -Nru tiff-4.7.0/debian/patches/CVE-2026-18495.patch tiff-4.7.0/debian/patches/CVE-2026-18495.patch --- tiff-4.7.0/debian/patches/CVE-2026-18495.patch 1970-01-01 00:00:00.000000000 +0000 +++ tiff-4.7.0/debian/patches/CVE-2026-18495.patch 2026-10-05 21:59:47.000000000 +0000 @@ -0,0 +1,448 @@ +From: Su Laus <[email protected]> +Date: Tue, 3 Jun 2025 17:47:49 +0000 +Subject: [PATCH] Fixing MSVC compiler warnings in some tools. + +Origin: backport, https://gitlab.com/libtiff/libtiff/-/commit/67fd283d276f09db54dc39b9ef7b979d4b45c4b1 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-18495 +Bug-Freexian-Security: https://security.freexian.com/extended-lts/tracker/CVE-2026-18495 +--- + tools/fax2ps.c | 4 ++- + tools/raw2tiff.c | 8 +++++- + tools/tiff2pdf.c | 88 +++++++++++++++++++++++++++++++++++++++++--------------- + tools/tiff2ps.c | 9 +++--- + tools/tiffcp.c | 65 +++++++++++++++++++++++++++++++++-------- + tools/tiffdump.c | 4 +-- + 6 files changed, 135 insertions(+), 43 deletions(-) + +--- a/tools/fax2ps.c ++++ b/tools/fax2ps.c +@@ -442,7 +442,9 @@ int main(int argc, char **argv) + } + _TIFF_lseek_f(fileno(fd), 0, SEEK_SET); + #if defined(_WIN32) && defined(USE_WIN32_FILEIO) +- tif = TIFFFdOpen(_get_osfhandle(fileno(fd)), "temp", "r"); ++ /* Avoid compiler warnings by using successive casts. */ ++ tif = TIFFFdOpen((int)(intptr_t)(HANDLE)_get_osfhandle(fileno(fd)), ++ "temp", "r"); + #else + tif = TIFFFdOpen(fileno(fd), "temp", "r"); + #endif +--- a/tools/raw2tiff.c ++++ b/tools/raw2tiff.c +@@ -434,7 +434,13 @@ static int guessSize(int fd, TIFFDataTyp + return -1; + } + +- imagesize = (filestat.st_size - hdr_size) / nbands / depth; ++ if (((filestat.st_size - hdr_size) / nbands / depth) > UINT32_MAX) ++ { ++ fprintf(stderr, "Too large image size calculated.\n"); ++ return -1; ++ } ++ else ++ imagesize = (uint32_t)((filestat.st_size - hdr_size) / nbands / depth); + + if (*width != 0 && *length == 0) + { +--- a/tools/tiff2pdf.c ++++ b/tools/tiff2pdf.c +@@ -281,6 +281,31 @@ typedef struct + tsize_t outputwritten; + } T2P; + ++/* This is a helper function. */ ++static uint32_t _TIFFCastSSizeToUInt32(tmsize_t val, const char *module) ++{ ++ if (val < 0) ++ { ++ TIFFError(module, "Unsigned integer underflow (negative)"); ++ return 0; ++ } ++ /* sizeof(tmsize_t) is determined by SIZEOF_SIZE_T */ ++#ifdef SIZEOF_SIZE_T ++#if SIZEOF_SIZE_T > 4 ++ if (val > UINT32_MAX) ++ { ++ TIFFError(module, "Integer overflow"); ++ return 0; ++ } ++#endif ++#else ++#pragma message( \ ++ "---- Error: SIZEOF_SIZE_T not defined. Generate a compile error. ----") ++ SIZEOF_SIZE_T ++#endif ++ return (uint32_t)val; ++} ++ + /* These functions are called by main. */ + + static void usage_info(int); +@@ -2260,7 +2285,8 @@ void t2p_read_tiff_size(T2P *t2p, TIFF * + "Input file %s has short JPEG " + "interchange file byte count", + TIFFFileName(input)); +- t2p->pdf_ojpegiflength = t2p->tiff_datasize; ++ t2p->pdf_ojpegiflength = _TIFFCastSSizeToUInt32( ++ t2p->tiff_datasize, "t2p_read_tiff_size"); + k = checkAdd64(k, t2p->tiff_datasize, t2p); + k = checkAdd64(k, 6, t2p); + k = checkAdd64(k, stripcount, t2p); +@@ -2533,7 +2559,7 @@ tsize_t t2p_readwrite_pdf_image(T2P *t2p + uint64_t *sbc; + unsigned char *stripbuffer; + tsize_t striplength = 0; +- uint32_t max_striplength = 0; ++ uint64_t max_striplength = 0; + #endif /* ifdef JPEG_SUPPORT */ + const char mod[] = "t2p_readwrite_pdf_image()"; + tsize_t tsdummy = 0; +@@ -2797,7 +2823,7 @@ tsize_t t2p_readwrite_pdf_image(T2P *t2p + if (stripbuffer == NULL) + { + TIFFError(TIFF2PDF_MODULE, +- "Can't allocate %" PRId32 ++ "Can't allocate %" PRId64 + " bytes of memory for t2p_readwrite_pdf_image, %s", + max_striplength, TIFFFileName(input)); + _TIFFfree(buffer); +@@ -2883,7 +2909,9 @@ tsize_t t2p_readwrite_pdf_image(T2P *t2p + sepstripcount = TIFFNumberOfStrips(input); + + stripsize = sepstripsize * t2p->tiff_samplesperpixel; +- stripcount = sepstripcount / t2p->tiff_samplesperpixel; ++ stripcount = _TIFFCastSSizeToUInt32(sepstripcount / ++ t2p->tiff_samplesperpixel, ++ "t2p_readwrite_pdf_image"); + + buffer = (unsigned char *)_TIFFmalloc(t2p->tiff_datasize); + if (buffer == NULL) +@@ -3208,7 +3236,7 @@ tsize_t t2p_readwrite_pdf_image_tile(T2P + #ifdef JPEG_SUPPORT + unsigned char *jpt; + float *xfloatp; +- uint32_t xuint32 = 0; ++ tmsize_t xint = 0; + #endif + const char mod[] = "t2p_readwrite_pdf_image_tile()"; + tsize_t tsdummy = 0; +@@ -3392,7 +3420,7 @@ tsize_t t2p_readwrite_pdf_image_tile(T2P + /* Store last 2 bytes of the JpegTables */ + table_end[0] = buffer[bufferoffset - 2]; + table_end[1] = buffer[bufferoffset - 1]; +- xuint32 = bufferoffset; ++ xint = bufferoffset; + bufferoffset -= 2; + retTIFFReadRawTile = TIFFReadRawTile( + input, tile, +@@ -3407,8 +3435,8 @@ tsize_t t2p_readwrite_pdf_image_tile(T2P + bufferoffset += retTIFFReadRawTile; + /* Overwrite SOI marker of image scan with previously */ + /* saved end of JpegTables */ +- buffer[xuint32 - 2] = table_end[0]; +- buffer[xuint32 - 1] = table_end[1]; ++ buffer[xint - 2] = table_end[0]; ++ buffer[xint - 1] = table_end[1]; + } + } + add_t2pWriteFile_check(output, (tdata_t)buffer, bufferoffset, mod, +@@ -6304,17 +6332,20 @@ tsize_t t2p_write_pdf(T2P *t2p, TIFF *in + t2p->pdf_info = 2; + t2p->pdf_pages = 3; + written += t2p_write_pdf_header(t2p, output); +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + t2p->pdf_catalog = t2p->pdf_xrefcount; + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_catalog(t2p, output); + written += t2p_write_pdf_obj_end(output); +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + t2p->pdf_info = t2p->pdf_xrefcount; + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_info(t2p, input, output); + written += t2p_write_pdf_obj_end(output); +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + t2p->pdf_pages = t2p->pdf_xrefcount; + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_pages(t2p, output); +@@ -6327,11 +6358,13 @@ tsize_t t2p_write_pdf(T2P *t2p, TIFF *in + { + return (0); + } +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_page(t2p->pdf_xrefcount, t2p, output); + written += t2p_write_pdf_obj_end(output); +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_stream_dict_start(output); + written += t2p_write_pdf_stream_dict(0, t2p->pdf_xrefcount + 1, output); +@@ -6342,19 +6375,22 @@ tsize_t t2p_write_pdf(T2P *t2p, TIFF *in + streamlen = written - streamlen; + written += t2p_write_pdf_stream_end(output); + written += t2p_write_pdf_obj_end(output); +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_stream_length(streamlen, output); + written += t2p_write_pdf_obj_end(output); + if (t2p->tiff_transferfunctioncount != 0) + { +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_transfer(t2p, output); + written += t2p_write_pdf_obj_end(output); + for (i = 0; i < t2p->tiff_transferfunctioncount; i++) + { +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_stream_dict_start(output); + written += t2p_write_pdf_transfer_dict(t2p, output, i); +@@ -6369,7 +6405,8 @@ tsize_t t2p_write_pdf(T2P *t2p, TIFF *in + } + if ((t2p->pdf_colorspace & T2P_CS_PALETTE) != 0) + { +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + t2p->pdf_palettecs = t2p->pdf_xrefcount; + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_stream_dict_start(output); +@@ -6385,7 +6422,8 @@ tsize_t t2p_write_pdf(T2P *t2p, TIFF *in + } + if ((t2p->pdf_colorspace & T2P_CS_ICCBASED) != 0) + { +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + t2p->pdf_icccs = t2p->pdf_xrefcount; + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_stream_dict_start(output); +@@ -6403,7 +6441,8 @@ tsize_t t2p_write_pdf(T2P *t2p, TIFF *in + for (i2 = 0; i2 < t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount; + i2++) + { +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_stream_dict_start(output); + written += +@@ -6433,7 +6472,8 @@ tsize_t t2p_write_pdf(T2P *t2p, TIFF *in + streamlen = written - streamlen; + written += t2p_write_pdf_stream_end(output); + written += t2p_write_pdf_obj_end(output); +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_stream_length(streamlen, output); + written += t2p_write_pdf_obj_end(output); +@@ -6441,7 +6481,8 @@ tsize_t t2p_write_pdf(T2P *t2p, TIFF *in + } + else + { +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_stream_dict_start(output); + written += t2p_write_pdf_xobject_stream_dict(0, t2p, output); +@@ -6470,13 +6511,14 @@ tsize_t t2p_write_pdf(T2P *t2p, TIFF *in + streamlen = written - streamlen; + written += t2p_write_pdf_stream_end(output); + written += t2p_write_pdf_obj_end(output); +- t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = written; ++ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++] = ++ _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output); + written += t2p_write_pdf_stream_length(streamlen, output); + written += t2p_write_pdf_obj_end(output); + } + } +- t2p->pdf_startxref = written; ++ t2p->pdf_startxref = _TIFFCastSSizeToUInt32(written, "t2p_write_pdf"); + written += t2p_write_pdf_xreftable(t2p, output); + written += t2p_write_pdf_trailer(t2p, output); + t2p_disable(output); +--- a/tools/tiff2ps.c ++++ b/tools/tiff2ps.c +@@ -675,10 +675,12 @@ static const char RGBcolorimage[] = "\ + * + * It is claimed to be part of some future revision of the EPS spec. + */ +-static void PhotoshopBanner(FILE *fd, uint32_t w, uint32_t h, int bs, int nc, +- const char *startline) ++static void PhotoshopBanner(FILE *fd, uint32_t w, uint32_t h, tmsize_t bs, ++ int nc, const char *startline) + { +- fprintf(fd, "%%ImageData: %" PRIu32 " %" PRIu32 " %" PRIu16 " %d 0 %d 2 \"", ++ fprintf(fd, ++ "%%ImageData: %" PRIu32 " %" PRIu32 " %" PRIu16 ++ " %d 0 %" TIFF_SSIZE_FORMAT " 2 \"", + w, h, bitspersample, nc, bs); + fprintf(fd, startline, nc); + fprintf(fd, "\"\n"); +@@ -2694,7 +2696,6 @@ void PSColorContigPreamble(FILE *fd, uin + void PSColorSeparatePreamble(FILE *fd, uint32_t w, uint32_t h, int nc) + { + int i; +- + PhotoshopBanner(fd, w, h, ps_bytesperrow, nc, "true %d colorimage"); + for (i = 0; i < nc; i++) + fprintf(fd, "/line%d %" TIFF_SSIZE_FORMAT " string def\n", i, +--- a/tools/tiffcp.c ++++ b/tools/tiffcp.c +@@ -1096,7 +1096,7 @@ static int tiffcp(TIFF *in, TIFF *out) + TIFFSetField(out, TIFFTAG_NUMBEROFINKS, ninks); + if (TIFFGetField(in, TIFFTAG_INKNAMES, &inknames)) + { +- int inknameslen = strlen(inknames) + 1; ++ size_t inknameslen = strlen(inknames) + 1; + const char *cp = inknames; + while (ninks > 1) + { +@@ -1105,7 +1105,14 @@ static int tiffcp(TIFF *in, TIFF *out) + inknameslen += (strlen(cp) + 1); + ninks--; + } +- TIFFSetField(out, TIFFTAG_INKNAMES, inknameslen, inknames); ++ if (inknameslen <= INT_MAX) ++ TIFFSetField(out, TIFFTAG_INKNAMES, (int)inknameslen, ++ inknames); ++ else ++ TIFFError(TIFFFileName(in), ++ "Error, length of inknames= %" PRIu64 ++ " exceeds size of int ", ++ (uint64_t)inknameslen); + } + } + } +@@ -1544,7 +1551,7 @@ bad: + } + + static void cpStripToTile(uint8_t *out, uint8_t *in, uint32_t rows, +- uint32_t cols, int outskew, int64_t inskew) ++ uint32_t cols, int64_t outskew, int64_t inskew) + { + while (rows-- > 0) + { +@@ -1705,13 +1712,40 @@ done: + return status; + } + ++/* This is a helper function. */ ++static uint32_t _TIFFCastSSizeToUInt32(tmsize_t val, const char *module) ++{ ++ if (val < 0) ++ { ++ TIFFError(module, "Unsigned integer underflow (negative)"); ++ return 0; ++ } ++ /* sizeof(tmsize_t) is determined by SIZEOF_SIZE_T */ ++#ifdef SIZEOF_SIZE_T ++#if SIZEOF_SIZE_T > 4 ++ if (val > UINT32_MAX) ++ { ++ TIFFError(module, "Integer overflow"); ++ return 0; ++ } ++#endif ++#else ++#pragma message( \ ++ "---- Error: SIZEOF_SIZE_T not defined. Generate a compile error. ----") ++ SIZEOF_SIZE_T ++#endif ++ return (uint32_t)val; ++} ++ + DECLAREreadFunc(readContigTilesIntoBuffer) + { + int status = 1; + tsize_t tilesize = TIFFTileSize(in); + tdata_t tilebuf; +- uint32_t imagew = TIFFScanlineSize(in); +- uint32_t tilew = TIFFTileRowSize(in); ++ uint32_t imagew = _TIFFCastSSizeToUInt32(TIFFScanlineSize(in), ++ "readContigTilesIntoBuffer"); ++ uint32_t tilew = _TIFFCastSSizeToUInt32(TIFFTileRowSize(in), ++ "readContigTilesIntoBuffer"); + int64_t iskew = (int64_t)imagew - (int64_t)tilew; + uint8_t *bufp = (uint8_t *)buf; + uint32_t tw, tl; +@@ -1762,8 +1796,10 @@ done: + DECLAREreadFunc(readSeparateTilesIntoBuffer) + { + int status = 1; +- uint32_t imagew = TIFFRasterScanlineSize(in); +- uint32_t tilew = TIFFTileRowSize(in); ++ uint32_t imagew = _TIFFCastSSizeToUInt32(TIFFRasterScanlineSize(in), ++ "readSeparateTilesIntoBuffer"); ++ uint32_t tilew = _TIFFCastSSizeToUInt32(TIFFTileRowSize(in), ++ "readSeparateTilesIntoBuffer"); + int iskew; + tsize_t tilesize = TIFFTileSize(in); + tdata_t tilebuf; +@@ -1942,8 +1978,10 @@ DECLAREwriteFunc(writeBufferToSeparateSt + + DECLAREwriteFunc(writeBufferToContigTiles) + { +- uint32_t imagew = TIFFScanlineSize(out); +- uint32_t tilew = TIFFTileRowSize(out); ++ uint32_t imagew = _TIFFCastSSizeToUInt32(TIFFScanlineSize(out), ++ "writeBufferToContigTiles"); ++ uint32_t tilew = _TIFFCastSSizeToUInt32(TIFFTileRowSize(out), ++ "writeBufferToContigTiles"); + int iskew = imagew - tilew; + tsize_t tilesize = TIFFTileSize(out); + tdata_t obuf; +@@ -1998,9 +2036,12 @@ DECLAREwriteFunc(writeBufferToContigTile + + DECLAREwriteFunc(writeBufferToSeparateTiles) + { +- uint32_t imagew = TIFFScanlineSize(out); +- tsize_t tilew = TIFFTileRowSize(out); +- uint32_t iimagew = TIFFRasterScanlineSize(out); ++ uint32_t imagew = _TIFFCastSSizeToUInt32(TIFFScanlineSize(out), ++ "writeBufferToSeparateTiles"); ++ uint32_t tilew = _TIFFCastSSizeToUInt32(TIFFTileRowSize(out), ++ "writeBufferToSeparateTiles"); ++ uint32_t iimagew = _TIFFCastSSizeToUInt32(TIFFRasterScanlineSize(out), ++ "writeBufferToSeparateTiles"); + int iskew = iimagew - tilew * spp; + tsize_t tilesize = TIFFTileSize(out); + tdata_t obuf; +--- a/tools/tiffdump.c ++++ b/tools/tiffdump.c +@@ -481,7 +481,7 @@ static uint64_t ReadDirectory(int fd, un + } + if (!datafits) + { +- datamem = _TIFFmalloc(datasize); ++ datamem = _TIFFmalloc((tmsize_t)datasize); + if (datamem) + { + if (_TIFF_lseek_f(fd, (_TIFF_off_t)dataoffset, 0) != +@@ -491,7 +491,7 @@ static uint64_t ReadDirectory(int fd, un + _TIFFfree(datamem); + datamem = NULL; + } +- else if (read(fd, datamem, (size_t)datasize) != ++ else if (read(fd, datamem, (unsigned int)datasize) != + (tmsize_t)datasize) + { + Error("Read error accessing tag %u value", tag); diff -Nru tiff-4.7.0/debian/patches/CVE-2026-36849.patch tiff-4.7.0/debian/patches/CVE-2026-36849.patch --- tiff-4.7.0/debian/patches/CVE-2026-36849.patch 1970-01-01 00:00:00.000000000 +0000 +++ tiff-4.7.0/debian/patches/CVE-2026-36849.patch 2026-10-05 21:59:47.000000000 +0000 @@ -0,0 +1,608 @@ +From: Even Rouault <[email protected]> +Date: Tue, 21 Apr 2026 19:52:02 +0200 +Subject: Add TIFFGetMaxCompressionRatio() and use it in + _TIFFReadEncoded[Tile|Strip)AndAllocBuffer() + +```rst + +.. c:function:: uint64_t TIFFGetMaxCompressionRatio(TIFF *tif); + +Description +----------- + +:c:func:`TIFFGetMaxCompressionRatio` returns the maximum compression ratio +for the current codec, which is typically achieved for a uncompressed buffer +with all bytes at zero. + +This function can be used to determine if the compressed size of a strip or tile +is realistic compared to the expected uncompressed size, to prevent some +denial-of-service scenarios. + +Depending on the codec, it may take into account the strip or tile size, +number of samples per pixel, etc. + +Some codecs don't implement that method, or only for a subset of configurations, +and may return 0 when the maximum compression ratio is unknown. + +Return values +------------- + +0 is returned if no maximum compression ratio is known. +1 is returned when there is no compression. +Values strictly bigger than 1 are returned when a maximum compression ratio is +known. +``` + +Fixes #781 + +Origin: backport, https://gitlab.com/libtiff/libtiff/-/commit/eedba405d3695b52faae65994c5904f228eca0bf +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-36849 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-36849 +--- + doc/Makefile.am | 1 + + doc/conf.py | 1 + + doc/functions/TIFFGetMaxCompressionRatio.rst | 40 ++++++++++++++++++++++++++++ + doc/functions/libtiff.rst | 2 ++ + libtiff/libtiff.def | 1 + + libtiff/libtiff.map | 1 + + libtiff/tif_compress.c | 22 +++++++++++++++ + libtiff/tif_fax3.c | 34 +++++++++++++++++++++++ + libtiff/tif_jpeg.c | 25 +++++++++++++++++ + libtiff/tif_lerc.c | 11 ++++++++ + libtiff/tif_lzma.c | 13 +++++++++ + libtiff/tif_lzw.c | 12 +++++++++ + libtiff/tif_packbits.c | 7 +++++ + libtiff/tif_pixarlog.c | 11 ++++++++ + libtiff/tif_read.c | 38 +++++++++++++++++--------- + libtiff/tif_webp.c | 9 +++++++ + libtiff/tif_zip.c | 8 ++++++ + libtiff/tiffio.h | 1 + + libtiff/tiffiop.h | 5 +++- + 19 files changed, 228 insertions(+), 14 deletions(-) + create mode 100644 doc/functions/TIFFGetMaxCompressionRatio.rst + +--- a/doc/Makefile.am ++++ b/doc/Makefile.am +@@ -190,6 +190,7 @@ rst_sources = \ + functions/TIFFReadFromUserBuffer.rst \ + functions/TIFFSetTagExtender.rst \ + functions/TIFFStrileQuery.rst \ ++ functions/TIFFGetMaxCompressionRatio.rst \ + libtiff.rst \ + multi_page.rst \ + images.rst +--- a/doc/conf.py ++++ b/doc/conf.py +@@ -137,6 +137,7 @@ man_pages = [ + ('functions/TIFFFieldWriteCount', 'TIFFFieldWriteCount', 'get number of values to be written to field', author, '3tiff'), + ('functions/TIFFFlush', 'TIFFFlush', 'flush pending writes to an open TIFF file', author, '3tiff'), + ('functions/TIFFGetField', 'TIFFGetField', 'get the value(s) of a tag in an open TIFF file', author, '3tiff'), ++ ('functions/TIFFGetMaxCompressionRatio', 'TIFFGetMaxCompressionRatio', 'return maximum compression ratio for current codec', author, '3tiff'), + ('functions/TIFFmemory', 'TIFFmemory', 'memory management-related functions for use with TIFF files', author, '3tiff'), + ('functions/TIFFMergeFieldInfo', 'TIFFMergeFieldInfo', 'add application-defined TIFF tags to the list of known libtiff tags', author, '3tiff'), + ('functions/TIFFOpen', 'TIFFOpen', 'open a TIFF file for reading or writing', author, '3tiff'), +--- /dev/null ++++ b/doc/functions/TIFFGetMaxCompressionRatio.rst +@@ -0,0 +1,40 @@ ++TIFFGetMaxCompressionRatio ++========================== ++ ++.. versionadded:: 4.7.2 ++ ++Synopsis ++-------- ++ ++.. highlight:: c ++ ++:: ++ ++ #include <tiffio.h> ++ ++.. c:function:: uint64_t TIFFGetMaxCompressionRatio(TIFF *tif); ++ ++Description ++----------- ++ ++:c:func:`TIFFGetMaxCompressionRatio` returns the maximum compression ratio ++for the current codec, which is typically achieved for a uncompressed buffer ++with all bytes at zero. ++ ++This function can be used to determine if the compressed size of a strip or tile ++is realistic compared to the expected uncompressed size, to prevent some ++denial-of-service scenarios. ++ ++Depending on the codec, it may take into account the strip or tile size, ++number of samples per pixel, etc. ++ ++Some codecs don't implement that method, or only for a subset of configurations, ++and may return 0 when the maximum compression ratio is unknown. ++ ++Return values ++------------- ++ ++0 is returned if no maximum compression ratio is known. ++1 is returned when there is no compression. ++Values strictly bigger than 1 are returned when a maximum compression ratio is ++known. +--- a/doc/functions/libtiff.rst ++++ b/doc/functions/libtiff.rst +@@ -257,6 +257,8 @@ will work. + * - :c:func:`TIFFGetFieldDefaulted` + - return tag value in current directory with default value set if the + value is not already set and a default is defined ++ * - :c:func:`TIFFGetMaxCompressionRatio` ++ - return maximum compression ratio for current codec + * - :c:func:`TIFFGetMapFileProc` + - returns a pointer to memory mapping method + * - :c:func:`TIFFGetMode` +--- a/libtiff/libtiff.def ++++ b/libtiff/libtiff.def +@@ -54,6 +54,7 @@ EXPORTS TIFFAccessTagMethods + TIFFGetField + TIFFGetFieldDefaulted + TIFFGetMapFileProc ++ TIFFGetMaxCompressionRatio + TIFFGetMode + TIFFGetReadProc + TIFFGetSeekProc +--- a/libtiff/libtiff.map ++++ b/libtiff/libtiff.map +@@ -213,6 +213,7 @@ LIBTIFF_4.5 { + TIFFOpenOptionsSetMaxSingleMemAlloc; + TIFFOpenOptionsSetErrorHandlerExtR; + TIFFOpenOptionsSetWarningHandlerExtR; ++ TIFFGetMaxCompressionRatio; + } LIBTIFF_4.4; + + LIBTIFF_4.6.1 { +--- a/libtiff/tif_compress.c ++++ b/libtiff/tif_compress.c +@@ -139,6 +139,18 @@ static int _TIFFtrue(TIFF *tif) + } + static void _TIFFvoid(TIFF *tif) { (void)tif; } + ++static uint64_t _TIFFDefaultGetMaxCompressionRatio(TIFF *tif) ++{ ++ (void)tif; ++ return 0; /* unknown */ ++} ++ ++static uint64_t _TIFFGetMaxCompressionRatioOne(TIFF *tif) ++{ ++ (void)tif; ++ return 1; /* no compression */ ++} ++ + void _TIFFSetDefaultCompressionState(TIFF *tif) + { + tif->tif_fixuptags = _TIFFNoFixupTags; +@@ -160,6 +172,7 @@ void _TIFFSetDefaultCompressionState(TIF + tif->tif_cleanup = _TIFFvoid; + tif->tif_defstripsize = _TIFFDefaultStripSize; + tif->tif_deftilesize = _TIFFDefaultTileSize; ++ tif->tif_getmaxcompressionratio = _TIFFDefaultGetMaxCompressionRatio; + tif->tif_flags &= ~(TIFF_NOBITREV | TIFF_NOREADRAW); + } + +@@ -168,6 +181,8 @@ int TIFFSetCompressionScheme(TIFF *tif, + const TIFFCodec *c = TIFFFindCODEC((uint16_t)scheme); + + _TIFFSetDefaultCompressionState(tif); ++ if (scheme == COMPRESSION_NONE) ++ tif->tif_getmaxcompressionratio = _TIFFGetMaxCompressionRatioOne; + /* + * Don't treat an unknown compression scheme as an error. + * This permits applications to open files with data that +@@ -177,6 +192,13 @@ int TIFFSetCompressionScheme(TIFF *tif, + return (c ? (*c->init)(tif, scheme) : 1); + } + ++uint64_t TIFFGetMaxCompressionRatio(TIFF *tif) ++{ ++ if (tif->tif_getmaxcompressionratio) ++ return tif->tif_getmaxcompressionratio(tif); ++ return 0; ++} ++ + /* + * Other compression schemes may be registered. Registered + * schemes can also override the builtin versions provided +--- a/libtiff/tif_fax3.c ++++ b/libtiff/tif_fax3.c +@@ -1439,6 +1439,18 @@ static void Fax3PrintDir(TIFF *tif, FILE + (*sp->printdir)(tif, fd, flags); + } + ++static uint64_t Fax3GetMaxCompressionRatio(TIFF *tif) ++{ ++ (void)tif; ++ /* 1024x1024: 36 */ ++ /* 4096x4096: 100 */ ++ /* 16383x16383: 163 */ ++ /* 65536x65536: 200 */ ++ /* 200000x200000: 208 */ ++ ++ return 250; ++} ++ + static int InitCCITTFax3(TIFF *tif) + { + static const char module[] = "InitCCITTFax3"; +@@ -1503,6 +1515,7 @@ static int InitCCITTFax3(TIFF *tif) + tif->tif_encodetile = Fax3Encode; + tif->tif_close = Fax3Close; + tif->tif_cleanup = Fax3Cleanup; ++ tif->tif_getmaxcompressionratio = Fax3GetMaxCompressionRatio; + + return (1); + } +@@ -1658,6 +1671,12 @@ static int Fax4PostEncode(TIFF *tif) + return (1); + } + ++static uint64_t Fax4GetMaxCompressionRatio(TIFF *tif) ++{ ++ return isTiled(tif) ? tif->tif_dir.td_tilewidth ++ : tif->tif_dir.td_imagewidth; ++} ++ + int TIFFInitCCITTFax4(TIFF *tif, int scheme) + { + (void)scheme; +@@ -1680,6 +1699,7 @@ int TIFFInitCCITTFax4(TIFF *tif, int sch + tif->tif_encodestrip = Fax4Encode; + tif->tif_encodetile = Fax4Encode; + tif->tif_postencode = Fax4PostEncode; ++ tif->tif_getmaxcompressionratio = Fax4GetMaxCompressionRatio; + /* + * Suppress RTC at the end of each strip. + */ +@@ -1749,6 +1769,18 @@ static int Fax3DecodeRLE(TIFF *tif, uint + return (1); + } + ++static uint64_t Fax3RLEGetMaxCompressionRatio(TIFF *tif) ++{ ++ (void)tif; ++ /* 1024x1024: 43 */ ++ /* 4096x4096: 128 */ ++ /* 16383x16383: 171 */ ++ /* 65536x65536: 205 */ ++ /* 200000x200000: 211 */ ++ ++ return 250; ++} ++ + int TIFFInitCCITTRLE(TIFF *tif, int scheme) + { + (void)scheme; +@@ -1757,6 +1789,7 @@ int TIFFInitCCITTRLE(TIFF *tif, int sche + tif->tif_decoderow = Fax3DecodeRLE; + tif->tif_decodestrip = Fax3DecodeRLE; + tif->tif_decodetile = Fax3DecodeRLE; ++ tif->tif_getmaxcompressionratio = Fax3RLEGetMaxCompressionRatio; + /* + * Suppress RTC+EOLs when encoding and byte-align data. + */ +@@ -1775,6 +1808,7 @@ int TIFFInitCCITTRLEW(TIFF *tif, int sch + tif->tif_decoderow = Fax3DecodeRLE; + tif->tif_decodestrip = Fax3DecodeRLE; + tif->tif_decodetile = Fax3DecodeRLE; ++ tif->tif_getmaxcompressionratio = Fax3RLEGetMaxCompressionRatio; + /* + * Suppress RTC+EOLs when encoding and word-align data. + */ +--- a/libtiff/tif_jpeg.c ++++ b/libtiff/tif_jpeg.c +@@ -2775,6 +2775,30 @@ static int JPEGInitializeLibJPEG(TIFF *t + return 1; + } + ++static uint64_t JPEGGetMaxCompressionRatio(TIFF *tif) ++{ ++ JPEGState *sp = JState(tif); ++ if ((tif->tif_dir.td_photometric == PHOTOMETRIC_YCBCR) && ++ (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG) && ++ (tif->tif_dir.td_samplesperpixel == 3)) ++ { ++ if (sp->h_sampling == 2 && sp->v_sampling == 2) ++ { ++ if (tif->tif_dir.td_bitspersample == 12) ++ return 768; ++ else ++ return 512; ++ } ++ ++ return 0; /* unknown */ ++ } ++ ++ if (tif->tif_dir.td_bitspersample == 12) ++ return 384; ++ else ++ return 256; ++} ++ + /* Common to tif_jpeg.c and tif_jpeg_12.c */ + static void TIFFInitJPEGCommon(TIFF *tif) + { +@@ -2811,6 +2835,7 @@ static void TIFFInitJPEGCommon(TIFF *tif + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; ++ tif->tif_getmaxcompressionratio = JPEGGetMaxCompressionRatio; + tif->tif_cleanup = JPEGCleanup; + + tif->tif_defstripsize = JPEGDefaultStripSize; +--- a/libtiff/tif_lerc.c ++++ b/libtiff/tif_lerc.c +@@ -1475,6 +1475,16 @@ static int LERCVGetField(TIFF *tif, uint + return 1; + } + ++static uint64_t LERCGetMaxCompressionRatio(TIFF *tif) ++{ ++ (void)tif; ++ ++ /* LERC compression ratio can grow to several millions */ ++ /* eg. 5703725 for Lerc deflate on 16383x16383 array */ ++ /* or 3829644 for regular Lerc */ ++ return 0; ++} ++ + int TIFFInitLERC(TIFF *tif, int scheme) + { + static const char module[] = "TIFFInitLERC"; +@@ -1523,6 +1533,7 @@ int TIFFInitLERC(TIFF *tif, int scheme) + tif->tif_encoderow = LERCEncode; + tif->tif_encodestrip = LERCEncode; + tif->tif_encodetile = LERCEncode; ++ tif->tif_getmaxcompressionratio = LERCGetMaxCompressionRatio; + tif->tif_cleanup = LERCCleanup; + + /* Default values for codec-specific fields */ +--- a/libtiff/tif_lzma.c ++++ b/libtiff/tif_lzma.c +@@ -455,6 +455,17 @@ static const TIFFField lzmaFields[] = { + "LZMA2 Compression Preset", NULL}, + }; + ++static uint64_t LZMAGetMaxCompressionRatio(TIFF *tif) ++{ ++ (void)tif; ++ /* 1024x1024: 3800 */ ++ /* 4096x4096: 6534 */ ++ /* 16383x16383: 6846 */ ++ /* 65536x65536: 6874 */ ++ ++ return 7000; ++} ++ + int TIFFInitLZMA(TIFF *tif, int scheme) + { + static const char module[] = "TIFFInitLZMA"; +@@ -530,6 +541,8 @@ int TIFFInitLZMA(TIFF *tif, int scheme) + tif->tif_encodestrip = LZMAEncode; + tif->tif_encodetile = LZMAEncode; + tif->tif_cleanup = LZMACleanup; ++ tif->tif_getmaxcompressionratio = LZMAGetMaxCompressionRatio; ++ + /* + * Setup predictor setup. + */ +--- a/libtiff/tif_lzw.c ++++ b/libtiff/tif_lzw.c +@@ -1391,6 +1391,17 @@ static void LZWCleanup(TIFF *tif) + _TIFFSetDefaultCompressionState(tif); + } + ++static uint64_t LZWGetMaxCompressionRatio(TIFF *tif) ++{ ++ (void)tif; ++ /* 1024x1024: 562 */ ++ /* 4096x4096: 1243 */ ++ /* 16383x16383: 1353 */ ++ /* 65536x65536: 1362 */ ++ ++ return 1400; ++} ++ + int TIFFInitLZW(TIFF *tif, int scheme) + { + static const char module[] = "TIFFInitLZW"; +@@ -1422,6 +1433,7 @@ int TIFFInitLZW(TIFF *tif, int scheme) + tif->tif_encoderow = LZWEncode; + tif->tif_encodestrip = LZWEncode; + tif->tif_encodetile = LZWEncode; ++ tif->tif_getmaxcompressionratio = LZWGetMaxCompressionRatio; + tif->tif_cleanup = LZWCleanup; + /* + * Setup predictor setup. +--- a/libtiff/tif_packbits.c ++++ b/libtiff/tif_packbits.c +@@ -308,6 +308,12 @@ static int PackBitsDecode(TIFF *tif, uin + return (1); + } + ++static uint64_t PackBitsGetMaxCompressionRatio(TIFF *tif) ++{ ++ (void)tif; ++ return 64; ++} ++ + int TIFFInitPackBits(TIFF *tif, int scheme) + { + (void)scheme; +@@ -319,6 +325,7 @@ int TIFFInitPackBits(TIFF *tif, int sche + tif->tif_encoderow = PackBitsEncode; + tif->tif_encodestrip = PackBitsEncodeChunk; + tif->tif_encodetile = PackBitsEncodeChunk; ++ tif->tif_getmaxcompressionratio = PackBitsGetMaxCompressionRatio; + return (1); + } + #endif /* PACKBITS_SUPPORT */ +--- a/libtiff/tif_pixarlog.c ++++ b/libtiff/tif_pixarlog.c +@@ -1655,6 +1655,16 @@ static const TIFFField pixarlogFields[] + {TIFFTAG_PIXARLOGQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, FALSE, FALSE, "", NULL}}; + ++static uint64_t PixarLogGetMaxCompressionRatio(TIFF *tif) ++{ ++ (void)tif; ++ /* cf https://zlib.net/zlib_tech.html */ ++ const uint64_t MAX_DEFLATE_RATIO = 1032; ++ ++ /* security margin as I don't understand what this codec does */ ++ return MAX_DEFLATE_RATIO * (uint64_t)4; ++} ++ + int TIFFInitPixarLog(TIFF *tif, int scheme) + { + static const char module[] = "TIFFInitPixarLog"; +@@ -1702,6 +1712,7 @@ int TIFFInitPixarLog(TIFF *tif, int sche + tif->tif_encodetile = PixarLogEncode; + tif->tif_close = PixarLogClose; + tif->tif_cleanup = PixarLogCleanup; ++ tif->tif_getmaxcompressionratio = PixarLogGetMaxCompressionRatio; + + /* Override SetField so we can handle our private pseudo-tag */ + sp->vgetparent = tif->tif_tagmethods.vgetfield; +--- a/libtiff/tif_read.c ++++ b/libtiff/tif_read.c +@@ -596,13 +596,32 @@ tmsize_t _TIFFReadEncodedStripAndAllocBu + if (!TIFFFillStrip(tif, strip)) + return ((tmsize_t)(-1)); + +- *buf = _TIFFmallocExt(tif, bufsizetoalloc); ++ /* Sanity checks to avoid excessive memory allocation */ ++ /* Max compression ratio experimentally determined. Might be fragile... ++ * Only apply this heuristics to situations where the memory allocation ++ * would be big, to avoid breaking nominal use cases. ++ */ ++ const uint64_t maxCompressionRatio = TIFFGetMaxCompressionRatio(tif); ++ if (maxCompressionRatio > 0 && bufsizetoalloc > 100 * 1000 * 1000 && ++ (uint64_t)tif->tif_rawdatasize < ++ (uint64_t)this_stripsize / maxCompressionRatio) ++ { ++ TIFFErrorExtR(tif, TIFFFileName(tif), ++ "Likely invalid strip byte count for strip %u. " ++ "Uncompressed strip size is %" PRIu64 ", " ++ "compressed one is %" PRIu64, ++ strip, (uint64_t)this_stripsize, ++ (uint64_t)tif->tif_rawdatasize); ++ return ((tmsize_t)(-1)); ++ } ++ ++ ++ *buf = _TIFFcallocExt(tif, 1, bufsizetoalloc); + if (*buf == NULL) + { + TIFFErrorExtR(tif, TIFFFileName(tif), "No space for strip buffer"); + return ((tmsize_t)(-1)); + } +- _TIFFmemset(*buf, 0, bufsizetoalloc); + + if ((*tif->tif_decodestrip)(tif, *buf, this_stripsize, plane) <= 0) + return ((tmsize_t)(-1)); +@@ -1065,17 +1084,10 @@ tmsize_t _TIFFReadEncodedTileAndAllocBuf + * Only apply this heuristics to situations where the memory allocation + * would be big, to avoid breaking nominal use cases. + */ +- const int maxCompressionRatio = +- td->td_compression == COMPRESSION_ZSTD ? 33000 +- : td->td_compression == COMPRESSION_JXL +- ? +- /* Evaluated on a 8000x8000 tile */ +- 25000 * (td->td_planarconfig == PLANARCONFIG_CONTIG +- ? td->td_samplesperpixel +- : 1) +- : td->td_compression == COMPRESSION_LZMA ? 7000 : 1000; +- if (bufsizetoalloc > 100 * 1000 * 1000 && +- tif->tif_rawdatasize < tilesize / maxCompressionRatio) ++ const uint64_t maxCompressionRatio = TIFFGetMaxCompressionRatio(tif); ++ if (maxCompressionRatio > 0 && bufsizetoalloc > 100 * 1000 * 1000 && ++ (uint64_t)tif->tif_rawdatasize < ++ (uint64_t)tilesize / maxCompressionRatio) + { + TIFFErrorExtR(tif, TIFFFileName(tif), + "Likely invalid tile byte count for tile %u. " +--- a/libtiff/tif_webp.c ++++ b/libtiff/tif_webp.c +@@ -846,6 +846,14 @@ static const TIFFField TWebPFields[] = { + NULL}, + }; + ++static uint64_t TWebPGetMaxCompressionRatio(TIFF *tif) ++{ ++ /* lossy compression: */ ++ /* return (tif->tif_dir.td_samplesperpixel == 4) ? 2199 : 1685; */ ++ /* lossless compression: */ ++ return (tif->tif_dir.td_samplesperpixel == 4) ? 104194 : 78146; ++} ++ + int TIFFInitWebP(TIFF *tif, int scheme) + { + static const char module[] = "TIFFInitWebP"; +@@ -909,6 +917,7 @@ int TIFFInitWebP(TIFF *tif, int scheme) + tif->tif_encodestrip = TWebPEncode; + tif->tif_encodetile = TWebPEncode; + tif->tif_cleanup = TWebPCleanup; ++ tif->tif_getmaxcompressionratio = TWebPGetMaxCompressionRatio; + + return 1; + bad: +--- a/libtiff/tif_zip.c ++++ b/libtiff/tif_zip.c +@@ -678,6 +678,13 @@ static const TIFFField zipFields[] = { + TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL}, + }; + ++static uint64_t ZIPGetMaxCompressionRatio(TIFF *tif) ++{ ++ (void)tif; ++ /* cf https://zlib.net/zlib_tech.html */ ++ return 1032; ++} ++ + int TIFFInitZIP(TIFF *tif, int scheme) + { + static const char module[] = "TIFFInitZIP"; +@@ -744,6 +751,7 @@ int TIFFInitZIP(TIFF *tif, int scheme) + tif->tif_encodestrip = ZIPEncode; + tif->tif_encodetile = ZIPEncode; + tif->tif_cleanup = ZIPCleanup; ++ tif->tif_getmaxcompressionratio = ZIPGetMaxCompressionRatio; + /* + * Setup predictor setup. + */ +--- a/libtiff/tiffio.h ++++ b/libtiff/tiffio.h +@@ -566,6 +566,7 @@ extern int TIFFReadRGBAImageOriented(TIF + tmsize_t cc); + extern tmsize_t TIFFWriteRawTile(TIFF *tif, uint32_t tile, void *data, + tmsize_t cc); ++ extern uint64_t TIFFGetMaxCompressionRatio(TIFF *tif); + extern int TIFFDataWidth( + TIFFDataType); /* table of tag datatype widths within TIFF file. */ + extern void TIFFSetWriteOffset(TIFF *tif, toff_t off); +--- a/libtiff/tiffiop.h ++++ b/libtiff/tiffiop.h +@@ -94,6 +94,7 @@ typedef int (*TIFFSeekMethod)(TIFF *, ui + typedef void (*TIFFPostMethod)(TIFF *tif, uint8_t *buf, tmsize_t size); + typedef uint32_t (*TIFFStripMethod)(TIFF *, uint32_t); + typedef void (*TIFFTileMethod)(TIFF *, uint32_t *, uint32_t *); ++typedef uint64_t (*TIFFGetMaxCompressionRatioMethod)(TIFF *); + + struct TIFFOffsetAndDirNumber + { +@@ -216,7 +217,9 @@ struct tiff + TIFFVoidMethod tif_cleanup; /* cleanup state routine */ + TIFFStripMethod tif_defstripsize; /* calculate/constrain strip size */ + TIFFTileMethod tif_deftilesize; /* calculate/constrain tile size */ +- uint8_t *tif_data; /* compression scheme private data */ ++ /* returns maximum compression ratio for current compression method */ ++ TIFFGetMaxCompressionRatioMethod tif_getmaxcompressionratio; ++ uint8_t *tif_data; /* compression scheme private data */ + /* input/output buffering */ + tmsize_t tif_scanlinesize; /* # of bytes in a scanline */ + tmsize_t tif_scanlineskew; /* scanline skew for reading strips */ diff -Nru tiff-4.7.0/debian/patches/CVE-2026-52490.patch tiff-4.7.0/debian/patches/CVE-2026-52490.patch --- tiff-4.7.0/debian/patches/CVE-2026-52490.patch 1970-01-01 00:00:00.000000000 +0000 +++ tiff-4.7.0/debian/patches/CVE-2026-52490.patch 2026-10-05 21:59:47.000000000 +0000 @@ -0,0 +1,138 @@ +From: waugustus <[email protected]> +Date: Fri, 12 Jun 2026 15:40:11 +0800 +Subject: Harden integer size and offset calculations in libtiff, tools, and + contrib + +Backport only the tiffcrop -S subdivision count hardening, which is the +part addressing CVE-2026-52490. The row/column zero and division based +MAX_SECTIONS guards come from the earlier upstream commits e12d1cf7 and +2f0509b0, which this change builds on. _TIFFCastUInt64ToUInt32() does not +exist in 4.5.0, so the uint64_t product is checked against UINT32_MAX +directly instead. + +Origin: backport, https://gitlab.com/libtiff/libtiff/-/commit/b04e935cb6242f22cc8b63c99a372cf3ea825e4e +Bug-Debian: https://bugs.debian.org/1147247 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-52490 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-52490 +--- +--- a/tools/tiffcrop.c ++++ b/tools/tiffcrop.c +@@ -458,6 +458,7 @@ struct pagedef + uint16_t res_unit; /* resolution unit for output image */ + unsigned int rows; /* number of section rows */ + unsigned int cols; /* number of section cols */ ++ uint32_t total_sections; + unsigned int orient; /* portrait, landscape, seascape, auto */ + }; + +@@ -2395,18 +2396,29 @@ void process_command_opts(int argc, char + page->cols = atoi(optarg); + page->rows = atoi(optarg); + } +- if ((page->cols * page->rows) > MAX_SECTIONS) ++ if ((page->cols == 0) || (page->rows == 0)) ++ { ++ TIFFError("Invalid subdivisions", ++ "Rows and columns must be non-zero"); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (page->cols > (MAX_SECTIONS / page->rows)) + { + TIFFError( + "Limit for subdivisions, ie rows x columns, exceeded", + "%d", MAX_SECTIONS); + exit(EXIT_FAILURE); + } +- if ((page->cols * page->rows) < 1) + { +- TIFFError("No subdivisions", "%d", +- (page->cols * page->rows)); +- exit(EXIT_FAILURE); ++ uint64_t total_sections64 = ++ (uint64_t)page->cols * (uint64_t)page->rows; ++ if (total_sections64 == 0 || total_sections64 > UINT32_MAX) ++ { ++ TIFFError("No subdivisions", "%u", 0U); ++ exit(EXIT_FAILURE); ++ } ++ page->total_sections = (uint32_t)total_sections64; + } + page->mode |= PAGE_MODE_ROWSCOLS; + break; +@@ -5727,6 +5739,7 @@ static void initPageSetup(struct pagedef + page->vmargin = 0.0; + page->rows = 0; + page->cols = 0; ++ page->total_sections = 0; + page->orient = ORIENTATION_NONE; + + for (i = 0; i < MAX_SECTIONS; i++) +@@ -6786,13 +6799,23 @@ static int computeOutputPixelOffsets(str + + line_bytes = TIFFhowmany8(owidth * image->spp * image->bps); + +- if ((orows * ocols) > MAX_SECTIONS) ++ if ((orows == 0) || (ocols == 0) || (ocols > (MAX_SECTIONS / orows))) + { + TIFFError("computeOutputPixelOffsets", + "Rows and Columns exceed maximum sections\nIncrease " + "resolution or reduce sections"); + return (-1); + } ++ { ++ uint64_t total_sections64 = (uint64_t)orows * (uint64_t)ocols; ++ if (total_sections64 == 0 || total_sections64 > UINT32_MAX) ++ { ++ TIFFError("computeOutputPixelOffsets", ++ "Integer overflow computing subdivision count"); ++ return (-1); ++ } ++ page->total_sections = (uint32_t)total_sections64; ++ } + + /* build the list of offsets for each output section */ + for (k = 0, i = 0; i < orows; i++) +@@ -6813,7 +6836,7 @@ static int computeOutputPixelOffsets(str + sections[k].y2 = y2; + sections[k].buffsize = line_bytes * olength; + sections[k].position = k + 1; +- sections[k].total = orows * ocols; ++ sections[k].total = (int)page->total_sections; + } + } + return (0); +@@ -8180,10 +8203,32 @@ static int writeImageSections(TIFF *in, + uint32_t i, k, width, length, sectsize; + unsigned char *sect_buff = *sect_buff_ptr; + ++ if ((page->cols == 0) || (page->rows == 0)) ++ { ++ TIFFError("Invalid subdivisions", "Rows and columns must be non-zero"); ++ return (-1); ++ } ++ ++ if (page->cols > (MAX_SECTIONS / page->rows)) ++ { ++ TIFFError("writeImageSections", ++ "Rows and Columns exceed maximum sections\n" ++ "Increase resolution or reduce sections"); ++ return (-1); ++ } ++ if (page->total_sections == 0) ++ { ++ uint64_t total_sections64 = ++ (uint64_t)page->cols * (uint64_t)page->rows; ++ if (total_sections64 == 0 || total_sections64 > UINT32_MAX) ++ return (-1); ++ page->total_sections = (uint32_t)total_sections64; ++ } ++ + hres = page->hres; + vres = page->vres; + +- k = page->cols * page->rows; ++ k = page->total_sections; + if ((k < 1) || (k > MAX_SECTIONS)) + { + TIFFError("writeImageSections", diff -Nru tiff-4.7.0/debian/patches/series tiff-4.7.0/debian/patches/series --- tiff-4.7.0/debian/patches/series 2026-07-10 14:33:30.000000000 +0000 +++ tiff-4.7.0/debian/patches/series 2026-10-05 21:59:47.000000000 +0000 @@ -8,3 +8,6 @@ pixarlog-add-comment-explaining-4-byte-advance-in-AB.patch pixarlog-complete-ABGR-bounds-check-for-multi-row-st.patch pixarlog-error-out-on-invalid-ABGR-output-buffer-siz.patch +CVE-2026-52490.patch +CVE-2026-18495.patch +CVE-2026-36849.patch
signature.asc
Description: PGP signature

