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:
- The tiffcmp program processes a malformed TIFF file with invalid directory structure
- 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"
- 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)
- Strip array allocation via
- Error handling paths fail to properly deallocate these large resources
- AddressSanitizer detects significant memory leaks during program termination
- 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
- Compile LibTIFF with AddressSanitizer enabled (
-fsanitize=address) - Execute the following command with the provided POC file:
./tiffcmp POC_tiffcmp_memory_leak_abort /dev/null - The program will display multiple TIFF parsing warnings
- AddressSanitizer will detect memory leaks totaling ~43KB
- Program will terminate with SIGBUS (abort)
Root Cause Analysis
Memory Management Issue
The vulnerability stems from incomplete error handling during complex TIFF directory processing:
- Parsing Phase: TIFF directory parsing encounters multiple validation errors
- Large Allocation: Strip array processing allocates large memory blocks (19KB × 2)
- Anonymous Fields: Custom tag processing creates anonymous field structures
- Cleanup Failure: Error handling paths fail to deallocate the large strip arrays
- Leak Accumulation: Significantly more memory remains allocated than the illegal instruction variant
- Detection: AddressSanitizer detects large-scale leaks during program termination
Technical Details
-
Primary Leak Location:
tif_dirread.c:7813/7815inallocChoppedUpStripArrays()(38016 bytes total) -
Secondary Leak Locations:
-
tif_open.c:197in_TIFFmallocExt()(1567 bytes) -
tif_dirinfo.c:904in_TIFFCreateAnonField()(240 bytes) -
tif_dir.c:55insetByteArray()(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)