From f68587ff2c8f6bcea10715563a30ac62b237f701 Mon Sep 17 00:00:00 2001 From: Lucas Wang Date: Mon, 8 Jun 2026 23:34:14 +0800 Subject: [PATCH] Fix heap OOB read in STL decoder from missing buffer bounds checks StlDecoder::DecodeFromBuffer reads header bytes, face count, and per-face data without verifying the buffer is large enough. A truncated STL file causes a heap-buffer-overflow read. - Require at least 84 bytes before reading header + face count - Check Decode() return values instead of ignoring them - Validate face_count against remaining buffer before the parse loop --- src/draco/io/stl_decoder.cc | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/draco/io/stl_decoder.cc b/src/draco/io/stl_decoder.cc index 1e5d3a938..a69a07793 100644 --- a/src/draco/io/stl_decoder.cc +++ b/src/draco/io/stl_decoder.cc @@ -37,13 +37,25 @@ StatusOr> StlDecoder::DecodeFromFile( StatusOr> StlDecoder::DecodeFromBuffer( DecoderBuffer *buffer) { + // Binary STL requires at least an 80-byte header + 4-byte face count. + if (buffer->remaining_size() < 84) { + return Status(Status::IO_ERROR, "STL file too small."); + } if (!strncmp(buffer->data_head(), "solid ", 6)) { return Status(Status::IO_ERROR, "Currently only binary STL files are supported."); } buffer->Advance(80); uint32_t face_count; - buffer->Decode(&face_count, 4); + if (!buffer->Decode(&face_count, 4)) { + return Status(Status::IO_ERROR, "Failed to read STL face count."); + } + // Each face is 50 bytes (12 floats = 48 bytes + 2-byte attribute). + constexpr int64_t kBytesPerFace = 50; + if (face_count > + static_cast(buffer->remaining_size()) / kBytesPerFace) { + return Status(Status::IO_ERROR, "STL face count exceeds available data."); + } TriangleSoupMeshBuilder builder; builder.Start(face_count); @@ -55,9 +67,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, "Failed to read STL face data."); + } uint16_t unused; - buffer->Decode(&unused, 2); + if (!buffer->Decode(&unused, 2)) { + return Status(Status::IO_ERROR, "Failed to read STL face attribute."); + } builder.SetPerFaceAttributeValueForFace( norm_att_id, draco::FaceIndex(i),