TIFFCMP Memory Leak (Abort)

Summary

During fuzzing of the TIFFCMP utility from LibTIFF, a memory leak vulnerability has been discovered that leads to program termination with SIGBUS (abort). The vulnerability occurs during TIFF file processing with malformed directory structures, causing significantly larger memory leaks than the illegal instruction variant.

Technical Details

  • Vulnerability Type: Memory Leak leading to Abort
  • Affected Function: Multiple functions in TIFF processing chain including strip array allocation
  • Primary Functions: _TIFFmallocExt, allocChoppedUpStripArrays, _TIFFCreateAnonField, _TIFFCheckRealloc
  • Signal: SIGBUS (7) / Abort
  • Affected Program: tiffcmp

Vulnerability Mechanism and Root Cause

This memory leak vulnerability is caused by improper resource management during TIFF file processing with malformed directory structures and invalid tag configurations. The root issue lies in the strip array allocation and anonymous field creation processes where large memory blocks are allocated but not properly freed when encountering parsing errors.

The vulnerability occurs when:

  1. The tiffcmp program processes a malformed TIFF file with invalid directory structure
  2. TIFF parsing encounters various validation warnings:
    • "Invalid TIFF directory; tags are not sorted in ascending order"
    • "Bad value for ResolutionUnit tag"
    • "Bogus StripByteCounts field"
    • "ASCII value contains null byte"
  3. Large memory allocations occur during processing:
    • Strip array allocation via allocChoppedUpStripArrays (up to 19008 bytes × 2)
    • Anonymous field creation via _TIFFCreateAnonField (240 bytes)
    • Main TIFF structure allocation (1567 bytes)
  4. Error handling paths fail to properly deallocate these large resources
  5. AddressSanitizer detects significant memory leaks during program termination
  6. The process terminates with SIGBUS due to the memory management violations

Complete AddressSanitizer Report

TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
TIFFFetchNormalTag: Warning, ASCII value for tag "DocumentName" contains null byte in value; value incorrectly truncated during reading due to implementation limitations.
TIFFFetchNormalTag: Warning, IO error during reading of "ImageDescription"; tag ignored.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 5632 (Tag 5632) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 5888 (Tag 5888) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 6656 (Tag 6656) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 6912 (Tag 6912) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 7168 (Tag 7168) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 10240 (Tag 10240) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFReadDirectory: Warning, Sum of Photometric type-related color channels and ExtraSamples doesn't match SamplesPerPixel. Defining non-color channels as ExtraSamples..
TIFFReadDirectory: Warning, TIFF directory is missing required "StripByteCounts" field, calculating from imagelength.
/dev/null: Cannot read TIFF header.

=================================================================
==1637016==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1567 byte(s) in 1 object(s) allocated from:
    #0 0x558720e627be in __interceptor_malloc (/fuzzdir/fz-tiffcmp/tiffcmp+0xd97be) (BuildId: 04ac6561bc9fdd8bf2962f31ac1c1af41d5c40bb)
    #1 0x558720f0874c in _TIFFmallocExt /libtiff/tif_open.c:197:12
    #2 0x558720f0874c in TIFFClientOpenExt /libtiff/tif_open.c:366:19
    #3 0x558720f21f78 in TIFFFdOpenExt /libtiff/tif_unix.c:221:11
    #4 0x558720f21f78 in TIFFOpenExt /libtiff/tif_unix.c:267:11
    #5 0x558720e9d635 in main /tools/tiffcmp.c:103:12
    #6 0x7f21ba319d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

Indirect leak of 19008 byte(s) in 1 object(s) allocated from:
    #0 0x558720e62be5 in __interceptor_realloc (/fuzzdir/fz-tiffcmp/tiffcmp+0xd9be5) (BuildId: 04ac6561bc9fdd8bf2962f31ac1c1af41d5c40bb)
    #1 0x558720f22d96 in _TIFFCheckRealloc /libtiff/tif_aux.c:107:14
    #2 0x558720f22d96 in _TIFFCheckMalloc /libtiff/tif_aux.c:125:12
    #3 0x558720f025c4 in allocChoppedUpStripArrays /libtiff/tif_dirread.c:7813:21
    #4 0x558720ecdc85 in TIFFReadDirectory /libtiff/tif_dirread.c:5146:9
    #5 0x558720f0a183 in TIFFClientOpenExt /libtiff/tif_open.c:769:17
    #6 0x558720f21f78 in TIFFFdOpenExt /libtiff/tif_unix.c:221:11
    #7 0x558720f21f78 in TIFFOpenExt /libtiff/tif_unix.c:267:11
    #8 0x558720e9d635 in main /tools/tiffcmp.c:103:12
    #9 0x7f21ba319d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

Indirect leak of 19008 byte(s) in 1 object(s) allocated from:
    #0 0x558720e62be5 in __interceptor_realloc (/fuzzdir/fz-tiffcmp/tiffcmp+0xd9be5) (BuildId: 04ac6561bc9fdd8bf2962f31ac1c1af41d5c40bb)
    #1 0x558720f22d96 in _TIFFCheckRealloc /libtiff/tif_aux.c:107:14
    #2 0x558720f22d96 in _TIFFCheckMalloc /libtiff/tif_aux.c:125:12
    #3 0x558720f025e2 in allocChoppedUpStripArrays /libtiff/tif_dirread.c:7815:30
    #4 0x558720ecdc85 in TIFFReadDirectory /libtiff/tif_dirread.c:5146:9
    #5 0x558720f0a183 in TIFFClientOpenExt /libtiff/tif_open.c:769:17
    #6 0x558720f21f78 in TIFFFdOpenExt /libtiff/tif_unix.c:221:11
    #7 0x558720f21f78 in TIFFOpenExt /libtiff/tif_unix.c:267:11
    #8 0x558720e9d635 in main /tools/tiffcmp.c:103:12
    #9 0x7f21ba319d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

Indirect leak of 1272 byte(s) in 1 object(s) allocated from:
    #0 0x558720e62be5 in __interceptor_realloc (/fuzzdir/fz-tiffcmp/tiffcmp+0xd9be5) (BuildId: 04ac6561bc9fdd8bf2962f31ac1c1af41d5c40bb)
    #1 0x558720f22bf6 in _TIFFCheckRealloc /libtiff/tif_aux.c:107:14
    #2 0x558720ec4309 in _TIFFMergeFields /libtiff/tif_dirinfo.c:584:41
    #3 0x558720eca1a2 in TIFFReadDirectory /libtiff/tif_dirread.c:4419:37
    #4 0x558720f0a183 in TIFFClientOpenExt /libtiff/tif_open.c:769:17
    #5 0x558720f21f78 in TIFFFdOpenExt /libtiff/tif_unix.c:221:11
    #6 0x558720f21f78 in TIFFOpenExt /libtiff/tif_unix.c:267:11
    #7 0x558720e9d635 in main /tools/tiffcmp.c:103:12
    #8 0x7f21ba319d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

Indirect leak of 510 byte(s) in 1 object(s) allocated from:
    #0 0x558720e627be in __interceptor_malloc (/fuzzdir/fz-tiffcmp/tiffcmp+0xd97be) (BuildId: 04ac6561bc9fdd8bf2962f31ac1c1af41d5c40bb)
    #1 0x558720ea88ee in setByteArray /libtiff/tif_dir.c:55:28
    #2 0x558720ea88ee in _TIFFsetShortArrayExt /libtiff/tif_dir.c:81:5
    #3 0x558720ecd77a in TIFFReadDirectory /libtiff/tif_dirread.c:4994:9
    #4 0x558720f0a183 in TIFFClientOpenExt /libtiff/tif_open.c:769:17
    #5 0x558720f21f78 in TIFFFdOpenExt /libtiff/tif_unix.c:221:11
    #6 0x558720f21f78 in TIFFOpenExt /libtiff/tif_unix.c:267:11
    #7 0x558720e9d635 in main /tools/tiffcmp.c:103:12
    #8 0x7f21ba319d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

Indirect leak of 424 byte(s) in 1 object(s) allocated from:
    #0 0x558720e629a8 in __interceptor_calloc (/fuzzdir/fz-tiffcmp/tiffcmp+0xd99a8) (BuildId: 04ac6561bc9fdd8bf2962f31ac1c1af41d5c40bb)
    #1 0x558720f049d9 in TIFFHashSetNew /libtiff/tif_hash_set.c:149:34
    #2 0x558720ecfa95 in _TIFFCheckDirNumberAndOffset /libtiff/tif_dirread.c:5685:45
    #3 0x558720ec8ff5 in TIFFReadDirectory /libtiff/tif_dirread.c:4262:10
    #4 0x558720f0a183 in TIFFClientOpenExt /libtiff/tif_open.c:769:17
    #5 0x558720f21f78 in TIFFFdOpenExt /libtiff/tif_unix.c:221:11
    #6 0x558720f21f78 in TIFFOpenExt /libtiff/tif_unix.c:267:11
    #7 0x558720e9d635 in main /tools/tiffcmp.c:103:12
    #8 0x7f21ba319d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

Indirect leak of 424 byte(s) in 1 object(s) allocated from:
    #0 0x558720e629a8 in __interceptor_calloc (/fuzzdir/fz-tiffcmp/tiffcmp+0xd99a8) (BuildId: 04ac6561bc9fdd8bf2962f31ac1c1af41d5c40bb)
    #1 0x558720f049d9 in TIFFHashSetNew /libtiff/tif_hash_set.c:149:34
    #2 0x558720ecf9d1 in _TIFFCheckDirNumberAndOffset /libtiff/tif_dirread.c:5671:45
    #3 0x558720ec8ff5 in TIFFReadDirectory /libtiff/tif_dirread.c:4262:10
    #4 0x558720f0a183 in TIFFClientOpenExt /libtiff/tif_open.c:769:17
    #5 0x558720f21f78 in TIFFFdOpenExt /libtiff/tif_unix.c:221:11
    #6 0x558720f21f78 in TIFFOpenExt /libtiff/tif_unix.c:267:11
    #7 0x558720e9d635 in main /tools/tiffcmp.c:103:12
    #8 0x7f21ba319d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

Indirect leak of 272 byte(s) in 1 object(s) allocated from:
    #0 0x558720e627be in __interceptor_malloc (/fuzzdir/fz-tiffcmp/tiffcmp+0xd97be) (BuildId: 04ac6561bc9fdd8bf2962f31ac1c1af41d5c40bb)
    #1 0x558720ec9551 in TIFFReadDirectory /libtiff/tif_dirread.c:4327:37
    #2 0x558720f0a183 in TIFFClientOpenExt /libtiff/tif_open.c:769:17
    #3 0x558720f21f78 in TIFFFdOpenExt /libtiff/tif_unix.c:221:11
    #4 0x558720f21f78 in TIFFOpenExt /libtiff/tif_unix.c:267:11
    #5 0x558720e9d635 in main /tools/tiffcmp.c:103:12
    #6 0x7f21ba319d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

Indirect leak of 240 byte(s) in 6 object(s) allocated from:
    #0 0x558720e627be in __interceptor_malloc (/fuzzdir/fz-tiffcmp/tiffcmp+0xd97be) (BuildId: 04ac6561bc9fdd8bf2962f31ac1c1af41d5c40bb)
    #1 0x558720ec703f in _TIFFCreateAnonField /libtiff/tif_dirinfo.c:904:24
    #2 0x558720eca182 in TIFFReadDirectory /libtiff/tif_dirread.c:4417:40
    #3 0x558720f0a183 in TIFFClientOpenExt /libtiff/tif_open.c:769:17
    #4 0x558720f21f78 in TIFFFdOpenExt /libtiff/tif_unix.c:221:11
    #5 0x558720f21f78 in TIFFOpenExt /libtiff/tif_unix.c:267:11
    #6 0x558720e9d635 in main /tools/tiffcmp.c:103:12
    #7 0x7f21ba319d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

[Additional leak entries continue with smaller allocations...]

SUMMARY: AddressSanitizer: 43118 byte(s) leaked in 27 allocation(s).
Aborted

Call Chain Analysis

The vulnerability follows this execution path with distinctive large allocations:

main() (tiffcmp.c:103)
  → TIFFOpenExt() (tif_unix.c:267)
    → TIFFFdOpenExt() (tif_unix.c:221)
      → TIFFClientOpenExt() (tif_open.c)
        → _TIFFmallocExt() (tif_open.c:197) [DIRECT LEAK: 1567 bytes]
        → TIFFReadDirectory() (tif_dirread.c:5146)
          → allocChoppedUpStripArrays() [MASSIVE LEAK: 19008 × 2 bytes = 38016 bytes]
            → _TIFFCheckMalloc() → _TIFFCheckRealloc()
          → _TIFFCreateAnonField() [INDIRECT LEAK: 240 bytes in 6 objects]
          → _TIFFsetShortArrayExt() [INDIRECT LEAK: 510 bytes]

Proof of Concept

POC File: POC_tiffcmp_memory_leak_abort

Reproduction Command:

./tiffcmp POC_tiffcmp_memory_leak_abort /dev/null

Affected Versions

  • LibTIFF Version: 4.7.0+ (latest master branch)
  • Build Configuration: Standard build with AddressSanitizer enabled
  • Platform: Linux x86_64

Reproduction Steps

  1. Compile LibTIFF with AddressSanitizer enabled (-fsanitize=address)
  2. Execute the following command with the provided POC file:
    ./tiffcmp POC_tiffcmp_memory_leak_abort /dev/null
  3. The program will display multiple TIFF parsing warnings
  4. AddressSanitizer will detect memory leaks totaling ~43KB
  5. Program will terminate with SIGBUS (abort)

Root Cause Analysis

Memory Management Issue

The vulnerability stems from incomplete error handling during complex TIFF directory processing:

  1. Parsing Phase: TIFF directory parsing encounters multiple validation errors
  2. Large Allocation: Strip array processing allocates large memory blocks (19KB × 2)
  3. Anonymous Fields: Custom tag processing creates anonymous field structures
  4. Cleanup Failure: Error handling paths fail to deallocate the large strip arrays
  5. Leak Accumulation: Significantly more memory remains allocated than the illegal instruction variant
  6. Detection: AddressSanitizer detects large-scale leaks during program termination

Technical Details

  • Primary Leak Location: tif_dirread.c:7813/7815 in allocChoppedUpStripArrays() (38016 bytes total)
  • Secondary Leak Locations:
    • tif_open.c:197 in _TIFFmallocExt() (1567 bytes)
    • tif_dirinfo.c:904 in _TIFFCreateAnonField() (240 bytes)
    • tif_dir.c:55 in setByteArray() (510 bytes)
  • Trigger Condition: Malformed TIFF directory + large strip array requirements + incomplete cleanup
  • Detection Method: AddressSanitizer LeakSanitizer during program termination

Distinctive Features

This vulnerability variant is characterized by:

  • Massive Strip Array Leaks: Up to 38KB in strip array allocations alone
  • Complex Directory Structure: Triggers processing of custom tags and anonymous fields
  • Multiple Warning Messages: Extensive validation warnings indicate complex malformed structure
  • Variable Severity: Leak sizes range from 4KB to 43KB depending on input complexity

Credit

Discovered by: Xudong Cao (UCAS), Yuqing Zhang (UCAS, Zhongguancun Laboratory)