From 991cb7781638e06f36740dc6463faf88302ef9ec Mon Sep 17 00:00:00 2001 From: mohammadmseet-hue Date: Thu, 2 Apr 2026 06:13:32 +0200 Subject: [PATCH] fix: add integer overflow checks for face/point count multiplications Multiple locations in the Unity plugin, JavaScript/WASM wrapper, and Maya plugin compute buffer sizes as num_faces * 3 or num_points * N without checking for integer overflow. When the product overflows (wraps to a small value), a tiny buffer is allocated and subsequent loops write the full count of entries, causing a heap buffer overflow. This is exploitable on 32-bit platforms (WASM32, 32-bit Unity builds) where the overflow threshold is practical (e.g., num_faces > ~1.4 billion causes num_faces * 3 to wrap). Affected locations: - unity/draco_unity_plugin.cc: GetMeshIndices, DecodeDracoMeshStep2 (indices, positions, normals, colors, texcoords) - javascript/emscripten/decoder_webidl_wrapper.cc: GetTrianglesArray - maya/draco_maya_plugin.cc: decode_faces Fix: add overflow checks before each unchecked multiplication. --- .../emscripten/decoder_webidl_wrapper.cc | 6 +++++- src/draco/maya/draco_maya_plugin.cc | 4 ++++ src/draco/unity/draco_unity_plugin.cc | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc b/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc index 034f3c3b4..f9596ba01 100644 --- a/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc +++ b/src/draco/javascript/emscripten/decoder_webidl_wrapper.cc @@ -175,7 +175,11 @@ template bool GetTrianglesArray(const draco::Mesh &m, const int out_size, T *out_values) { const uint32_t num_faces = m.num_faces(); - if (num_faces * 3 * sizeof(T) != out_size) { + // Check for integer overflow before size comparison. + const uint64_t required_size = + static_cast(num_faces) * 3 * sizeof(T); + if (required_size > static_cast(out_size) || + static_cast(required_size) != out_size) { return false; } diff --git a/src/draco/maya/draco_maya_plugin.cc b/src/draco/maya/draco_maya_plugin.cc index 25b0240b2..5fb027c18 100644 --- a/src/draco/maya/draco_maya_plugin.cc +++ b/src/draco/maya/draco_maya_plugin.cc @@ -20,6 +20,10 @@ namespace maya { static void decode_faces(std::unique_ptr &drc_mesh, Drc2PyMesh *out_mesh) { int num_faces = drc_mesh->num_faces(); + // Check for integer overflow in num_faces * 3. + if (num_faces < 0 || static_cast(num_faces) * 3 > SIZE_MAX / sizeof(int)) { + return; + } out_mesh->faces = new int[num_faces * 3]; out_mesh->faces_num = num_faces; for (int i = 0; i < num_faces; i++) { diff --git a/src/draco/unity/draco_unity_plugin.cc b/src/draco/unity/draco_unity_plugin.cc index e80279b89..61f2fe24a 100644 --- a/src/draco/unity/draco_unity_plugin.cc +++ b/src/draco/unity/draco_unity_plugin.cc @@ -236,6 +236,10 @@ bool EXPORT_API GetMeshIndices(const DracoMesh *mesh, DracoData **indices) { return false; } const Mesh *const m = static_cast(mesh->private_mesh); + // Check for integer overflow in num_faces * 3. + if (m->num_faces() > SIZE_MAX / 3 / sizeof(int)) { + return false; + } int *const temp_indices = new int[m->num_faces() * 3]; for (draco::FaceIndex face_id(0); face_id < m->num_faces(); ++face_id) { const Mesh::Face &face = m->face(draco::FaceIndex(face_id)); @@ -328,6 +332,11 @@ int DecodeMeshForUnity(char *data, unsigned int length, unity_mesh->num_faces = in_mesh->num_faces(); unity_mesh->num_vertices = in_mesh->num_points(); + // Check for integer overflow in num_faces * 3. + if (in_mesh->num_faces() > SIZE_MAX / 3 / sizeof(int)) { + ReleaseUnityMesh(&unity_mesh); + return -4; + } unity_mesh->indices = new int[in_mesh->num_faces() * 3]; for (draco::FaceIndex face_id(0); face_id < in_mesh->num_faces(); ++face_id) { const Mesh::Face &face = in_mesh->face(draco::FaceIndex(face_id)); @@ -336,6 +345,11 @@ int DecodeMeshForUnity(char *data, unsigned int length, } // TODO(draco-eng): Add other attributes. + // Check for integer overflow in num_points * components * sizeof(float). + if (in_mesh->num_points() > SIZE_MAX / 4 / sizeof(float)) { + ReleaseUnityMesh(&unity_mesh); + return -4; + } unity_mesh->position = new float[in_mesh->num_points() * 3]; const auto pos_att = in_mesh->GetNamedAttribute(draco::GeometryAttribute::POSITION);