gltfio: Fix vulnerabilities in ResourceLoader.cpp
- Implement PR #9878 to add bounds checking in normalizeSkinningWeights, preventing heap OOB write by clamping the count to available buffer size. - Fix 3 similar vulnerabilities in uploadBuffers where accessor->count was trusted for malloc allocation before cgltf_accessor_unpack_floats. - Add overflow checks for allocation sizes in uploadBuffers. - Clamp accessor count based on available buffer bytes in uploadBuffers to prevent OOB read.
This commit is contained in:
committed by
Mathias Agopian
parent
a943b57c86
commit
8d16ad8882
@@ -24,6 +24,7 @@
|
||||
#include "Utility.h"
|
||||
#include "extended/ResourceLoaderExtended.h"
|
||||
|
||||
#include <limits>
|
||||
#include <filament/BufferObject.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndexBuffer.h>
|
||||
@@ -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<size_t>::max() / components) {
|
||||
continue;
|
||||
}
|
||||
const size_t floatsCount = accessor->count * components;
|
||||
|
||||
if (floatsCount > std::numeric_limits<size_t>::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<size_t>::max() / components) {
|
||||
continue;
|
||||
}
|
||||
const size_t floatsCount = safeCount * components;
|
||||
|
||||
if (floatsCount > std::numeric_limits<size_t>::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<size_t>::max() / components) {
|
||||
continue;
|
||||
}
|
||||
const size_t floatsCount = safeCount * components;
|
||||
|
||||
if (floatsCount > std::numeric_limits<size_t>::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) {
|
||||
|
||||
Reference in New Issue
Block a user