From 94c44461373e046dd4614b0580942aef978767b3 Mon Sep 17 00:00:00 2001 From: Ashutosh0x Date: Mon, 1 Jun 2026 19:34:48 +0530 Subject: [PATCH] Fix heap buffer overflow in StructDef::Deserialize Add bounds checking and null validation when deserializing .bfbs files: - Null-check object->fields() before dereferencing - Detect duplicate field IDs to prevent silent overwrites - Null-check individual field pointers in the loop - Null-check enum values() and included_filenames() pointers These checks prevent heap buffer overflow via maliciously crafted .bfbs files where field IDs exceed the fields array size. Fixes #8932 --- src/idl_parser.cpp | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index b1bdffa014..5258a58d30 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -4130,15 +4130,32 @@ bool StructDef::Deserialize(Parser& parser, const reflection::Object* object) { name = parser.UnqualifiedName(object->name()->str()); predecl = false; sortbysize = attributes.Lookup("original_order") == nullptr && !fixed; - const auto& of = *(object->fields()); - auto indexes = std::vector(of.size()); - for (uoffset_t i = 0; i < of.size(); i++) { - uint16_t field_id = of.Get(i)->id(); - if (field_id >= of.size()) { + auto fields_ptr = object->fields(); + if (!fields_ptr || fields_ptr->size() == 0) { + parser.error_ = "Object has no fields"; + return false; + } + const auto& of = *fields_ptr; + const auto field_count = of.size(); + auto indexes = std::vector(field_count); + std::vector id_used(field_count, false); + for (uoffset_t i = 0; i < field_count; i++) { + auto field_ptr = of.Get(i); + if (!field_ptr) { + parser.error_ = "Null field at index " + std::to_string(i); + return false; + } + uint16_t field_id = field_ptr->id(); + if (field_id >= field_count) { parser.error_ = "Field ID " + std::to_string(field_id) + - " exceeds field count " + std::to_string(of.size()); + " exceeds field count " + std::to_string(field_count); return false; } + if (id_used[field_id]) { + parser.error_ = "Duplicate field ID " + std::to_string(field_id); + return false; + } + id_used[field_id] = true; indexes[field_id] = i; } size_t tmp_struct_size = 0; @@ -4313,9 +4330,13 @@ Offset EnumDef::Serialize(FlatBufferBuilder* builder, bool EnumDef::Deserialize(Parser& parser, const reflection::Enum* _enum) { name = parser.UnqualifiedName(_enum->name()->str()); - for (uoffset_t i = 0; i < _enum->values()->size(); ++i) { + auto values_ptr = _enum->values(); + if (!values_ptr) { + return false; + } + for (uoffset_t i = 0; i < values_ptr->size(); ++i) { auto val = new EnumVal(); - if (!val->Deserialize(parser, _enum->values()->Get(i)) || + if (!val->Deserialize(parser, values_ptr->Get(i)) || vals.Add(val->name, val)) { delete val; return false; @@ -4520,6 +4541,7 @@ bool Parser::Deserialize(const reflection::Schema* schema) { if (schema->fbs_files()) for (auto s = schema->fbs_files()->begin(); s != schema->fbs_files()->end(); ++s) { + if (!s->included_filenames()) continue; for (auto f = s->included_filenames()->begin(); f != s->included_filenames()->end(); ++f) { IncludedFile included_file;