Double Free with Tcache Detection
Summary
During fuzzing of the TIFFCROP utility from LibTIFF, a critical double free vulnerability has been discovered that is detected by the glibc thread cache (tcache) mechanism. The vulnerability occurs when the program attempts to free memory that has already been freed and is still present in the tcache, triggering the memory allocator's corruption detection with the error "free(): double free detected in tcache 2".
Technical Details
- Vulnerability Type: Double Free / Tcache Corruption
-
Affected Function:
main(cleanup path) -
Source File:
tiffcrop.c - Line Number: 2931
- Signal: SIGABRT (6)
-
Detection Point:
_int_freeatmalloc.c:4473 - Affected Crashes: 11 out of 135 total crashes (8.1%)
Vulnerability Mechanism and Root Cause
This double free vulnerability is caused by improper memory lifecycle management in the error handling paths of tiffcrop, specifically detected through the tcache (thread cache) mechanism. The root issue lies in the cleanup logic where the same memory region gets freed multiple times, and the second free attempt finds the memory block still cached in tcache bin 2.
The vulnerability occurs when:
- The tiffcrop program processes a malformed TIFF image with color inversion parameters
- Image inversion fails due to unsupported multi-sample pixel format
- Error handling triggers cleanup operations that attempt to free the same memory multiple times
- The first free() operation places the memory block (0x555555788fd0) into tcache bin 2
- The second free() attempt detects the block is already in tcache, triggering the detection at
_int_freeline 4473 - The glibc memory allocator aborts with "free(): double free detected in tcache 2"
The tcache mechanism provides fast allocation/deallocation for small blocks by caching recently freed blocks. When the same block is freed twice, the tcache consistency checks detect this condition and abort the program to prevent heap corruption.
GDB Debugging Report
=== PROGRAM_EXECUTION_START ===
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (no_tid=0, signo=6, threadid=140737348006464) at ./nptl/pthread_kill.c:44
=== PROGRAM_EXECUTION_END ===
=== PRIMARY_CRASH_DETECTION ===
Program status from 'info program':
Using the running image of child Thread 0x7ffff7a27240 (LWP 1758061).
Program stopped at 0x7ffff7abe9fc.
It stopped with signal SIGABRT, Aborted.
=== SIGNAL_CRASH_DETECTED ===
Program terminated by signal - this is a genuine crash
=== FRAME_ANALYSIS ===
Valid frame found - program stopped at signal
=== BACKTRACE_ANALYSIS ===
#0 __pthread_kill_implementation (no_tid=0, signo=6, threadid=140737348006464) at ./nptl/pthread_kill.c:44
#1 __pthread_kill_internal (signo=6, threadid=140737348006464) at ./nptl/pthread_kill.c:78
#2 __GI___pthread_kill (threadid=140737348006464, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3 0x00007ffff7a6a476 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4 0x00007ffff7a507f3 in __GI_abort () at ./stdlib/abort.c:79
#5 0x00007ffff7ab1677 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff7c03b77 "%s\n") at ../sysdeps/posix/libc_fatal.c:156
#6 0x00007ffff7ac8cfc in malloc_printerr (str=str@entry=0x7ffff7c066f0 "free(): double free detected in tcache 2") at ./malloc/malloc.c:5664
#7 0x00007ffff7acb0ab in _int_free (av=0x7ffff7c42c80 <main_arena>, p=0x555555788fd0, have_lock=0) at ./malloc/malloc.c:4473
#8 0x00007ffff7acd453 in __GI___libc_free (mem=<optimized out>) at ./malloc/malloc.c:3391
#9 0x000055555556cedc in main (argc=<optimized out>, argv=0x7fffffffe3f8) at tiffcrop.c:2931
=== FINAL_STATUS_DETERMINATION ===
CONCLUSION: Program crashed due to signal
This is a genuine crash requiring investigation
Program Output Before Crash
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
invertImage: Image inversion not supported for more than one sample per pixel.
createCroppedImage: Failed to invert colorspace for image or cropped selection.
main: Unable to create output image.
free(): double free detected in tcache 2
Aborted (core dumped)
Proof of Concept
The proof of concept file is available at: POC_tiffcrop_double_free_tcache_detection
Reproduction Steps
- Compile LibTIFF with debugging symbols
- Execute the following command with the provided POC file:
./tiffcrop -I both POC_tiffcrop_double_free_tcache_detection /dev/null - The program will crash with SIGABRT due to tcache double free detection at malloc.c:4473
Affected Versions
- LibTIFF Version: 4.7.0 (the newest master)
- Build Configuration: Standard build with debugging symbols
- Platform: Linux x86_64
Credit
Discovered by: Xudong Cao (UCAS), Yuqing Zhang (UCAS, Zhongguancun Laboratory)