From 1bf1c1454ebc454635859a9b31e2aab88d3632ea Mon Sep 17 00:00:00 2001 From: smoke-wolf Date: Wed, 2 Sep 2026 03:45:57 -0600 Subject: [PATCH] Fix OOB reads in sequential mesh decoder and rANS entropy decoder mesh_sequential_decoder.cc: face vertex indices decoded from the bitstream were not validated against num_points, allowing crafted meshes to reference nonexistent vertices. Subsequent attribute access via these indices causes heap-buffer-overflow. Add bounds checking for all face index decode paths. ans.h: RAnsDecoder::read_init() was missing a bounds check for the x==3 case (offset < 4), unlike the x==1 and x==2 cases which had equivalent guards. A crafted entropy stream with offset=1 and x=3 reads 4 bytes before the buffer start. Add the missing check. Both bugs confirmed under AddressSanitizer. --- src/draco/compression/entropy/ans.h | 3 +++ .../compression/mesh/mesh_sequential_decoder.cc | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/draco/compression/entropy/ans.h b/src/draco/compression/entropy/ans.h index 313546fee..17318c371 100644 --- a/src/draco/compression/entropy/ans.h +++ b/src/draco/compression/entropy/ans.h @@ -441,6 +441,9 @@ class RAnsDecoder { ans_.buf_offset = offset - 3; ans_.state = mem_get_le24(buf + offset - 3) & 0x3FFFFF; } else if (x == 3) { + if (offset < 4) { + return 1; + } ans_.buf_offset = offset - 4; ans_.state = mem_get_le32(buf + offset - 4) & 0x3FFFFFFF; } else { diff --git a/src/draco/compression/mesh/mesh_sequential_decoder.cc b/src/draco/compression/mesh/mesh_sequential_decoder.cc index 124df3345..bf6f9a0f2 100644 --- a/src/draco/compression/mesh/mesh_sequential_decoder.cc +++ b/src/draco/compression/mesh/mesh_sequential_decoder.cc @@ -78,6 +78,9 @@ bool MeshSequentialDecoder::DecodeConnectivity() { if (!buffer()->Decode(&val)) { return false; } + if (val >= num_points) { + return false; + } face[j] = val; } mesh()->AddFace(face); @@ -91,6 +94,9 @@ bool MeshSequentialDecoder::DecodeConnectivity() { if (!buffer()->Decode(&val)) { return false; } + if (val >= num_points) { + return false; + } face[j] = val; } mesh()->AddFace(face); @@ -105,6 +111,9 @@ bool MeshSequentialDecoder::DecodeConnectivity() { if (!DecodeVarint(&val, buffer())) { return false; } + if (val >= num_points) { + return false; + } face[j] = val; } mesh()->AddFace(face); @@ -118,6 +127,9 @@ bool MeshSequentialDecoder::DecodeConnectivity() { if (!buffer()->Decode(&val)) { return false; } + if (val >= num_points) { + return false; + } face[j] = val; } mesh()->AddFace(face);