diff --git a/libs/gltfio/src/ResourceLoader.cpp b/libs/gltfio/src/ResourceLoader.cpp index ec1da42743..6571c83ba7 100644 --- a/libs/gltfio/src/ResourceLoader.cpp +++ b/libs/gltfio/src/ResourceLoader.cpp @@ -24,6 +24,7 @@ #include "Utility.h" #include "extended/ResourceLoaderExtended.h" +#include #include #include #include @@ -163,9 +164,40 @@ inline void normalizeSkinningWeights(cgltf_data const* gltf) { LOG(WARNING) << "Cannot normalize weights, unsupported attribute type."; return; } + if (!data->buffer_view || !data->buffer_view->buffer || + !data->buffer_view->buffer->data) { + LOG(WARNING) << "Cannot normalize weights, missing buffer data."; + return; + } + const cgltf_size bufferSize = data->buffer_view->buffer->size; + const cgltf_size viewOffset = data->buffer_view->offset; + const cgltf_size accessorOffset = data->offset; + const cgltf_size totalOffset = viewOffset + accessorOffset; + + if (totalOffset >= bufferSize) { + LOG(WARNING) << "Cannot normalize weights, accessor offset exceeds buffer size."; + return; + } + + const cgltf_size availableBytes = bufferSize - totalOffset; + const cgltf_size stride = data->stride; + + cgltf_size maxCount = 0; + if (stride > 0 && availableBytes >= sizeof(float4)) { + maxCount = 1 + (availableBytes - sizeof(float4)) / stride; + } + + cgltf_size safeCount = data->count; + if (safeCount > maxCount) { + LOG(WARNING) << "Skinning weights accessor count (" << safeCount + << ") exceeds buffer capacity (" << maxCount + << "), clamping to prevent out-of-bounds access."; + safeCount = maxCount; + } + uint8_t* bytes = (uint8_t*) data->buffer_view->buffer->data; - bytes += data->offset + data->buffer_view->offset; - for (cgltf_size i = 0, n = data->count; i < n; ++i, bytes += data->stride) { + bytes += totalOffset; + for (cgltf_size i = 0, n = safeCount; i < n; ++i, bytes += stride) { float4* weights = (float4*) bytes; const float sum = weights->x + weights->y + weights->z + weights->w; *weights /= sum; @@ -243,8 +275,17 @@ inline void uploadBuffers(FFilamentAsset* asset, Engine& engine, // For morph targets without buffer_view, use cgltf_accessor_unpack_floats to unpack data directly if (!accessor->buffer_view && isMorphTarget) { - const size_t floatsCount = accessor->count * cgltf_num_components(accessor->type); + const size_t components = cgltf_num_components(accessor->type); + if (components > 0 && accessor->count > std::numeric_limits::max() / components) { + continue; + } + const size_t floatsCount = accessor->count * components; + + if (floatsCount > std::numeric_limits::max() / sizeof(float)) { + continue; + } const size_t floatsByteCount = sizeof(float) * floatsCount; + float* floatsData = (float*)malloc(floatsByteCount); cgltf_accessor_unpack_floats(accessor, floatsData, floatsCount); @@ -279,8 +320,39 @@ inline void uploadBuffers(FFilamentAsset* asset, Engine& engine, } if (slot.vertexBuffer) { if (utility::requiresConversion(accessor)) { - const size_t floatsCount = accessor->count * cgltf_num_components(accessor->type); + const cgltf_size bufferSize = accessor->buffer_view->buffer->size; + const cgltf_size totalOffset = accessor->buffer_view->offset + accessor->offset; + + if (totalOffset >= bufferSize) { + continue; + } + + const cgltf_size availableBytes = bufferSize - totalOffset; + const cgltf_size stride = accessor->stride; + const cgltf_size elementSize = cgltf_calc_size(accessor->type, accessor->component_type); + + cgltf_size maxCount = 0; + if (stride > 0 && availableBytes >= elementSize) { + maxCount = 1 + (availableBytes - elementSize) / stride; + } + + cgltf_size safeCount = accessor->count; + if (safeCount > maxCount) { + LOG(WARNING) << "Accessor count exceeds buffer capacity, clamping."; + safeCount = maxCount; + } + + const size_t components = cgltf_num_components(accessor->type); + if (components > 0 && safeCount > std::numeric_limits::max() / components) { + continue; + } + const size_t floatsCount = safeCount * components; + + if (floatsCount > std::numeric_limits::max() / sizeof(float)) { + continue; + } const size_t floatsByteCount = sizeof(float) * floatsCount; + float* floatsData = (float*) malloc(floatsByteCount); cgltf_accessor_unpack_floats(accessor, floatsData, floatsCount); BufferObject* bo = BufferObject::Builder().size(floatsByteCount).build(engine); @@ -317,8 +389,39 @@ inline void uploadBuffers(FFilamentAsset* asset, Engine& engine, assert(slot.morphTargetBuffer); if (utility::requiresPacking(accessor)) { - const size_t floatsCount = accessor->count * cgltf_num_components(accessor->type); + const cgltf_size bufferSize = accessor->buffer_view->buffer->size; + const cgltf_size totalOffset = accessor->buffer_view->offset + accessor->offset; + + if (totalOffset >= bufferSize) { + continue; + } + + const cgltf_size availableBytes = bufferSize - totalOffset; + const cgltf_size stride = accessor->stride; + const cgltf_size elementSize = cgltf_calc_size(accessor->type, accessor->component_type); + + cgltf_size maxCount = 0; + if (stride > 0 && availableBytes >= elementSize) { + maxCount = 1 + (availableBytes - elementSize) / stride; + } + + cgltf_size safeCount = accessor->count; + if (safeCount > maxCount) { + LOG(WARNING) << "Accessor count exceeds buffer capacity, clamping."; + safeCount = maxCount; + } + + const size_t components = cgltf_num_components(accessor->type); + if (components > 0 && safeCount > std::numeric_limits::max() / components) { + continue; + } + const size_t floatsCount = safeCount * components; + + if (floatsCount > std::numeric_limits::max() / sizeof(float)) { + continue; + } const size_t floatsByteCount = sizeof(float) * floatsCount; + float* floatsData = (float*) malloc(floatsByteCount); cgltf_accessor_unpack_floats(accessor, floatsData, floatsCount); if (accessor->type == cgltf_type_vec3) {