diff --git a/ios/samples/hello-ar/hello-ar/FilamentArView/FilamentApp.cpp b/ios/samples/hello-ar/hello-ar/FilamentArView/FilamentApp.cpp index aa8038d9657d..65133f1b2e48 100644 --- a/ios/samples/hello-ar/hello-ar/FilamentArView/FilamentApp.cpp +++ b/ios/samples/hello-ar/hello-ar/FilamentArView/FilamentApp.cpp @@ -236,7 +236,7 @@ void FilamentApp::setupMaterial() { void FilamentApp::setupMesh() { MeshReader::Mesh mesh = MeshReader::loadMeshFromBuffer(engine, RESOURCES_CUBE_DATA, - nullptr, nullptr, app.materialInstance); + RESOURCES_CUBE_SIZE, nullptr, nullptr, app.materialInstance); app.materialInstance->setParameter("baseColor", RgbType::sRGB, {0.71f, 0.0f, 0.0f}); app.renderable = mesh.renderable; diff --git a/ios/samples/hello-pbr/hello-pbr/FilamentApp.cpp b/ios/samples/hello-pbr/hello-pbr/FilamentApp.cpp index 732be6993340..d0889eafdaa5 100644 --- a/ios/samples/hello-pbr/hello-pbr/FilamentApp.cpp +++ b/ios/samples/hello-pbr/hello-pbr/FilamentApp.cpp @@ -88,7 +88,7 @@ void FilamentApp::initialize() { app.materialInstance = app.mat->createInstance(); MeshReader::Mesh mesh = MeshReader::loadMeshFromBuffer(engine, RESOURCES_MATERIAL_SPHERE_DATA, - nullptr, nullptr, app.materialInstance); + RESOURCES_MATERIAL_SPHERE_SIZE, nullptr, nullptr, app.materialInstance); app.materialInstance->setParameter("baseColor", RgbType::sRGB, {0.71f, 0.0f, 0.0f}); app.renderable = mesh.renderable; diff --git a/libs/filameshio/include/filameshio/MeshReader.h b/libs/filameshio/include/filameshio/MeshReader.h index 2253379120d7..12aa772502b0 100644 --- a/libs/filameshio/include/filameshio/MeshReader.h +++ b/libs/filameshio/include/filameshio/MeshReader.h @@ -102,7 +102,7 @@ class UTILS_PUBLIC MeshReader { * named "DefaultMaterial" to the registry. */ static Mesh loadMeshFromBuffer(filament::Engine* engine, - void const* data, Callback destructor, void* user, + void const* data, size_t dataSize, Callback destructor, void* user, MaterialRegistry& materials); /** @@ -111,7 +111,7 @@ class UTILS_PUBLIC MeshReader { * renderable are assigned the specified default material. */ static Mesh loadMeshFromBuffer(filament::Engine* engine, - void const* data, Callback destructor, void* user, + void const* data, size_t dataSize, Callback destructor, void* user, filament::MaterialInstance* defaultMaterial); }; diff --git a/libs/filameshio/src/MeshReader.cpp b/libs/filameshio/src/MeshReader.cpp index 700856177db0..2a0fae0d35f4 100644 --- a/libs/filameshio/src/MeshReader.cpp +++ b/libs/filameshio/src/MeshReader.cpp @@ -165,6 +165,9 @@ MeshReader::Mesh MeshReader::loadMeshFromFile(filament::Engine* engine, const ut Mesh mesh; int fd = open(path.c_str(), O_RDONLY); + if (fd < 0) { + return mesh; + } size_t size = fileSize(fd); char* data = (char*) malloc(size); @@ -176,7 +179,7 @@ MeshReader::Mesh MeshReader::loadMeshFromFile(filament::Engine* engine, const ut p += sizeof(MAGICID); if (!strncmp(MAGICID, magic, 8)) { - mesh = loadMeshFromBuffer(engine, data, nullptr, nullptr, materials); + mesh = loadMeshFromBuffer(engine, data, size, nullptr, nullptr, materials); } Fence::waitAndDestroy(engine->createFence()); @@ -188,42 +191,77 @@ MeshReader::Mesh MeshReader::loadMeshFromFile(filament::Engine* engine, const ut } MeshReader::Mesh MeshReader::loadMeshFromBuffer(filament::Engine* engine, - void const* data, Callback destructor, void* user, + void const* data, size_t dataSize, Callback destructor, void* user, MaterialInstance* defaultMaterial) { MaterialRegistry reg; reg.registerMaterialInstance(utils::CString(DEFAULT_MATERIAL), defaultMaterial); - return loadMeshFromBuffer(engine, data, destructor, user, reg); + return loadMeshFromBuffer(engine, data, dataSize, destructor, user, reg); } MeshReader::Mesh MeshReader::loadMeshFromBuffer(filament::Engine* engine, - void const* data, Callback destructor, void* user, + void const* data, size_t dataSize, Callback destructor, void* user, MaterialRegistry& materials) { const uint8_t* p = (const uint8_t*) data; - if (strncmp(MAGICID, (const char *) p, 8)) { + const uint8_t* const end = p + dataSize; + + if (dataSize < 8 || strncmp(MAGICID, (const char *) p, 8)) { utils::slog.e << "Magic string not found." << utils::io::endl; return {}; } p += 8; + if (size_t(end - p) < sizeof(Header)) { + utils::slog.e << "Buffer too small for header." << utils::io::endl; + return {}; + } Header* header = (Header*) p; p += sizeof(Header); + if (header->vertexSize > size_t(end - p)) { + utils::slog.e << "Invalid vertexSize." << utils::io::endl; + return {}; + } uint8_t const* vertexData = p; p += header->vertexSize; + if (header->indexSize > size_t(end - p)) { + utils::slog.e << "Invalid indexSize." << utils::io::endl; + return {}; + } uint8_t const* indices = p; p += header->indexSize; + size_t partsBytes = size_t(header->parts) * sizeof(Part); + if (header->parts != 0 && partsBytes / sizeof(Part) != header->parts) { + utils::slog.e << "Invalid parts count." << utils::io::endl; + return {}; + } + if (partsBytes > size_t(end - p)) { + utils::slog.e << "Invalid parts count." << utils::io::endl; + return {}; + } Part* parts = (Part*) p; - p += header->parts * sizeof(Part); + p += partsBytes; + if (size_t(end - p) < sizeof(uint32_t)) { + utils::slog.e << "Buffer too small for material count." << utils::io::endl; + return {}; + } uint32_t materialCount = (uint32_t) *p; p += sizeof(uint32_t); std::vector partsMaterial(materialCount); for (size_t i = 0; i < materialCount; i++) { + if (size_t(end - p) < sizeof(uint32_t)) { + utils::slog.e << "Buffer too small for material name." << utils::io::endl; + return {}; + } uint32_t nameLength = (uint32_t) *p; p += sizeof(uint32_t); + if (size_t(end - p) < nameLength + 1u) { + utils::slog.e << "Invalid material name length." << utils::io::endl; + return {}; + } partsMaterial[i] = (const char*) p; p += nameLength + 1; // null terminated } @@ -244,6 +282,10 @@ MeshReader::Mesh MeshReader::loadMeshFromBuffer(filament::Engine* engine, size_t indexSize = header->indexType == UI16 ? sizeof(uint16_t) : sizeof(uint32_t); size_t indexCount = header->indexCount; size_t uncompressedSize = indexSize * indexCount; + if (indexCount != 0 && uncompressedSize / indexCount != indexSize) { + utils::slog.e << "Index buffer size overflow." << utils::io::endl; + return {}; + } void* uncompressed = malloc(uncompressedSize); int err = meshopt_decodeIndexBuffer(uncompressed, indexCount, indexSize, indices, indicesSize); @@ -303,6 +345,10 @@ MeshReader::Mesh MeshReader::loadMeshFromBuffer(filament::Engine* engine, (hasUV1 ? sizeof(ushort2) : 0); size_t vertexCount = header->vertexCount; size_t uncompressedSize = vertexSize * vertexCount; + if (vertexCount != 0 && uncompressedSize / vertexCount != vertexSize) { + utils::slog.e << "Vertex buffer size overflow." << utils::io::endl; + return {}; + } void* uncompressed = malloc(uncompressedSize); const uint8_t* srcdata = vertexData + sizeof(CompressionHeader); int err = 0; diff --git a/libs/filameshio/tests/test_filamesh.cpp b/libs/filameshio/tests/test_filamesh.cpp index 57d3db26332c..89ced795c5fd 100644 --- a/libs/filameshio/tests/test_filamesh.cpp +++ b/libs/filameshio/tests/test_filamesh.cpp @@ -157,7 +157,7 @@ TEST_F(FilameshTest, NonInterleaved) { // Deserialize the mesh as a smoke test. MaterialInstance* mi = engine->getDefaultMaterial()->createInstance(); - auto mesh = MeshReader::loadMeshFromBuffer(engine, stream.str().data(), nullptr, nullptr, mi); + auto mesh = MeshReader::loadMeshFromBuffer(engine, stream.str().data(), stream.str().size(), nullptr, nullptr, mi); auto& rm = engine->getRenderableManager(); auto inst = rm.getInstance(mesh.renderable); EXPECT_EQ(rm.getPrimitiveCount(inst), 1); @@ -206,7 +206,7 @@ TEST_F(FilameshTest, Interleaved) { // Deserialize the mesh as a smoke test. MaterialInstance* mi = engine->getDefaultMaterial()->createInstance(); - auto mesh = MeshReader::loadMeshFromBuffer(engine, stream.str().data(), nullptr, nullptr, mi); + auto mesh = MeshReader::loadMeshFromBuffer(engine, stream.str().data(), stream.str().size(), nullptr, nullptr, mi); auto& rm = engine->getRenderableManager(); auto inst = rm.getInstance(mesh.renderable); EXPECT_EQ(rm.getPrimitiveCount(inst), 1); diff --git a/samples/hellopbr.cpp b/samples/hellopbr.cpp index 6f1f383e4e31..a672fe2efeb3 100644 --- a/samples/hellopbr.cpp +++ b/samples/hellopbr.cpp @@ -123,7 +123,7 @@ int main(int argc, char** argv) { mi->setParameter("reflectance", 0.5f); // Add geometry into the scene. - app.mesh = MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, nullptr, nullptr, mi); + app.mesh = MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, MONKEY_SUZANNE_SIZE, nullptr, nullptr, mi); auto ti = tcm.getInstance(app.mesh.renderable); app.transform = mat4f{ mat3f(1), float3(0, 0, -4) } * tcm.getWorldTransform(ti); rcm.setCastShadows(rcm.getInstance(app.mesh.renderable), false); diff --git a/samples/hellostereo.cpp b/samples/hellostereo.cpp index 668aa6263653..59a0a2669e0c 100644 --- a/samples/hellostereo.cpp +++ b/samples/hellostereo.cpp @@ -193,7 +193,7 @@ int main(int argc, char** argv) { // Add a monkey and a light source into the main scene. app.monkeyMesh = MeshReader::loadMeshFromBuffer( - engine, MONKEY_SUZANNE_DATA, nullptr, nullptr, mi); + engine, MONKEY_SUZANNE_DATA, MONKEY_SUZANNE_SIZE, nullptr, nullptr, mi); auto ti = tcm.getInstance(app.monkeyMesh.renderable); app.monkeyTransform = mat4f{mat3f(1), monkeyPosition } * tcm.getWorldTransform(ti); rcm.setCastShadows(rcm.getInstance(app.monkeyMesh.renderable), false); diff --git a/samples/materialinstancestress.cpp b/samples/materialinstancestress.cpp index 92a178b6e188..50bc0cdb13c2 100644 --- a/samples/materialinstancestress.cpp +++ b/samples/materialinstancestress.cpp @@ -207,7 +207,7 @@ int main(int argc, char** argv) { auto setup = [&app](Engine* engine, View* view, Scene* scene) { app.desiredObjectCount = app.ui.objectCountSlider; app.suzanneTemplate = MeshReader::loadMeshFromBuffer(engine, - MONKEY_SUZANNE_DATA, nullptr, nullptr, nullptr); + MONKEY_SUZANNE_DATA, MONKEY_SUZANNE_SIZE, nullptr, nullptr, nullptr); app.litMaterial = Material::Builder() .package(RESOURCES_AIDEFAULTMAT_DATA, RESOURCES_AIDEFAULTMAT_SIZE) diff --git a/samples/multiple_windows.cpp b/samples/multiple_windows.cpp index e3d665119019..f954ebf325e0 100644 --- a/samples/multiple_windows.cpp +++ b/samples/multiple_windows.cpp @@ -297,7 +297,7 @@ void setup_static_scene(Window& w, Engine* engine) { w.materialInstance->setParameter("sheenColor", 0.00f); w.materialInstance->setParameter("clearCoat", 1.00f); w.materialInstance->setParameter("clearCoatRoughness", 0.00f); - w.mesh = filamesh::MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, nullptr, nullptr, w.materialInstance); + w.mesh = filamesh::MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, MONKEY_SUZANNE_SIZE, nullptr, nullptr, w.materialInstance); w.scene->addEntity(w.mesh.renderable); int width, height; @@ -330,7 +330,7 @@ void setup_animating_scene(Window& w, Engine* engine) { w.materialInstance->setParameter("sheenColor", 0.00f); w.materialInstance->setParameter("clearCoat", 0.00f); w.materialInstance->setParameter("clearCoatRoughness", 0.00f); - w.mesh = filamesh::MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, nullptr, nullptr, w.materialInstance); + w.mesh = filamesh::MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, MONKEY_SUZANNE_SIZE, nullptr, nullptr, w.materialInstance); w.scene->addEntity(w.mesh.renderable); int width, height; diff --git a/samples/rendertarget.cpp b/samples/rendertarget.cpp index 084d316e437a..839c404c2878 100644 --- a/samples/rendertarget.cpp +++ b/samples/rendertarget.cpp @@ -276,7 +276,7 @@ int main(int argc, char** argv) { mi->setParameter("reflectance", 0.5f); // Add monkey into the scene. - app.monkeyMesh = MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, nullptr, nullptr, mi); + app.monkeyMesh = MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, MONKEY_SUZANNE_SIZE, nullptr, nullptr, mi); auto ti = tcm.getInstance(app.monkeyMesh.renderable); app.transform = mat4f{ mat3f(1), float3(0, 0, -4) } * tcm.getWorldTransform(ti); rcm.setCastShadows(rcm.getInstance(app.monkeyMesh.renderable), false); diff --git a/samples/suzanne.cpp b/samples/suzanne.cpp index cc24b9545b31..fa7ea28737cd 100644 --- a/samples/suzanne.cpp +++ b/samples/suzanne.cpp @@ -187,8 +187,8 @@ int main(int argc, char** argv) { ibl->setRotation(mat3f::rotation(0.5f, float3{ 0, 1, 0 })); // Add geometry into the scene. - app.mesh = filamesh::MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, nullptr, - nullptr, app.materialInstance); + app.mesh = filamesh::MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, + MONKEY_SUZANNE_SIZE, nullptr, nullptr, app.materialInstance); auto ti = tcm.getInstance(app.mesh.renderable); app.transform = mat4f{ mat3f(1), float3(0, 0, -4) } * tcm.getWorldTransform(ti); rcm.setCastShadows(rcm.getInstance(app.mesh.renderable), false); diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index 22c9518e3103..629207dc9d2a 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -1907,7 +1907,7 @@ class_("MeshReader") }; // Parse the filamesh buffer. This creates the VB, IB, and renderable. return MeshReader::loadMeshFromBuffer( - engine, buffer.bd->buffer, + engine, buffer.bd->buffer, buffer.bd->size, destructor, bundle, matreg); }), allow_raw_pointers());