浏览代码

More GLTF loading hardening (#5415)

Co-authored-by: Kim Kulling <[email protected]>
Florian Born 1 年之前
父节点
当前提交
f59a5fab1a
共有 2 个文件被更改,包括 45 次插入9 次删除
  1. 2 2
      code/AssetLib/glTF2/glTF2Asset.h
  2. 43 7
      code/AssetLib/glTF2/glTF2Asset.inl

+ 2 - 2
code/AssetLib/glTF2/glTF2Asset.h

@@ -547,7 +547,7 @@ struct BufferView : public Object {
     BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
     BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
 
 
     void Read(Value &obj, Asset &r);
     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.
 //! 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.
         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);
         void PatchData(unsigned int elementSize);
     };
     };
 };
 };

+ 43 - 7
code/AssetLib/glTF2/glTF2Asset.inl

@@ -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) {
     if (!buffer) {
+        outTailSize = 0;
         return nullptr;
         return nullptr;
     }
     }
-    uint8_t *basePtr = buffer->GetPointer();
+    uint8_t * const basePtr = buffer->GetPointer();
     if (!basePtr) {
     if (!basePtr) {
+        outTailSize = 0;
         return nullptr;
         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 begin = buffer->EncodedRegion_Current->Offset;
         const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
         const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
         if ((offset >= begin) && (offset < end)) {
         if ((offset >= begin) && (offset < end)) {
+            outTailSize = end - offset;
             return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
             return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
         }
         }
     }
     }
 
 
+    if (offset >= buffer->byteLength)
+    {
+        outTailSize = 0;
+        return nullptr;
+    }
+    
+    outTailSize = buffer->byteLength - offset;
     return basePtr + offset;
     return basePtr + offset;
 }
 }
 
 
 //
 //
 // struct Accessor
 // 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) {
     if (bytes) {
         data.assign(bytes, bytes + numBytes);
         data.assign(bytes, bytes + numBytes);
     } else {
     } else {
@@ -818,11 +828,21 @@ inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
 }
 }
 
 
 inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
 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));
     const unsigned int indexSize = int(ComponentTypeSize(indicesType));
     uint8_t *indicesEnd = pIndices + count * indexSize;
     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) {
     while (pIndices != indicesEnd) {
         size_t offset;
         size_t offset;
         switch (indicesType) {
         switch (indicesType) {
@@ -894,6 +914,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
         if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
         if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
             //indices bufferView
             //indices bufferView
             Value *indiceViewID = FindUInt(*indicesValue, "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());
             sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint());
             //indices byteOffset
             //indices byteOffset
             sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0));
             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")) {
         if (Value *valuesValue = FindObject(*sparseValue, "values")) {
             //value bufferView
             //value bufferView
             Value *valueViewID = FindUInt(*valuesValue, "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());
             sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint());
             //value byteOffset
             //value byteOffset
             sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0));
             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 unsigned int elementSize = GetElementSize();
         const size_t dataSize = count * elementSize;
         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);
     }
     }
 }
 }