More GLTF loading hardening (#5415)

Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
pull/5431/head^2
Florian Born 2024-02-04 21:23:31 +01:00 committed by GitHub
parent b7b6601a75
commit f59a5fab1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 9 deletions

View File

@ -547,7 +547,7 @@ struct BufferView : public Object {
BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
void Read(Value &obj, Asset &r);
uint8_t *GetPointer(size_t accOffset);
uint8_t *GetPointerAndTailSize(size_t accOffset, size_t& outTailSize);
};
//! A typed view into a BufferView. A BufferView contains raw binary data.
@ -629,7 +629,7 @@ struct Accessor : public Object {
std::vector<uint8_t> data; //!< Actual data, which may be defaulted to an array of zeros or the original data, with the sparse buffer view applied on top of it.
void PopulateData(size_t numBytes, uint8_t *bytes);
void PopulateData(size_t numBytes, const uint8_t *bytes);
void PatchData(unsigned int elementSize);
};
};

View File

@ -785,12 +785,14 @@ inline void BufferView::Read(Value &obj, Asset &r) {
}
}
inline uint8_t *BufferView::GetPointer(size_t accOffset) {
inline uint8_t *BufferView::GetPointerAndTailSize(size_t accOffset, size_t& outTailSize) {
if (!buffer) {
outTailSize = 0;
return nullptr;
}
uint8_t *basePtr = buffer->GetPointer();
uint8_t * const basePtr = buffer->GetPointer();
if (!basePtr) {
outTailSize = 0;
return nullptr;
}
@ -799,17 +801,25 @@ inline uint8_t *BufferView::GetPointer(size_t accOffset) {
const size_t begin = buffer->EncodedRegion_Current->Offset;
const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
if ((offset >= begin) && (offset < end)) {
outTailSize = end - offset;
return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
}
}
if (offset >= buffer->byteLength)
{
outTailSize = 0;
return nullptr;
}
outTailSize = buffer->byteLength - offset;
return basePtr + offset;
}
//
// struct Accessor
//
inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
inline void Accessor::Sparse::PopulateData(size_t numBytes, const uint8_t *bytes) {
if (bytes) {
data.assign(bytes, bytes + numBytes);
} else {
@ -818,11 +828,21 @@ inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
}
inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
uint8_t *pIndices = indices->GetPointer(indicesByteOffset);
size_t indicesTailDataSize;
uint8_t *pIndices = indices->GetPointerAndTailSize(indicesByteOffset, indicesTailDataSize);
const unsigned int indexSize = int(ComponentTypeSize(indicesType));
uint8_t *indicesEnd = pIndices + count * indexSize;
uint8_t *pValues = values->GetPointer(valuesByteOffset);
if ((uint64_t)indicesEnd > (uint64_t)pIndices + indicesTailDataSize) {
throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory.");
}
size_t valuesTailDataSize;
uint8_t* pValues = values->GetPointerAndTailSize(valuesByteOffset, valuesTailDataSize);
if (elementSize * count > valuesTailDataSize) {
throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory.");
}
while (pIndices != indicesEnd) {
size_t offset;
switch (indicesType) {
@ -894,6 +914,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
//indices bufferView
Value *indiceViewID = FindUInt(*indicesValue, "bufferView");
if (!indiceViewID) {
throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
}
sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint());
//indices byteOffset
sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0));
@ -909,6 +932,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
if (Value *valuesValue = FindObject(*sparseValue, "values")) {
//value bufferView
Value *valueViewID = FindUInt(*valuesValue, "bufferView");
if (!valueViewID) {
throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
}
sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint());
//value byteOffset
sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0));
@ -918,8 +944,18 @@ inline void Accessor::Read(Value &obj, Asset &r) {
const unsigned int elementSize = GetElementSize();
const size_t dataSize = count * elementSize;
sparse->PopulateData(dataSize, bufferView ? bufferView->GetPointer(byteOffset) : nullptr);
sparse->PatchData(elementSize);
if (bufferView) {
size_t bufferViewTailSize;
const uint8_t* bufferViewPointer = bufferView->GetPointerAndTailSize(byteOffset, bufferViewTailSize);
if (dataSize > bufferViewTailSize) {
throw DeadlyImportError("Invalid buffer when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
}
sparse->PopulateData(dataSize, bufferViewPointer);
}
else {
sparse->PopulateData(dataSize, nullptr);
}
sparse->PatchData(elementSize);
}
}