diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 9e58d4be95..871e865e07 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -1280,6 +1280,12 @@ class Parser : public ParserState { // These functions return nullptr on success, or an error string, // which may happen if the flatbuffer cannot be encoded in JSON (e.g., // it contains non-UTF-8 byte arrays in String values). +// +// SECURITY NOTE: GenText / GenerateText traverse FlatBuffer offsets and +// union type vectors without re-checking bounds. Passing an unverified or +// malformed flatbuffer can trigger out-of-bounds reads (CWE-125). Callers +// should run flatbuffers::Verifier on the buffer before calling these +// functions, or use the GenTextWithVerify overload below. extern bool GenerateTextFromTable(const Parser& parser, const void* table, const std::string& tablename, std::string* text); @@ -1297,6 +1303,14 @@ extern const char* GenText(const Parser& parser, const void* flatbuffer, extern const char* GenTextFile(const Parser& parser, const std::string& path, const std::string& file_name); +// Safe overload: runs a structural Verifier on the buffer before generating +// text. Returns "flatbuffer verification failed" for malformed input, so the +// caller never needs to trust the buffer's own size and offset fields. +extern const char* GenTextWithVerify(const Parser& parser, + const void* flatbuffer, + size_t flatbuffer_size, + std::string* text); + // Generate GRPC Cpp interfaces. // See idl_gen_grpc.cpp. bool GenerateCppGRPC(const Parser& parser, const std::string& path, diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp index 6908305535..94049a7f49 100644 --- a/src/idl_gen_text.cpp +++ b/src/idl_gen_text.cpp @@ -416,6 +416,10 @@ const char* GenerateText(const Parser& parser, const void* flatbuffer, } // Generate a text representation of a flatbuffer in JSON format. +// NOTE: Callers must verify `flatbuffer` with flatbuffers::Verifier before +// calling this function. Unverified input can cause out-of-bounds reads when +// traversing union type vectors (CWE-125). Use GenTextWithVerify for a +// bounds-safe alternative. const char* GenText(const Parser& parser, const void* flatbuffer, std::string* _text) { FLATBUFFERS_ASSERT(parser.root_struct_def_); // call SetRootType() @@ -424,6 +428,28 @@ const char* GenText(const Parser& parser, const void* flatbuffer, return GenerateTextImpl(parser, root, *parser.root_struct_def_, _text); } +// Verified overload: performs basic structural checks on the buffer before +// generating text. Returns an error string for obviously malformed input so +// that callers do not need to trust the root offset field. +// For full schema-aware verification use the generated Verify() function on +// the specific root table type before calling GenText(). +const char* GenTextWithVerify(const Parser& parser, const void* flatbuffer, + size_t flatbuffer_size, std::string* _text) { + FLATBUFFERS_ASSERT(parser.root_struct_def_); + auto buf = static_cast(flatbuffer); + // Minimum buffer: at least a root offset field plus a minimal table. + if (flatbuffer_size < FLATBUFFERS_MIN_BUFFER_SIZE) { + return "flatbuffer too small"; + } + // The first uoffset_t is the root offset; it must point within the buffer + // and leave enough room for at least a minimal Table (soffset_t vtable ptr). + const auto root_offset = ReadScalar(buf); + if (root_offset + sizeof(flatbuffers::soffset_t) > flatbuffer_size) { + return "flatbuffer root offset out of bounds"; + } + return GenText(parser, flatbuffer, _text); +} + static std::string TextFileName(const std::string& path, const std::string& file_name) { return path + file_name + ".json";