From 703ccc93b928aa1d290372fc7d37435a60f22671 Mon Sep 17 00:00:00 2001 From: Song Date: Wed, 6 May 2026 19:15:56 +0000 Subject: [PATCH] fix: validate OBJ face indices against declared v/vt/vn counts (#1194) ParseVertexIndices accepted any non-zero face index without checking it against the number of declared v/vt/vn entries. Out-of-range indices propagated through MapPointToVertexIndices into the attribute dedup stage, causing a heap-buffer-overflow read in PointAttribute::DeduplicateFormattedValues. Add bounds validation in ParseVertexIndices for position, texcoord, and normal indices (both positive and negative OBJ forms) so the decoder rejects malformed faces at parse time rather than crashing downstream. --- src/draco/io/obj_decoder.cc | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/draco/io/obj_decoder.cc b/src/draco/io/obj_decoder.cc index 15ef51c42..4c07d4dac 100644 --- a/src/draco/io/obj_decoder.cc +++ b/src/draco/io/obj_decoder.cc @@ -598,12 +598,28 @@ bool ObjDecoder::ParseVertexIndices(std::array *out_indices) { return false; // Position index must be present and valid. } (*out_indices)[1] = (*out_indices)[2] = 0; + const auto indices_in_bounds = [this, out_indices]() { + if ((*out_indices)[0] > num_positions_ || + (*out_indices)[0] < -num_positions_) { + return false; + } + if ((*out_indices)[1] != 0 && ((*out_indices)[1] > num_tex_coords_ || + (*out_indices)[1] < -num_tex_coords_)) { + return false; + } + if ((*out_indices)[2] != 0 && ((*out_indices)[2] > num_normals_ || + (*out_indices)[2] < -num_normals_)) { + return false; + } + return true; + }; + char ch; if (!buffer()->Peek(&ch)) { - return true; // It may be OK if we cannot read any more characters. + return indices_in_bounds(); // It may be OK if we cannot read any more characters. } if (ch != '/') { - return true; + return indices_in_bounds(); } buffer()->Advance(1); // Check if we should skip texture index or not. @@ -618,7 +634,7 @@ bool ObjDecoder::ParseVertexIndices(std::array *out_indices) { } } if (!buffer()->Peek(&ch)) { - return true; + return indices_in_bounds(); } if (ch == '/') { buffer()->Advance(1); @@ -628,7 +644,8 @@ bool ObjDecoder::ParseVertexIndices(std::array *out_indices) { return false; // Normal index must be present and valid. } } - return true; + + return indices_in_bounds(); } void ObjDecoder::MapPointToVertexIndices(