Repository: assimp/assimp (language: python)

Issue:
Bug : invalid test file(heap-buffer-overflow)::importBinaryPLY
Describe the bug
A bug was found within the assimp. Though it might not be an intended use of the relevant API, the bug can still produce critical issues within a program using assimp. It would be best if the affected logic is checked beforehand.
The bug was found with a fuzzer based on the function "utPLYImportExport.importBinaryPLY"
This may cause problems in the use of libraries
When you read this test file
heap buffer overflow is triggered during the Running InternReadFile function
I think this code is needed to be exceptional processing for the unintended number.

==49972==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x608000001da0 at pc 0x0000006070e3 bp 0x7ffeedc90c50 sp 0x7ffeedc90c48
READ of size 4 at 0x608000001da0 thread T0
    #0 0x6070e2 in aiVector3t<float>::operator==(aiVector3t<float> const&) const assimp/include/assimp/vector3.inl:201:23
    #1 0xc28c1a in Assimp::FindDegeneratesProcess::ExecuteOnMesh(aiMesh*) assimp/code/PostProcessing/FindDegenerates.cpp:194:58
    #2 0xc27928 in Assimp::FindDegeneratesProcess::Execute(aiScene*) assimp/code/PostProcessing/FindDegenerates.cpp:101:96
    #3 0x273ff3c in Assimp::BaseProcess::ExecuteOnScene(Assimp::Importer*) assimp/code/Common/BaseProcess.cpp:78:9
    #4 0xb69406 in Assimp::Importer::ApplyPostProcessing(unsigned int) assimp/code/Common/Importer.cpp:807:22
    #5 0xb66a47 in Assimp::Importer::ReadFile(char const*, unsigned int) assimp/code/Common/Importer.cpp:717:13

How To Reproduce
Download the attached file
Execute reproduce.sh
assimp/build/bin/unit --gtest_filter="utPLYImportExport.importBinaryPLY"


Expected behavior
This can always cause problems when reading an invalid test file. Exception handling is required for reading an invalid test file.

Platform (please complete the following information):
OS: Ubuntu 18.04
[assimp_bug11.tar.gz](https://github.com/assimp/assimp/files/7778052/assimp_bug11.tar.gz)




Discussion / hints:

Fix patch:
diff --git a/code/PostProcessing/FindDegenerates.cpp b/code/PostProcessing/FindDegenerates.cpp
index c506b08b58..7401ea0e7d 100644
--- a/code/PostProcessing/FindDegenerates.cpp
+++ b/code/PostProcessing/FindDegenerates.cpp
@@ -143,9 +143,13 @@ bool FindDegeneratesProcess::ExecuteOnMesh(aiMesh *mesh) {
     for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
         aiFace &face = mesh->mFaces[a];
         bool first = true;
+        auto vertex_in_range = [numVertices = mesh->mNumVertices](unsigned int vertex_idx) { return vertex_idx < numVertices; };
 
         // check whether the face contains degenerated entries
         for (unsigned int i = 0; i < face.mNumIndices; ++i) {
+            if (!std::all_of(face.mIndices, face.mIndices + face.mNumIndices, vertex_in_range))
+                continue;
+
             // Polygons with more than 4 points are allowed to have double points, that is
             // simulating polygons with holes just with concave polygons. However,
             // double points may not come directly after another.


Test patch:
diff --git a/test/unit/utFindDegenerates.cpp b/test/unit/utFindDegenerates.cpp
index 04f554716e..405c352307 100644
--- a/test/unit/utFindDegenerates.cpp
+++ b/test/unit/utFindDegenerates.cpp
@@ -206,3 +206,38 @@ TEST_F(FindDegeneratesProcessTest, meshRemoval) {
     EXPECT_EQ(scene->mRootNode->mNumMeshes, 1u);
     EXPECT_EQ(scene->mRootNode->mMeshes[0], 0u);
 }
+
+TEST_F(FindDegeneratesProcessTest, invalidVertexIndex) {
+    mProcess->EnableAreaCheck(true);
+    mProcess->EnableInstantRemoval(true);
+    mProcess->ExecuteOnMesh(mMesh);
+
+    std::unique_ptr<aiScene> scene(new aiScene);
+    scene->mNumMeshes = 1;
+    scene->mMeshes = new aiMesh *[1];
+
+    std::unique_ptr<aiMesh> mesh(new aiMesh);
+    mesh->mNumVertices = 1;
+    mesh->mVertices = new aiVector3D[1];
+    mesh->mVertices[0] = aiVector3D{ 0.0f, 0.0f, 0.0f };
+    mesh->mNumFaces = 1;
+    mesh->mFaces = new aiFace[1];
+    mesh->mFaces[0].mNumIndices = 3;
+    mesh->mFaces[0].mIndices = new unsigned int[3];
+    mesh->mFaces[0].mIndices[0] = 0;
+    mesh->mFaces[0].mIndices[1] = 1;
+    mesh->mFaces[0].mIndices[2] = 99999;
+
+    scene->mMeshes[0] = mesh.release();
+
+    scene->mRootNode = new aiNode;
+    scene->mRootNode->mNumMeshes = 1;
+    scene->mRootNode->mMeshes = new unsigned int[1];
+    scene->mRootNode->mMeshes[0] = 0;
+
+    mProcess->Execute(scene.get());
+
+    EXPECT_EQ(scene->mNumMeshes, 1u);
+    EXPECT_EQ(scene->mRootNode->mNumMeshes, 1u);
+    EXPECT_EQ(scene->mRootNode->mMeshes[0], 0u);
+}