Intro
Hi! I have been fuzzing VTK file readers and have potentially fond some memory bugs in the vtkExodusIIReader module.
Fuzzing Setup
All fuzzing was done with AFL++ using a from source build of VTK with AFL instrumentation. Fuzzing was done for 1 hour over 3 seperate campaigns. Saved crashing test cases were triaged with ASAN. The CMake config for VTK is the following.
VTK Version
Branch: master
Commit: 00f9418c
cmake ../ \
-GNinja \
-DCMAKE_C_COMPILER=afl-clang-fast \
-DCMAKE_CXX_COMPILER=afl-clang-fast++ \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DVTK_BUILD_TESTING=OFF \
-DVTK_BUILD_EXAMPLES=OFF \
-DVTK_GROUP_ENABLE_Rendering=NO \
-DVTK_GROUP_ENABLE_Views=NO \
-DVTK_GROUP_ENABLE_Web=NO \
-DVTK_GROUP_ENABLE_Qt=NO \
-DVTK_MODULE_ENABLE_VTK_RenderingCore=YES \
-DVTK_MODULE_ENABLE_VTK_FiltersHybrid=YES \
-DVTK_MODULE_ENABLE_VTK_IOLegacy=YES \
-DVTK_MODULE_ENABLE_VTK_IOImage=YES \
-DVTK_MODULE_ENABLE_VTK_IOGeometry=YES \
-DVTK_MODULE_ENABLE_VTK_ImagingCore=YES \
-DVTK_MODULE_ENABLE_VTK_CommonCore=YES \
-DVTK_MODULE_ENABLE_VTK_CommonDataModel=YES
1: Heap-Buffer Overflow
Found in vtkAOSDataArrayTemplate<ValueTypeT>::GetTuple function. AFL++ found several malformed exodus test cases which triggered invalid 8 byte reads beyond the allocated memory of the data array.
template <class ValueTypeT>
double* vtkAOSDataArrayTemplate<ValueTypeT>::GetTuple(vtkIdType tupleIdx)
{
ValueTypeT* data = this->Buffer->GetBuffer() + tupleIdx * this->NumberOfComponents;
double* tuple = this->LegacyTuple.data();
// See note in SetTuple about std::copy vs for loops on MSVC.
for (int i = 0; i < this->NumberOfComponents; ++i)
{
tuple[i] = static_cast<double>(data[i]);
}
return this->LegacyTuple.data();
}
ASAN Output
=================================================================
==88262==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x532000016fe8 at pc 0xffffa37b4dd8 bp 0xffffea362360 sp 0xffffea362358
READ of size 8 at 0x532000016fe8 thread T0
#0 0xffffa37b4dd4 in vtkAOSDataArrayTemplate<double>::GetTuple(long long) /work/final/vtk/Common/Core/vtkAOSDataArrayTemplate.txx:294:36
#1 0xffffa99db8c8 in vtkExodusIIReaderPrivate::AssembleOutputPoints(long long, vtkExodusIIReaderPrivate::BlockSetInfoType*, vtkUnstructuredGrid*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:546:38
#2 0xffffa9a0cff4 in vtkExodusIIReaderPrivate::RequestData(long long, vtkMultiBlockDataSet*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:4531:15
#3 0xffffa9a18cc8 in vtkExodusIIReader::RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:5547:19
#4 0xffffa90eb5f4 in vtkExecutive::CallAlgorithm(vtkInformation*, int, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkExecutive.cxx:723:33
#5 0xffffa90d9a80 in vtkDemandDrivenPipeline::ExecuteData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:447:22
#6 0xffffa90cf350 in vtkCompositeDataPipeline::ExecuteData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkCompositeDataPipeline.cxx:151:32
#7 0xffffa90d858c in vtkDemandDrivenPipeline::ProcessRequest(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:246:22
#8 0xffffa9152d38 in vtkStreamingDemandDrivenPipeline::ProcessRequest(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkStreamingDemandDrivenPipeline.cxx
#9 0xffffa90d9444 in vtkDemandDrivenPipeline::UpdateData(int) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:404:16
#10 0xffffa9153eb8 in vtkStreamingDemandDrivenPipeline::Update(int, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkStreamingDemandDrivenPipeline.cxx:421:34
#11 0xffffa90c58a4 in vtkAlgorithm::Update(int) /work/final/vtk/Common/ExecutionModel/vtkAlgorithm.cxx:1660:32
#12 0xaaaada13a548 in main /work/final/fuzzing-vtk/exodusTestSimple.cpp:14:10
#13 0xffffa20684c0 (/lib/aarch64-linux-gnu/libc.so.6+0x284c0) (BuildId: d6c205bda1b6e91815f8fef45bdf56bc2239c37e)
#14 0xffffa2068594 in __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x28594) (BuildId: d6c205bda1b6e91815f8fef45bdf56bc2239c37e)
#15 0xaaaada055e2c in _start (/work/final/Fuzzing-VTK/build/harness-asan+0x35e2c) (BuildId: 37da1d56ebb97cbdd7c9ab2560fd5cbcf420849d)
0x532000016fe8 is located 1560 bytes after 90576-byte region [0x532000000800,0x5320000169d0)
allocated by thread T0 here:
#0 0xaaaada0f88f4 in malloc (/work/final/Fuzzing-VTK/build/harness-asan+0xd88f4) (BuildId: 37da1d56ebb97cbdd7c9ab2560fd5cbcf420849d)
#1 0xffffa37b8980 in vtkBuffer<double>::Allocate(long long) /work/final/vtk/Common/Core/vtkBuffer.h:202:43
#2 0xffffa38316b4 in vtkAOSDataArrayTemplate<double>::ReallocateTuples(long long) /work/final/vtk/Common/Core/vtkAOSDataArrayTemplate.txx:488:21
#3 0xffffa38316b4 in vtkGenericDataArray<vtkAOSDataArrayTemplate<double>, double, 5>::ReallocateTuples(long long) /work/final/vtk/Common/Core/vtkGenericDataArray.h:358:42
#4 0xffffa38316b4 in vtkGenericDataArray<vtkAOSDataArrayTemplate<double>, double, 5>::ReserveTuples(long long) /work/final/vtk/Common/Core/vtkGenericDataArray.txx:455:14
#5 0xffffa6dbcf40 in vtkAbstractArray::ReserveValues(long long) /work/final/vtk/Common/Core/vtkAbstractArray.cxx:216:16
#6 0xffffa6dbcf40 in vtkAbstractArray::SetNumberOfValues(long long) /work/final/vtk/Common/Core/vtkAbstractArray.cxx:222:14
#7 0xffffa99e16b4 in vtkExodusIIReaderPrivate::GetCacheOrRead(vtkExodusIICacheKey) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:2547:10
#8 0xffffa99db718 in vtkExodusIIReaderPrivate::AssembleOutputPoints(long long, vtkExodusIIReaderPrivate::BlockSetInfoType*, vtkUnstructuredGrid*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:533:11
#9 0xffffa9a0cff4 in vtkExodusIIReaderPrivate::RequestData(long long, vtkMultiBlockDataSet*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:4531:15
#10 0xffffa9a18cc8 in vtkExodusIIReader::RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:5547:19
#11 0xffffa90eb5f4 in vtkExecutive::CallAlgorithm(vtkInformation*, int, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkExecutive.cxx:723:33
#12 0xffffa90d9a80 in vtkDemandDrivenPipeline::ExecuteData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:447:22
#13 0xffffa90cf350 in vtkCompositeDataPipeline::ExecuteData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkCompositeDataPipeline.cxx:151:32
#14 0xffffa90d858c in vtkDemandDrivenPipeline::ProcessRequest(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:246:22
#15 0xffffa9152d38 in vtkStreamingDemandDrivenPipeline::ProcessRequest(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkStreamingDemandDrivenPipeline.cxx
#16 0xffffa90d9444 in vtkDemandDrivenPipeline::UpdateData(int) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:404:16
#17 0xffffa9153eb8 in vtkStreamingDemandDrivenPipeline::Update(int, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkStreamingDemandDrivenPipeline.cxx:421:34
#18 0xffffa90c58a4 in vtkAlgorithm::Update(int) /work/final/vtk/Common/ExecutionModel/vtkAlgorithm.cxx:1660:32
#19 0xaaaada13a548 in main /work/final/fuzzing-vtk/exodusTestSimple.cpp:14:10
#20 0xffffa20684c0 (/lib/aarch64-linux-gnu/libc.so.6+0x284c0) (BuildId: d6c205bda1b6e91815f8fef45bdf56bc2239c37e)
#21 0xffffa2068594 in __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x28594) (BuildId: d6c205bda1b6e91815f8fef45bdf56bc2239c37e)
#22 0xaaaada055e2c in _start (/work/final/Fuzzing-VTK/build/harness-asan+0x35e2c) (BuildId: 37da1d56ebb97cbdd7c9ab2560fd5cbcf420849d)
SUMMARY: AddressSanitizer: heap-buffer-overflow /work/final/vtk/Common/Core/vtkAOSDataArrayTemplate.txx:294:36 in vtkAOSDataArrayTemplate<double>::GetTuple(long long)
Shadow bytes around the buggy address:
0x532000016d00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x532000016d80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x532000016e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x532000016e80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x532000016f00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x532000016f80: fa fa fa fa fa fa fa fa fa fa fa fa fa[fa]fa fa
0x532000017000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x532000017080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x532000017100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x532000017180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x532000017200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==88262==ABORTING
2: Nullptr Dereference
Found in tkExodusIIReaderPrivate::GetSortedObjectInfo function. Again, AFL++ found several generated test cases that trigger a nullptr dereference.
vtkExodusIIReaderPrivate::ObjectInfoType* vtkExodusIIReaderPrivate::GetSortedObjectInfo(
int otyp, int k)
{
int i = this->GetObjectTypeIndexFromObjectType(otyp);
if (i < 0)
{
vtkDebugMacro("Could not find collection of objects with type " << otyp << ".");
return nullptr;
}
int N = this->GetNumberOfObjectsAtTypeIndex(i);
if (k < 0 || k >= N)
{
const char* otname = i >= 0 ? objtype_names[i] : "object";
static_cast<void>(otname); // not referenced warning
vtkDebugMacro(
"You requested " << otname << " " << k << " in a collection of only " << N << " objects.");
return nullptr;
}
return this->GetObjectInfo(i, this->SortedObjectIndices[otyp][k]);
}
ASAN Output
e[0me[31m2026-04-18 22:07:50.524 ( 0.015s) [ FFFFA1E1C020] vtkExodusIIReader.cxx:4276 ERR| vtkExodusIIReaderPrivate (0x51900002df80): Could not read set parameters.e[0m
AddressSanitizer:DEADLYSIGNAL
=================================================================
==88570==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0xffff84b6b598 bp 0xffffecf38bc0 sp 0xffffecf38980 T0)
==88570==The signal is caused by a READ memory access.
==88570==Hint: address points to the zero page.
#0 0xffff84b6b598 in vtkExodusIIReaderPrivate::GetSortedObjectInfo(int, int) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:2954:33
#1 0xffff84b6b598 in vtkExodusIIReaderPrivate::GetObjectName(int, int) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:4845:34
#2 0xffff84b6b598 in vtkExodusIIReaderPrivate::RequestData(long long, vtkMultiBlockDataSet*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:4497:39
#3 0xffff84b78cc8 in vtkExodusIIReader::RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:5547:19
#4 0xffff840eb5f4 in vtkExecutive::CallAlgorithm(vtkInformation*, int, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkExecutive.cxx:723:33
#5 0xffff840d9a80 in vtkDemandDrivenPipeline::ExecuteData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:447:22
#6 0xffff840cf350 in vtkCompositeDataPipeline::ExecuteData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkCompositeDataPipeline.cxx:151:32
#7 0xffff840d858c in vtkDemandDrivenPipeline::ProcessRequest(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:246:22
#8 0xffff84152d38 in vtkStreamingDemandDrivenPipeline::ProcessRequest(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkStreamingDemandDrivenPipeline.cxx
#9 0xffff840d9444 in vtkDemandDrivenPipeline::UpdateData(int) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:404:16
#10 0xffff84153eb8 in vtkStreamingDemandDrivenPipeline::Update(int, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkStreamingDemandDrivenPipeline.cxx:421:34
#11 0xffff840c58a4 in vtkAlgorithm::Update(int) /work/final/vtk/Common/ExecutionModel/vtkAlgorithm.cxx:1660:32
#12 0xaaaabefea548 in main /work/final/fuzzing-vtk/exodusTestSimple.cpp:14:10
#13 0xffff7d2284c0 (/lib/aarch64-linux-gnu/libc.so.6+0x284c0) (BuildId: d6c205bda1b6e91815f8fef45bdf56bc2239c37e)
#14 0xffff7d228594 in __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x28594) (BuildId: d6c205bda1b6e91815f8fef45bdf56bc2239c37e)
#15 0xaaaabef05e2c in _start (/work/final/Fuzzing-VTK/build/harness-asan+0x35e2c) (BuildId: 37da1d56ebb97cbdd7c9ab2560fd5cbcf420849d)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:2954:33 in vtkExodusIIReaderPrivate::GetSortedObjectInfo(int, int)
==88570==ABORTING
3: Invalid Pointer Dereference
Found in vtkAOSDataArrayTemplate<long long>::GetPointer(long long). Could be caused by trying to access Buffer despite invalid contents or state.
template <class ValueTypeT>
typename vtkAOSDataArrayTemplate<ValueTypeT>::ValueType*
vtkAOSDataArrayTemplate<ValueTypeT>::GetPointer(vtkIdType valueIdx)
{
return this->Buffer->GetBuffer() + valueIdx;
}
ASAN Output
e[0me[31m2026-04-18 22:09:10.514 ( 0.013s) [ FFFF97CE4020] vtkExodusIIReader.cxx:4060 ERR| vtkExodusIIReaderPrivate (0x51900002df80): Could not read object ids for i=6 and otyp=3.e[0m
e[0me[31m2026-04-18 22:09:10.517 ( 0.016s) [ FFFF97CE4020] vtkExodusIIReader.cxx:2215 ERR| vtkExodusIIReaderPrivate (0x51900002df80): Unable to read Element block -1509949431 (index 0) nodal connectivity.e[0m
AddressSanitizer:DEADLYSIGNAL
=================================================================
==12206==ERROR: AddressSanitizer: SEGV on unknown address 0x0000000001a8 (pc 0xffff92b93950 bp 0xffffc1d70a50 sp 0xffffc1d70a50 T0)
==12206==The signal is caused by a READ memory access.
==12206==Hint: address points to the zero page.
#0 0xffff92b93950 in vtkAOSDataArrayTemplate<long long>::GetPointer(long long) /work/final/vtk/Common/Core/vtkAOSDataArrayTemplate.txx:454:16
#1 0xffff97bf0220 in vtkExodusIIReaderPrivate::GetCacheOrRead(vtkExodusIICacheKey) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:2221:22
#2 0xffff97be9ea0 in vtkExodusIIReaderPrivate::InsertBlockCells(int, int, int, int, vtkExodusIIReaderPrivate::BlockInfoType*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:1209:11
#3 0xffff97be970c in vtkExodusIIReaderPrivate::AssembleOutputConnectivity(long long, int, int, int, vtkExodusIIReaderPrivate::BlockSetInfoType*, vtkUnstructuredGrid*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:487:11
#4 0xffff97c1cfe0 in vtkExodusIIReaderPrivate::RequestData(long long, vtkMultiBlockDataSet*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:4527:15
#5 0xffff97c28cc8 in vtkExodusIIReader::RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/IO/Exodus/vtkExodusIIReader.cxx:5547:19
#6 0xffff972eb5f4 in vtkExecutive::CallAlgorithm(vtkInformation*, int, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkExecutive.cxx:723:33
#7 0xffff972d9a80 in vtkDemandDrivenPipeline::ExecuteData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:447:22
#8 0xffff972cf350 in vtkCompositeDataPipeline::ExecuteData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkCompositeDataPipeline.cxx:151:32
#9 0xffff972d858c in vtkDemandDrivenPipeline::ProcessRequest(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:246:22
#10 0xffff97352d38 in vtkStreamingDemandDrivenPipeline::ProcessRequest(vtkInformation*, vtkInformationVector**, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkStreamingDemandDrivenPipeline.cxx
#11 0xffff972d9444 in vtkDemandDrivenPipeline::UpdateData(int) /work/final/vtk/Common/ExecutionModel/vtkDemandDrivenPipeline.cxx:404:16
#12 0xffff97353eb8 in vtkStreamingDemandDrivenPipeline::Update(int, vtkInformationVector*) /work/final/vtk/Common/ExecutionModel/vtkStreamingDemandDrivenPipeline.cxx:421:34
#13 0xffff972c58a4 in vtkAlgorithm::Update(int) /work/final/vtk/Common/ExecutionModel/vtkAlgorithm.cxx:1660:32
#14 0xaaaac9d8a548 in main /work/final/fuzzing-vtk/exodusTestSimple.cpp:14:10
#15 0xffff902684c0 (/lib/aarch64-linux-gnu/libc.so.6+0x284c0) (BuildId: d6c205bda1b6e91815f8fef45bdf56bc2239c37e)
#16 0xffff90268594 in __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x28594) (BuildId: d6c205bda1b6e91815f8fef45bdf56bc2239c37e)
#17 0xaaaac9ca5e2c in _start (/work/final/Fuzzing-VTK/build/harness-asan+0x35e2c) (BuildId: 37da1d56ebb97cbdd7c9ab2560fd5cbcf420849d)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /work/final/vtk/Common/Core/vtkAOSDataArrayTemplate.txx:454:16 in vtkAOSDataArrayTemplate<long long>::GetPointer(long long)
==12206==ABORTING
Example Crashing Test Cases
Attached is a set of representing AFL++ mutated exodus files that can reproduce the results. Included is also the starting seed file which should not crash.
EDIT: New users aren’t allowed to add attachements so fell free to reach out for the example crashing files.
AI Use Disclosure
LLMs were used to help with understanding module dependencies, library modules, and general API use. No AI was used in fuzzing configuration or running experiments.