Affected Projects
assimp v5.4.3 (https://github.com/assimp/assimp)
Problem Type
CWE-122: Heap-based Buffer Overflow
Description
Summary
A heap-buffer-overflow vulnerability was discovered in the Assimp::MD3Importer::ValidateSurfaceHeaderOffsets function within the Assimp Library. This issue occurs when processing certain malformed files, leading to an out-of-bounds read and potential application crash.
Details
The vulnerability arises in the Assimp::MD3Importer::ValidateSurfaceHeaderOffsets function defined in code/AssetLib/MD3/MD3Loader.cpp at line 397. The function seems to lack judgment on pointer validity, resulting in the use of wild pointers (according to ASAN report).
void MD3Importer::ValidateSurfaceHeaderOffsets(const MD3::Surface *pcSurf) {
// Calculate the relative offset of the surface
const int32_t ofs = int32_t((const unsigned char *)pcSurf - this->mBuffer);
// Check whether all data chunks are inside the valid range
if (pcSurf->OFS_TRIANGLES + ofs + pcSurf->NUM_TRIANGLES * sizeof(MD3::Triangle) > fileSize || //heap-buffer-overflow
pcSurf->OFS_SHADERS + ofs + pcSurf->NUM_SHADER * sizeof(MD3::Shader) > fileSize ||
pcSurf->OFS_ST + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::TexCoord) > fileSize ||
pcSurf->OFS_XYZNORMAL + ofs + pcSurf->NUM_VERTICES * sizeof(MD3::Vertex) > fileSize) {
throw DeadlyImportError("Invalid MD3 surface header: some offsets are outside the file");
}
// Check whether all requirements for Q3 files are met. We don't
// care, but probably someone does.
if (pcSurf->NUM_TRIANGLES > AI_MD3_MAX_TRIANGLES) {
ASSIMP_LOG_WARN("MD3: Quake III triangle limit exceeded");
}
if (pcSurf->NUM_SHADER > AI_MD3_MAX_SHADERS) {
ASSIMP_LOG_WARN("MD3: Quake III shader limit exceeded");
}
if (pcSurf->NUM_VERTICES > AI_MD3_MAX_VERTS) {
ASSIMP_LOG_WARN("MD3: Quake III vertex limit exceeded");
}
if (pcSurf->NUM_FRAMES > AI_MD3_MAX_FRAMES) {
ASSIMP_LOG_WARN("MD3: Quake III frame limit exceeded");
}
}
PoC
Steps to reproduce:
- Clone the Assimp repository and build it using the following commands :
export CC='clang'
export CXX='clang++'
export CFLAGS='-fsanitize=address -O0 -g'
export CXXFLAGS='-fsanitize=address -O0 -g'
export LIB_FUZZING_ENGINE='-fsanitize=fuzzer'
cmake CMakeLists.txt -G "Ninja" -DBUILD_SHARED_LIBS=OFF -DASSIMP_BUILD_ZLIB=ON \
-DASSIMP_BUILD_TESTS=OFF -DASSIMP_BUILD_ASSIMP_TOOLS=OFF \
-DASSIMP_BUILD_SAMPLES=OFF
cmake --build .
- Compile the fuzzer:
$CXX $CXXFLAGS $LIB_FUZZING_ENGINE -std=c++11 -I$SRC/assimp/include \
fuzz/assimp_fuzzer.cc -o $OUT/assimp_fuzzer \
./lib/libassimp.a ./contrib/zlib/libzlibstatic.a
- Run the fuzzer to trigger the segmentation fault:
Assimp_MD3Importer_ValidateSurfaceHeaderOffsets-hbo.zip
./assimp_fuzzer ./Assimp_MD3Importer_ValidateSurfaceHeaderOffsets-hbo
Report
Running: ./Assimp_MD3Importer_ValidateSurfaceHeaderOffsets-hbo
=================================================================
==2372==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61300000279c at pc 0x5f2b6bd70119 bp 0x7ffdd7941530 sp 0x7ffdd7941528
READ of size 4 at 0x61300000279c thread T0
#0 0x5f2b6bd70118 in Assimp::MD3Importer::ValidateSurfaceHeaderOffsets(Assimp::MD3::Surface const*) /fuzz/project/assimp/code/AssetLib/MD3/MD3Loader.cpp:397:17
#1 0x5f2b6bd7732a in Assimp::MD3Importer::InternReadFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, aiScene*, Assimp::IOSystem*) /fuzz/project/assimp/code/AssetLib/MD3/MD3Loader.cpp:826:9
#2 0x5f2b6b8d2842 in Assimp::BaseImporter::ReadFile(Assimp::Importer*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Assimp::IOSystem*) /fuzz/project/assimp/code/Common/BaseImporter.cpp:131:9
#3 0x5f2b6b34ddf4 in Assimp::Importer::ReadFile(char const*, unsigned int) /fuzz/project/assimp/code/Common/Importer.cpp:709:30
#4 0x5f2b6b34b6b2 in Assimp::Importer::ReadFileFromMemory(void const*, unsigned long, unsigned int, char const*) /fuzz/project/assimp/code/Common/Importer.cpp:507:9
#5 0x5f2b6b346d27 in LLVMFuzzerTestOneInput /fuzz/project/assimp/fuzz/assimp_fuzzer.cc:57:34
#6 0x5f2b6b26d1a3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/fuzz/fuzzers/assimp_fuzzer+0x3bb1a3) (BuildId: 2e85733d2820458344d0708d9620140031cd73e3)
#7 0x5f2b6b256f1f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/fuzz/fuzzers/assimp_fuzzer+0x3a4f1f) (BuildId: 2e85733d2820458344d0708d9620140031cd73e3)
#8 0x5f2b6b25cc76 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/fuzz/fuzzers/assimp_fuzzer+0x3aac76) (BuildId: 2e85733d2820458344d0708d9620140031cd73e3)
#9 0x5f2b6b286a92 in main (/fuzz/fuzzers/assimp_fuzzer+0x3d4a92) (BuildId: 2e85733d2820458344d0708d9620140031cd73e3)
#10 0x7fc7759d1d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#11 0x7fc7759d1e3f in __libc_start_main csu/../csu/libc-start.c:392:3
#12 0x5f2b6b2517e4 in _start (/fuzz/fuzzers/assimp_fuzzer+0x39f7e4) (BuildId: 2e85733d2820458344d0708d9620140031cd73e3)
Address 0x61300000279c is a wild pointer inside of access range of size 0x000000000004.
SUMMARY: AddressSanitizer: heap-buffer-overflow /fuzz/project/assimp/code/AssetLib/MD3/MD3Loader.cpp:397:17 in Assimp::MD3Importer::ValidateSurfaceHeaderOffsets(Assimp::MD3::Surface const*)
Shadow bytes around the buggy address:
0x0c267fff84a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff84b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff84c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff84d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff84e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c267fff84f0: fa fa fa[fa]fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8510: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8520: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8530: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c267fff8540: 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
==2372==ABORTING
Affected Projects
assimp v5.4.3 (https://github.com/assimp/assimp)
Problem Type
CWE-122: Heap-based Buffer Overflow
Description
Summary
A heap-buffer-overflow vulnerability was discovered in the
Assimp::MD3Importer::ValidateSurfaceHeaderOffsetsfunction within the Assimp Library. This issue occurs when processing certain malformed files, leading to an out-of-bounds read and potential application crash.Details
The vulnerability arises in the
Assimp::MD3Importer::ValidateSurfaceHeaderOffsetsfunction defined incode/AssetLib/MD3/MD3Loader.cppat line397. The function seems to lack judgment on pointer validity, resulting in the use of wild pointers (according to ASAN report).PoC
Steps to reproduce:
Assimp_MD3Importer_ValidateSurfaceHeaderOffsets-hbo.zip
Report
Running: ./Assimp_MD3Importer_ValidateSurfaceHeaderOffsets-hbo ================================================================= ==2372==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61300000279c at pc 0x5f2b6bd70119 bp 0x7ffdd7941530 sp 0x7ffdd7941528 READ of size 4 at 0x61300000279c thread T0 #0 0x5f2b6bd70118 in Assimp::MD3Importer::ValidateSurfaceHeaderOffsets(Assimp::MD3::Surface const*) /fuzz/project/assimp/code/AssetLib/MD3/MD3Loader.cpp:397:17 #1 0x5f2b6bd7732a in Assimp::MD3Importer::InternReadFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, aiScene*, Assimp::IOSystem*) /fuzz/project/assimp/code/AssetLib/MD3/MD3Loader.cpp:826:9 #2 0x5f2b6b8d2842 in Assimp::BaseImporter::ReadFile(Assimp::Importer*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Assimp::IOSystem*) /fuzz/project/assimp/code/Common/BaseImporter.cpp:131:9 #3 0x5f2b6b34ddf4 in Assimp::Importer::ReadFile(char const*, unsigned int) /fuzz/project/assimp/code/Common/Importer.cpp:709:30 #4 0x5f2b6b34b6b2 in Assimp::Importer::ReadFileFromMemory(void const*, unsigned long, unsigned int, char const*) /fuzz/project/assimp/code/Common/Importer.cpp:507:9 #5 0x5f2b6b346d27 in LLVMFuzzerTestOneInput /fuzz/project/assimp/fuzz/assimp_fuzzer.cc:57:34 #6 0x5f2b6b26d1a3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/fuzz/fuzzers/assimp_fuzzer+0x3bb1a3) (BuildId: 2e85733d2820458344d0708d9620140031cd73e3) #7 0x5f2b6b256f1f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/fuzz/fuzzers/assimp_fuzzer+0x3a4f1f) (BuildId: 2e85733d2820458344d0708d9620140031cd73e3) #8 0x5f2b6b25cc76 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/fuzz/fuzzers/assimp_fuzzer+0x3aac76) (BuildId: 2e85733d2820458344d0708d9620140031cd73e3) #9 0x5f2b6b286a92 in main (/fuzz/fuzzers/assimp_fuzzer+0x3d4a92) (BuildId: 2e85733d2820458344d0708d9620140031cd73e3) #10 0x7fc7759d1d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #11 0x7fc7759d1e3f in __libc_start_main csu/../csu/libc-start.c:392:3 #12 0x5f2b6b2517e4 in _start (/fuzz/fuzzers/assimp_fuzzer+0x39f7e4) (BuildId: 2e85733d2820458344d0708d9620140031cd73e3) Address 0x61300000279c is a wild pointer inside of access range of size 0x000000000004. SUMMARY: AddressSanitizer: heap-buffer-overflow /fuzz/project/assimp/code/AssetLib/MD3/MD3Loader.cpp:397:17 in Assimp::MD3Importer::ValidateSurfaceHeaderOffsets(Assimp::MD3::Surface const*) Shadow bytes around the buggy address: 0x0c267fff84a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c267fff84b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c267fff84c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c267fff84d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c267fff84e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c267fff84f0: fa fa fa[fa]fa fa fa fa fa fa fa fa fa fa fa fa 0x0c267fff8500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c267fff8510: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c267fff8520: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c267fff8530: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c267fff8540: 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 ==2372==ABORTING