diff --git a/src/draco/io/obj_decoder.cc b/src/draco/io/obj_decoder.cc index 15ef51c42..46d2d8051 100644 --- a/src/draco/io/obj_decoder.cc +++ b/src/draco/io/obj_decoder.cc @@ -447,7 +447,11 @@ bool ObjDecoder::ParseFace(Status *status) { for (int c = 0; c < 3; c++) { const PointIndex vert_id(3 * num_obj_faces_ + c); const int triangulated_index = Triangulate(t, c); - MapPointToVertexIndices(vert_id, indices[triangulated_index]); + if (!MapPointToVertexIndices(vert_id, indices[triangulated_index])) { + *status = Status(Status::DRACO_ERROR, + "OBJ: negative index out of range"); + return true; + } // Save info about new edges that will allow us to reconstruct polygons. if (added_edge_att_id_ >= 0) { const AttributeValueIndex avi(IsNewEdge(nt, t, c)); @@ -631,7 +635,7 @@ bool ObjDecoder::ParseVertexIndices(std::array *out_indices) { return true; } -void ObjDecoder::MapPointToVertexIndices( +bool ObjDecoder::MapPointToVertexIndices( PointIndex vert_id, const std::array &indices) { // Use face entries to store mapping between vertex and attribute indices // (positions, texture coordinates and normal indices). @@ -643,6 +647,9 @@ void ObjDecoder::MapPointToVertexIndices( out_point_cloud_->attribute(pos_att_id_) ->SetPointMapEntry(vert_id, AttributeValueIndex(indices[0] - 1)); } else if (indices[0] < 0) { + if (-indices[0] > num_positions_) { + return false; + } out_point_cloud_->attribute(pos_att_id_) ->SetPointMapEntry(vert_id, AttributeValueIndex(num_positions_ + indices[0])); @@ -653,6 +660,9 @@ void ObjDecoder::MapPointToVertexIndices( out_point_cloud_->attribute(tex_att_id_) ->SetPointMapEntry(vert_id, AttributeValueIndex(indices[1] - 1)); } else if (indices[1] < 0) { + if (-indices[1] > num_tex_coords_) { + return false; + } out_point_cloud_->attribute(tex_att_id_) ->SetPointMapEntry(vert_id, AttributeValueIndex(num_tex_coords_ + indices[1])); @@ -669,6 +679,9 @@ void ObjDecoder::MapPointToVertexIndices( out_point_cloud_->attribute(norm_att_id_) ->SetPointMapEntry(vert_id, AttributeValueIndex(indices[2] - 1)); } else if (indices[2] < 0) { + if (-indices[2] > num_normals_) { + return false; + } out_point_cloud_->attribute(norm_att_id_) ->SetPointMapEntry(vert_id, AttributeValueIndex(num_normals_ + indices[2])); @@ -691,6 +704,7 @@ void ObjDecoder::MapPointToVertexIndices( out_point_cloud_->attribute(sub_obj_att_id_) ->SetPointMapEntry(vert_id, AttributeValueIndex(last_sub_obj_id_)); } + return true; } bool ObjDecoder::ParseMaterialFile(const std::string &file_name, diff --git a/src/draco/io/obj_decoder.h b/src/draco/io/obj_decoder.h index 18dc9aadd..1294a21ce 100644 --- a/src/draco/io/obj_decoder.h +++ b/src/draco/io/obj_decoder.h @@ -87,7 +87,7 @@ class ObjDecoder { // Maps specified point index to the parsed vertex indices (triplet of // position, texture coordinate, and normal indices) . - void MapPointToVertexIndices(PointIndex vert_id, + bool MapPointToVertexIndices(PointIndex vert_id, const std::array &indices); // Parses material file definitions from a separate file. diff --git a/src/draco/io/ply_reader.cc b/src/draco/io/ply_reader.cc index 0da9ab5fe..9976bb965 100644 --- a/src/draco/io/ply_reader.cc +++ b/src/draco/io/ply_reader.cc @@ -203,6 +203,10 @@ bool PlyReader::ParseElementData(DecoderBuffer *buffer, int element_index) { // Read and store the actual property data const int64_t num_bytes_to_read = prop.data_type_num_bytes() * num_entries; + if (num_entries < 0 || + num_bytes_to_read > buffer->remaining_size()) { + return false; + } prop.data_.insert(prop.data_.end(), buffer->data_head(), buffer->data_head() + num_bytes_to_read); buffer->Advance(num_bytes_to_read); diff --git a/src/draco/io/stl_decoder.cc b/src/draco/io/stl_decoder.cc index 1e5d3a938..b5cdfd9f1 100644 --- a/src/draco/io/stl_decoder.cc +++ b/src/draco/io/stl_decoder.cc @@ -41,9 +41,14 @@ StatusOr> StlDecoder::DecodeFromBuffer( return Status(Status::IO_ERROR, "Currently only binary STL files are supported."); } + if (buffer->remaining_size() < 80) { + return Status(Status::IO_ERROR, "STL: truncated header"); + } buffer->Advance(80); uint32_t face_count; - buffer->Decode(&face_count, 4); + if (!buffer->Decode(&face_count, 4)) { + return Status(Status::IO_ERROR, "STL: truncated face count"); + } TriangleSoupMeshBuilder builder; builder.Start(face_count); @@ -55,9 +60,13 @@ StatusOr> StlDecoder::DecodeFromBuffer( for (uint32_t i = 0; i < face_count; i++) { float data[48]; - buffer->Decode(data, 48); + if (!buffer->Decode(data, 48)) { + return Status(Status::IO_ERROR, "STL: truncated face data"); + } uint16_t unused; - buffer->Decode(&unused, 2); + if (!buffer->Decode(&unused, 2)) { + return Status(Status::IO_ERROR, "STL: truncated face data"); + } builder.SetPerFaceAttributeValueForFace( norm_att_id, draco::FaceIndex(i),