From 4fe58e22314f2b822bf9f171c10d3bf925975730 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Sat, 4 Jul 2026 08:30:40 -0400 Subject: [PATCH] fix(tiff): fix heap overflow unpacking sub-8-bit contig CMYK samples We had missed a case where bit_convert needed outputs to go to the scratch buffer: PHOTOMETRIC_SEPARATED, but not requesting raw color. (Because the real number of channels differ from what we are presenting to the caller.) Assisted-by: Claude Code / Sonnet 5 Signed-off-by: Larry Gritz --- src/tiff.imageio/tiffinput.cpp | 9 ++++++--- testsuite/tiff-misc/ref/out-libtiff403-b.txt | 17 +++++++++++++++++ testsuite/tiff-misc/ref/out-libtiff403-c.txt | 17 +++++++++++++++++ testsuite/tiff-misc/ref/out-libtiff403.txt | 17 +++++++++++++++++ testsuite/tiff-misc/ref/out-libtiff409.txt | 17 +++++++++++++++++ testsuite/tiff-misc/ref/out-libtiff410.txt | 17 +++++++++++++++++ testsuite/tiff-misc/ref/out-libtiff430.txt | 17 +++++++++++++++++ testsuite/tiff-misc/ref/out-libtiff470-b.txt | 17 +++++++++++++++++ testsuite/tiff-misc/ref/out-libtiff470-c.txt | 17 +++++++++++++++++ testsuite/tiff-misc/ref/out-libtiff470.txt | 17 +++++++++++++++++ testsuite/tiff-misc/ref/out.txt | 17 +++++++++++++++++ testsuite/tiff-misc/run.py | 8 ++++++++ testsuite/tiff-misc/src/crash-cmyk-1bit.tif | Bin 0 -> 13733 bytes 13 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 testsuite/tiff-misc/src/crash-cmyk-1bit.tif diff --git a/src/tiff.imageio/tiffinput.cpp b/src/tiff.imageio/tiffinput.cpp index 2a0ccf5ed2..636c4b4547 100644 --- a/src/tiff.imageio/tiffinput.cpp +++ b/src/tiff.imageio/tiffinput.cpp @@ -2048,6 +2048,9 @@ TIFFInput::read_native_scanline_locked(int subimage, int miplevel, int y, } // Handle less-than-full bit depths + bool use_scratch_dest = m_separate + || (m_photometric == PHOTOMETRIC_SEPARATED + && !m_raw_color); if (m_bitspersample < 8) { // m_scratch now holds nvals n-bit values, contig or separate m_scratch2.resize(input_bytes); @@ -2055,7 +2058,7 @@ TIFFInput::read_native_scanline_locked(int subimage, int miplevel, int y, for (int c = 0; c < planes; ++c) /* planes==1 for contig */ bit_convert(m_separate ? m_spec.width : nvals, &m_scratch2[plane_bytes * c], m_bitspersample, - m_separate + use_scratch_dest ? &m_scratch[plane_bytes * c] : (unsigned char*)data.data() + plane_bytes * c, 8); @@ -2066,7 +2069,7 @@ TIFFInput::read_native_scanline_locked(int subimage, int miplevel, int y, for (int c = 0; c < planes; ++c) /* planes==1 for contig */ bit_convert(m_separate ? m_spec.width : nvals, &m_scratch2[plane_bytes * c], m_bitspersample, - m_separate + use_scratch_dest ? &m_scratch[plane_bytes * c] : (unsigned char*)data.data() + plane_bytes * c, 16); @@ -2077,7 +2080,7 @@ TIFFInput::read_native_scanline_locked(int subimage, int miplevel, int y, for (int c = 0; c < planes; ++c) /* planes==1 for contig */ bit_convert(m_separate ? m_spec.width : nvals, &m_scratch2[plane_bytes * c], m_bitspersample, - m_separate + use_scratch_dest ? &m_scratch[plane_bytes * c] : (unsigned char*)data.data() + plane_bytes * c, 32); diff --git a/testsuite/tiff-misc/ref/out-libtiff403-b.txt b/testsuite/tiff-misc/ref/out-libtiff403-b.txt index 8495a831fb..64188cf31d 100644 --- a/testsuite/tiff-misc/ref/out-libtiff403-b.txt +++ b/testsuite/tiff-misc/ref/out-libtiff403-b.txt @@ -41,5 +41,22 @@ gps.tif : 64 x 64, 3 channel, uint8 tiff tiff:RowsPerStrip: 32 iconvert ERROR copying "src/crash-cmyk-e12b.tif" to "out.tif" : Decoding error at scanline 0, invalid distance too far back +Reading src/crash-cmyk-1bit.tif +src/crash-cmyk-1bit.tif : 73 x 43, 3 channel, uint1 tiff + SHA-1: 7E9169CEC1B8ABD56C3604AAD37761DBD8FE0F2A + channel list: R, G, B + compression: "none" + DocumentName: "flower-separated-contig-08.tif" + Orientation: 1 (normal) + planarconfig: "contig" + ResolutionUnit: "in" + XResolution: 0 + YResolution: 72 + oiio:BitsPerSample: 1 + tiff:ColorSpace: "CMYK" + tiff:Compression: 1 + tiff:PhotometricInterpretation: 5 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 28 Comparing "check1.tif" and "ref/check1.tif" PASS diff --git a/testsuite/tiff-misc/ref/out-libtiff403-c.txt b/testsuite/tiff-misc/ref/out-libtiff403-c.txt index bcc10ab221..0add5ff244 100644 --- a/testsuite/tiff-misc/ref/out-libtiff403-c.txt +++ b/testsuite/tiff-misc/ref/out-libtiff403-c.txt @@ -41,5 +41,22 @@ gps.tif : 64 x 64, 3 channel, uint8 tiff tiff:RowsPerStrip: 32 iconvert ERROR copying "src/crash-cmyk-e12b.tif" to "out.tif" : Decoding error at scanline 0, invalid distance too far back +Reading src/crash-cmyk-1bit.tif +src/crash-cmyk-1bit.tif : 73 x 43, 3 channel, uint1 tiff + SHA-1: 7E9169CEC1B8ABD56C3604AAD37761DBD8FE0F2A + channel list: R, G, B + compression: "none" + DocumentName: "flower-separated-contig-08.tif" + Orientation: 1 (normal) + planarconfig: "contig" + ResolutionUnit: "in" + XResolution: 0 + YResolution: 72 + oiio:BitsPerSample: 1 + tiff:ColorSpace: "CMYK" + tiff:Compression: 1 + tiff:PhotometricInterpretation: 5 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 28 Comparing "check1.tif" and "ref/check1.tif" PASS diff --git a/testsuite/tiff-misc/ref/out-libtiff403.txt b/testsuite/tiff-misc/ref/out-libtiff403.txt index 06ddff8181..643ca1b8cf 100644 --- a/testsuite/tiff-misc/ref/out-libtiff403.txt +++ b/testsuite/tiff-misc/ref/out-libtiff403.txt @@ -41,5 +41,22 @@ gps.tif : 64 x 64, 3 channel, uint8 tiff tiff:RowsPerStrip: 32 iconvert ERROR copying "src/crash-cmyk-e12b.tif" to "out.tif" : Decoding error at scanline 0, invalid distance too far back +Reading src/crash-cmyk-1bit.tif +src/crash-cmyk-1bit.tif : 73 x 43, 3 channel, uint1 tiff + SHA-1: 7E9169CEC1B8ABD56C3604AAD37761DBD8FE0F2A + channel list: R, G, B + compression: "none" + DocumentName: "flower-separated-contig-08.tif" + Orientation: 1 (normal) + planarconfig: "contig" + ResolutionUnit: "in" + XResolution: 0 + YResolution: 72 + oiio:BitsPerSample: 1 + tiff:ColorSpace: "CMYK" + tiff:Compression: 1 + tiff:PhotometricInterpretation: 5 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 28 Comparing "check1.tif" and "ref/check1.tif" PASS diff --git a/testsuite/tiff-misc/ref/out-libtiff409.txt b/testsuite/tiff-misc/ref/out-libtiff409.txt index b8f9937118..8cd8867ea7 100644 --- a/testsuite/tiff-misc/ref/out-libtiff409.txt +++ b/testsuite/tiff-misc/ref/out-libtiff409.txt @@ -41,5 +41,22 @@ gps.tif : 64 x 64, 3 channel, uint8 tiff tiff:RowsPerStrip: 32 iconvert ERROR copying "src/crash-cmyk-e12b.tif" to "out.tif" : Decoding error at scanline 0, invalid distance too far back +Reading src/crash-cmyk-1bit.tif +src/crash-cmyk-1bit.tif : 73 x 43, 3 channel, uint1 tiff + SHA-1: 7E9169CEC1B8ABD56C3604AAD37761DBD8FE0F2A + channel list: R, G, B + compression: "none" + DocumentName: "flower-separated-contig-08.tif" + Orientation: 1 (normal) + planarconfig: "contig" + ResolutionUnit: "in" + XResolution: 0 + YResolution: 72 + oiio:BitsPerSample: 1 + tiff:ColorSpace: "CMYK" + tiff:Compression: 1 + tiff:PhotometricInterpretation: 5 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 28 Comparing "check1.tif" and "ref/check1.tif" PASS diff --git a/testsuite/tiff-misc/ref/out-libtiff410.txt b/testsuite/tiff-misc/ref/out-libtiff410.txt index a8247397b4..5f08284b0c 100644 --- a/testsuite/tiff-misc/ref/out-libtiff410.txt +++ b/testsuite/tiff-misc/ref/out-libtiff410.txt @@ -41,5 +41,22 @@ gps.tif : 64 x 64, 3 channel, uint8 tiff tiff:RowsPerStrip: 32 iconvert ERROR copying "src/crash-cmyk-e12b.tif" to "out.tif" : Decoding error at scanline 0, invalid distance too far back +Reading src/crash-cmyk-1bit.tif +src/crash-cmyk-1bit.tif : 73 x 43, 3 channel, uint1 tiff + SHA-1: 7E9169CEC1B8ABD56C3604AAD37761DBD8FE0F2A + channel list: R, G, B + compression: "none" + DocumentName: "flower-separated-contig-08.tif" + Orientation: 1 (normal) + planarconfig: "contig" + ResolutionUnit: "in" + XResolution: 0 + YResolution: 72 + oiio:BitsPerSample: 1 + tiff:ColorSpace: "CMYK" + tiff:Compression: 1 + tiff:PhotometricInterpretation: 5 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 28 Comparing "check1.tif" and "ref/check1.tif" PASS diff --git a/testsuite/tiff-misc/ref/out-libtiff430.txt b/testsuite/tiff-misc/ref/out-libtiff430.txt index 1ba814e913..73d139c156 100644 --- a/testsuite/tiff-misc/ref/out-libtiff430.txt +++ b/testsuite/tiff-misc/ref/out-libtiff430.txt @@ -56,5 +56,22 @@ gps.tif : 64 x 64, 3 channel, uint8 tiff tiff:RowsPerStrip: 32 iconvert ERROR copying "src/crash-cmyk-e12b.tif" to "out.tif" : Decoding error at scanline 0 +Reading src/crash-cmyk-1bit.tif +src/crash-cmyk-1bit.tif : 73 x 43, 3 channel, uint1 tiff + SHA-1: 7E9169CEC1B8ABD56C3604AAD37761DBD8FE0F2A + channel list: R, G, B + compression: "none" + DocumentName: "flower-separated-contig-08.tif" + Orientation: 1 (normal) + planarconfig: "contig" + ResolutionUnit: "in" + XResolution: 0 + YResolution: 72 + oiio:BitsPerSample: 1 + tiff:ColorSpace: "CMYK" + tiff:Compression: 1 + tiff:PhotometricInterpretation: 5 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 28 Comparing "check1.tif" and "ref/check1.tif" PASS diff --git a/testsuite/tiff-misc/ref/out-libtiff470-b.txt b/testsuite/tiff-misc/ref/out-libtiff470-b.txt index 4f9e90b485..6bebe2b474 100644 --- a/testsuite/tiff-misc/ref/out-libtiff470-b.txt +++ b/testsuite/tiff-misc/ref/out-libtiff470-b.txt @@ -56,5 +56,22 @@ gps.tif : 64 x 64, 3 channel, uint8 tiff tiff:RowsPerStrip: 32 iconvert ERROR copying "src/crash-cmyk-e12b.tif" to "out.tif" : Decoding error at scanline 0, invalid distance too far back +Reading src/crash-cmyk-1bit.tif +src/crash-cmyk-1bit.tif : 73 x 43, 3 channel, uint1 tiff + SHA-1: 7E9169CEC1B8ABD56C3604AAD37761DBD8FE0F2A + channel list: R, G, B + compression: "none" + DocumentName: "flower-separated-contig-08.tif" + Orientation: 1 (normal) + planarconfig: "contig" + ResolutionUnit: "in" + XResolution: 0 + YResolution: 72 + oiio:BitsPerSample: 1 + tiff:ColorSpace: "CMYK" + tiff:Compression: 1 + tiff:PhotometricInterpretation: 5 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 28 Comparing "check1.tif" and "ref/check1.tif" PASS diff --git a/testsuite/tiff-misc/ref/out-libtiff470-c.txt b/testsuite/tiff-misc/ref/out-libtiff470-c.txt index 85bc2404f8..61dc38ee9d 100644 --- a/testsuite/tiff-misc/ref/out-libtiff470-c.txt +++ b/testsuite/tiff-misc/ref/out-libtiff470-c.txt @@ -56,5 +56,22 @@ gps.tif : 64 x 64, 3 channel, uint8 tiff tiff:RowsPerStrip: 32 iconvert ERROR copying "src/crash-cmyk-e12b.tif" to "out.tif" : Decoding error at scanline 0, invalid distance too far back +Reading src/crash-cmyk-1bit.tif +src/crash-cmyk-1bit.tif : 73 x 43, 3 channel, uint1 tiff + SHA-1: 7E9169CEC1B8ABD56C3604AAD37761DBD8FE0F2A + channel list: R, G, B + compression: "none" + DocumentName: "flower-separated-contig-08.tif" + Orientation: 1 (normal) + planarconfig: "contig" + ResolutionUnit: "in" + XResolution: 0 + YResolution: 72 + oiio:BitsPerSample: 1 + tiff:ColorSpace: "CMYK" + tiff:Compression: 1 + tiff:PhotometricInterpretation: 5 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 28 Comparing "check1.tif" and "ref/check1.tif" PASS diff --git a/testsuite/tiff-misc/ref/out-libtiff470.txt b/testsuite/tiff-misc/ref/out-libtiff470.txt index c5df0c6b7d..a86c32046d 100644 --- a/testsuite/tiff-misc/ref/out-libtiff470.txt +++ b/testsuite/tiff-misc/ref/out-libtiff470.txt @@ -56,5 +56,22 @@ gps.tif : 64 x 64, 3 channel, uint8 tiff tiff:RowsPerStrip: 32 iconvert ERROR copying "src/crash-cmyk-e12b.tif" to "out.tif" : Decoding error at scanline 0 +Reading src/crash-cmyk-1bit.tif +src/crash-cmyk-1bit.tif : 73 x 43, 3 channel, uint1 tiff + SHA-1: 7E9169CEC1B8ABD56C3604AAD37761DBD8FE0F2A + channel list: R, G, B + compression: "none" + DocumentName: "flower-separated-contig-08.tif" + Orientation: 1 (normal) + planarconfig: "contig" + ResolutionUnit: "in" + XResolution: 0 + YResolution: 72 + oiio:BitsPerSample: 1 + tiff:ColorSpace: "CMYK" + tiff:Compression: 1 + tiff:PhotometricInterpretation: 5 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 28 Comparing "check1.tif" and "ref/check1.tif" PASS diff --git a/testsuite/tiff-misc/ref/out.txt b/testsuite/tiff-misc/ref/out.txt index a067377d67..707d956136 100644 --- a/testsuite/tiff-misc/ref/out.txt +++ b/testsuite/tiff-misc/ref/out.txt @@ -41,5 +41,22 @@ gps.tif : 64 x 64, 3 channel, uint8 tiff tiff:RowsPerStrip: 32 iconvert ERROR copying "src/crash-cmyk-e12b.tif" to "out.tif" : Decoding error at scanline 0, invalid distance too far back +Reading src/crash-cmyk-1bit.tif +src/crash-cmyk-1bit.tif : 73 x 43, 3 channel, uint1 tiff + SHA-1: 7E9169CEC1B8ABD56C3604AAD37761DBD8FE0F2A + channel list: R, G, B + compression: "none" + DocumentName: "flower-separated-contig-08.tif" + Orientation: 1 (normal) + planarconfig: "contig" + ResolutionUnit: "in" + XResolution: 0 + YResolution: 72 + oiio:BitsPerSample: 1 + tiff:ColorSpace: "CMYK" + tiff:Compression: 1 + tiff:PhotometricInterpretation: 5 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 28 Comparing "check1.tif" and "ref/check1.tif" PASS diff --git a/testsuite/tiff-misc/run.py b/testsuite/tiff-misc/run.py index 04030b4950..434223de79 100755 --- a/testsuite/tiff-misc/run.py +++ b/testsuite/tiff-misc/run.py @@ -32,4 +32,12 @@ # Test bug with corrupt cmyk file command += iconvert ("src/crash-cmyk-e12b.tif out.tif", failureok=True) +# Regression test: CMYK (photometric=separated) TIFF missing its +# BitsPerSample tag, which makes libtiff default it to 1 bit/sample. When +# unpacking the sub-8-bit samples for the CMYK->RGB conversion, the bit +# unpacker was writing all 4 input channels' worth of unpacked samples +# directly into the 3-channel RGB output buffer instead of scratch space, +# causing a heap buffer overflow. +command += info_command ("src/crash-cmyk-1bit.tif", safematch=True) + outputs = [ "check1.tif", "out.txt" ] diff --git a/testsuite/tiff-misc/src/crash-cmyk-1bit.tif b/testsuite/tiff-misc/src/crash-cmyk-1bit.tif new file mode 100644 index 0000000000000000000000000000000000000000..531e6c05e9668b23c4b10b54f6c2bcf5519bd919 GIT binary patch literal 13733 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 TP$}n?vjB%Fl^)oYUj4rT-o0($ literal 0 HcmV?d00001