A null-pointer dereference in libtiff leads to a crash during directory rewrite on TIFFClose()/TIFFFlush() when handling malformed inputs.
# Bug Report
TIFFWriteDirectoryTagLongLong8Array.zip
## Describe the bug
A null-pointer dereference in libtiff leads to a crash during directory rewrite on TIFFClose()/TIFFFlush() when handling malformed inputs.
When TIFFRewriteDirectorySec%20writes%20StripOffsets/StripByteCounts%20as%20LONG8%20arrays,%20it%20calls%20TIFFWriteDirectoryTagLongLong8Array() with a NULL array pointer. Inside that function, the code unconditionally dereferences the pointer (*ma > 0xFFFF), causing a segmentation fault.
- Impact: Denial of service (process crash). This can be triggered when an application opens a crafted TIFF in update mode ("r+", or otherwise hits the rewrite path) and then closes it.
- CWE: CWE-476 (NULL Pointer Dereference)
- Observed result (ASan):
```
SEGV at TIFFWriteDirectoryTagLongLong8Array (tif_dirwrite.c:2006)
#0 TIFFWriteDirectoryTagLongLong8Array
#1 (closed) TIFFWriteDirectorySec
#2 (closed) TIFFRewriteDirectorySec / TIFFRewriteDirectory
#3 (closed) TIFFFlush
#4 (closed) TIFFCleanup
#5 (closed) TIFFClose
```
# Root Cause Analysis
- During TIFFClose() → TIFFCleanup() → TIFFFlush(), the code may decide to rewrite the directory (e.g., update mode / dirty strip state / force strile arrays).
- TIFFRewriteDirectorySec() → TIFFWriteDirectorySec() attempts to write StripOffsets / StripByteCounts using LONG8 arrays and passes pointers derived from td->td_stripoffset_p / td->td_stripbytecount_p.
- With malformed inputs and certain state transitions, these pointers remain NULL (the directory lacked required fields and no safe allocation was performed).
- TIFFWriteDirectoryTagLongLong8Array() then unconditionally dereferences the array pointer (if (*ma > 0xFFFF) … at tif_dirwrite.c:2006) → NULL deref.
This is a logic/defensive-programming gap: the write path assumes the arrays are valid and non-NULL, but that precondition isn’t enforced when the input is inconsistent.
# Fix suggestions
1. Immediate guard in TIFFWriteDirectoryTagLongLong8Array():
- If value == NULL or count == 0, return error (set tif->tif_errno appropriately) instead of dereferencing.
2. Upstream consistency in TIFFWriteDirectorySec():
- Before calling writers for StripOffsets/StripByteCounts, ensure td_stripoffset_p / td_stripbytecount_p are allocated/initialized (or refuse rewrite with a clear error).
- Alternatively, ensure TIFFForceStrileArrayWriting() (or equivalent) guarantees those arrays are non-NULL before reaching the tag-writer.
# To Reproduce
1. Compile libtiff with AddressSanitizer:
```
export CC="clang -fsanitize=address,fuzzer-no-link -g "
export CFLAGS="-g -O0"
mkdir build_asan
cd build_asan
../code/configure --prefix=$PWD/../bin_asan --enable-static --disable-shared
make -j$(nproc)
make install
```
2. Compile the Fuzz Driver:
- Compile the fuzz driver with the following command:
```
clang ./fuzz_driver_184.c -o ./fuzz_driver_184 -fsanitize=fuzzer,address,undefined -g -O0 -I../bin_asan/include ../bin_asan/lib/libtiff.a -lz -ljpeg -ljbig -llzma -lzstd -ldeflate -lwebp -lsharpyuv -L/usr/local/lib -lLerc -lm -lpthread
```
3. Run the Fuzz Driver:
```
./fuzz_driver_184 ./bug.input
```
# Desktop Environment
- OS and Version: Linux (Ubuntu 24.04.2 LTS)
- libtiff Version and Source:
main branch at commit 5fe20d0e9aba49a6a350ed533459d1505203838f (Fri Sep 12 11:21:38 2025 +0000)(from https://gitlab.com/libtiff/libtiff.git )
- Compiler and Version: Ubuntu clang version 18.1.3
# ASan Report
=================================================================
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2801120172
INFO: Loaded 1 modules (10731 inline 8-bit counters): 10731 [0x5a4601cb4668, 0x5a4601cb7053),
INFO: Loaded 1 PC tables (10731 PCs): 10731 [0x5a4601cb7058,0x5a4601ce0f08),
./fuzz_driver_184: Running 1 inputs 1 time(s) each.
Running: ./bug.input
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 0 (Tag 0) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFReadDirectory: Warning, Invalid data type for tag TileOffsets.
TIFFReadDirectory: Warning, TIFF directory is missing required "StripByteCounts" field, calculating from imagelength.
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
TIFFFetchNormalTag: Warning, IO error during reading of "Tag 0"; tag ignored.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 33023 (Tag 33023) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 59136 (Tag 59136) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 97 (Tag 97) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFReadDirectory: Warning, Invalid data type for tag TileByteCounts.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 16 (Tag 16) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 65280 (Tag 65280) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
MissingRequired: TIFF directory is missing required "StripOffsets" field.
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 0 (Tag 0) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFReadDirectory: Warning, Invalid data type for tag TileOffsets.
TIFFReadDirectory: Warning, TIFF directory is missing required "StripByteCounts" field, calculating from imagelength.
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
TIFFFetchNormalTag: Warning, IO error during reading of "Tag 0"; tag ignored.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 33023 (Tag 33023) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 59136 (Tag 59136) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 97 (Tag 97) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFReadDirectory: Warning, Invalid data type for tag TileByteCounts.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 16 (Tag 16) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 65280 (Tag 65280) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
MissingRequired: TIFF directory is missing required "StripOffsets" field.
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 0 (Tag 0) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFReadDirectory: Warning, Invalid data type for tag TileOffsets.
TIFFReadDirectory: Warning, TIFF directory is missing required "StripByteCounts" field, calculating from imagelength.
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
TIFFFetchNormalTag: Warning, IO error during reading of "Tag 0"; tag ignored.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 33023 (Tag 33023) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 59136 (Tag 59136) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 97 (Tag 97) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFReadDirectory: Warning, Invalid data type for tag TileByteCounts.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 16 (Tag 16) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 65280 (Tag 65280) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
MissingRequired: TIFF directory is missing required "StripOffsets" field.
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 0 (Tag 0) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFReadDirectory: Warning, Invalid data type for tag TileOffsets.
TIFFReadDirectory: Warning, TIFF directory is missing required "StripByteCounts" field, calculating from imagelength.
TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order.
TIFFFetchNormalTag: Warning, IO error during reading of "Tag 0"; tag ignored.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 33023 (Tag 33023) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 59136 (Tag 59136) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 97 (Tag 97) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFReadDirectory: Warning, Invalid data type for tag TileByteCounts.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 16 (Tag 16) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
TIFFFetchNormalTag: Defined set_get_field_type of custom tag 65280 (Tag 65280) is TIFF_SETGET_UNDEFINED and thus tag is not read from file.
MissingRequired: TIFF directory is missing required "StripOffsets" field.
TIFFVStripSize64: Invalid td_samplesperpixel value.
AddressSanitizer:DEADLYSIGNAL
=================================================================
==4060590==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5a4601b2e937 bp 0x7ffe129a7410 sp 0x7ffe129a7230 T0)
==4060590==The signal is caused by a READ memory access.
==4060590==Hint: address points to the zero page.
#0 0x5a4601b2e937 in TIFFWriteDirectoryTagLongLong8Array /root/cov_fuzz/testTP/libtiff/build_asan/libtiff/../../code/libtiff/tif_dirwrite.c:2006:17
#1 0x5a4601b1f9ed in TIFFWriteDirectorySec /root/cov_fuzz/testTP/libtiff/build_asan/libtiff/../../code/libtiff/tif_dirwrite.c:717:26
#2 0x5a4601b29644 in TIFFRewriteDirectorySec /root/cov_fuzz/testTP/libtiff/build_asan/libtiff/../../code/libtiff/tif_dirwrite.c:474:12
#3 0x5a4601b278ff in TIFFRewriteDirectory /root/cov_fuzz/testTP/libtiff/build_asan/libtiff/../../code/libtiff/tif_dirwrite.c:485:12
#4 0x5a4601ae5d3a in TIFFFlush /root/cov_fuzz/testTP/libtiff/build_asan/libtiff/../../code/libtiff/tif_flush.c:51:10
#5 0x5a4601a6cfe5 in TIFFCleanup /root/cov_fuzz/testTP/libtiff/build_asan/libtiff/../../code/libtiff/tif_close.c:50:9
#6 0x5a4601a6de26 in TIFFClose /root/cov_fuzz/testTP/libtiff/build_asan/libtiff/../../code/libtiff/tif_close.c:162:9
#7 0x5a4601a6ccbe in LLVMFuzzerTestOneInput /root/cov_fuzz/testTP/libtiff/TIFFWriteDirectoryTagLongLong8Array/./fuzz_driver_184.c:77:9
#8 0x5a460197a2a4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const\*, unsigned long) (/root/cov_fuzz/testTP/libtiff/TIFFWriteDirectoryTagLongLong8Array/fuzz_driver_184+0xac2a4) (BuildId: ead438d8377c6e41b9c4ffe8a6c28f8f2d2518bd)
#9 0x5a46019633d6 in fuzzer::RunOneTest(fuzzer::Fuzzer\*, char const\*, unsigned long) (/root/cov_fuzz/testTP/libtiff/TIFFWriteDirectoryTagLongLong8Array/fuzz_driver_184+0x953d6) (BuildId: ead438d8377c6e41b9c4ffe8a6c28f8f2d2518bd)
#10 0x5a4601968e8a in fuzzer::FuzzerDriver(int\*, char\*\*_\*, int (\*_)(unsigned char const\*, unsigned long)) (/root/cov_fuzz/testTP/libtiff/TIFFWriteDirectoryTagLongLong8Array/fuzz_driver_184+0x9ae8a) (BuildId: ead438d8377c6e41b9c4ffe8a6c28f8f2d2518bd)
#11 0x5a4601993646 in main (/root/cov_fuzz/testTP/libtiff/TIFFWriteDirectoryTagLongLong8Array/fuzz_driver_184+0xc5646) (BuildId: ead438d8377c6e41b9c4ffe8a6c28f8f2d2518bd)
#12 0x705a5989f1c9 in \__libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#13 0x705a5989f28a in \__libc_start_main csu/../csu/libc-start.c:360:3
#14 0x5a460195dfa4 in \_start (/root/cov_fuzz/testTP/libtiff/TIFFWriteDirectoryTagLongLong8Array/fuzz_driver_184+0x8ffa4) (BuildId: ead438d8377c6e41b9c4ffe8a6c28f8f2d2518bd)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /root/cov_fuzz/testTP/libtiff/build_asan/libtiff/../../code/libtiff/tif_dirwrite.c:2006:17 in TIFFWriteDirectoryTagLongLong8Array
==4060590==ABORTING