mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-01 19:58:15 +00:00
Protected parser against infinite recursion.
Will error-out after e.g. 64 levels of nested JSON tables. Change-Id: I3ab66cdd509378bfab87b85f85c07ab42aded788 Tested: on Linux.
This commit is contained in:
@@ -525,7 +525,8 @@ class Parser : public ParserState {
|
||||
opts(options),
|
||||
uses_flexbuffers_(false),
|
||||
source_(nullptr),
|
||||
anonymous_counter(0) {
|
||||
anonymous_counter(0),
|
||||
recurse_protection_counter(0) {
|
||||
// Start out with the empty namespace being current.
|
||||
empty_namespace_ = new Namespace();
|
||||
namespaces_.push_back(empty_namespace_);
|
||||
@@ -704,6 +705,15 @@ class Parser : public ParserState {
|
||||
bool SupportsVectorOfUnions() const;
|
||||
Namespace *UniqueNamespace(Namespace *ns);
|
||||
|
||||
enum { kMaxParsingDepth = 64 };
|
||||
FLATBUFFERS_CHECKED_ERROR RecurseError();
|
||||
template<typename F> CheckedError Recurse(F f) {
|
||||
if (++recurse_protection_counter >= kMaxParsingDepth) return RecurseError();
|
||||
auto ce = f();
|
||||
recurse_protection_counter--;
|
||||
return ce;
|
||||
}
|
||||
|
||||
public:
|
||||
SymbolTable<Type> types_;
|
||||
SymbolTable<StructDef> structs_;
|
||||
@@ -736,6 +746,7 @@ class Parser : public ParserState {
|
||||
std::vector<std::pair<Value, FieldDef *>> field_stack_;
|
||||
|
||||
int anonymous_counter;
|
||||
int recurse_protection_counter;
|
||||
};
|
||||
|
||||
// Utility functions for multiple generators:
|
||||
|
||||
@@ -113,6 +113,11 @@ CheckedError Parser::Error(const std::string &msg) {
|
||||
|
||||
inline CheckedError NoError() { return CheckedError(false); }
|
||||
|
||||
CheckedError Parser::RecurseError() {
|
||||
return Error("maximum parsing recursion of " + NumToString(kMaxParsingDepth) +
|
||||
" reached");
|
||||
}
|
||||
|
||||
inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op,
|
||||
int64_t limit) {
|
||||
const std::string cause = NumToString(val) + op + NumToString(limit);
|
||||
@@ -583,7 +588,7 @@ CheckedError Parser::ParseType(Type &type) {
|
||||
} else if (token_ == '[') {
|
||||
NEXT();
|
||||
Type subtype;
|
||||
ECHECK(ParseType(subtype));
|
||||
ECHECK(Recurse([&]() { return ParseType(subtype); }));
|
||||
if (subtype.base_type == BASE_TYPE_VECTOR) {
|
||||
// We could support this, but it will complicate things, and it's
|
||||
// easier to work around with a struct around the inner vector.
|
||||
@@ -975,7 +980,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
|
||||
fieldn_outer, &struct_def,
|
||||
[](const std::string &name, size_t &fieldn,
|
||||
const StructDef *struct_def_inner, void *state) -> CheckedError {
|
||||
Parser *parser = static_cast<Parser *>(state);
|
||||
auto *parser = static_cast<Parser *>(state);
|
||||
if (name == "$schema") {
|
||||
ECHECK(parser->Expect(kTokenStringConstant));
|
||||
return NoError();
|
||||
@@ -1006,8 +1011,10 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
|
||||
ECHECK(parser->ParseNestedFlatbuffer(val, field, fieldn,
|
||||
struct_def_inner));
|
||||
} else {
|
||||
ECHECK(
|
||||
parser->ParseAnyValue(val, field, fieldn, struct_def_inner));
|
||||
ECHECK(parser->Recurse([&]() {
|
||||
return parser->ParseAnyValue(val, field, fieldn,
|
||||
struct_def_inner);
|
||||
}));
|
||||
}
|
||||
// Hardcoded insertion-sort with error-check.
|
||||
// If fields are specified in order, then this loop exits
|
||||
@@ -1152,7 +1159,9 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
|
||||
auto *parser = parser_and_type->first;
|
||||
Value val;
|
||||
val.type = parser_and_type->second;
|
||||
ECHECK(parser->ParseAnyValue(val, nullptr, 0, nullptr));
|
||||
ECHECK(parser->Recurse([&]() {
|
||||
return parser->ParseAnyValue(val, nullptr, 0, nullptr);
|
||||
}));
|
||||
parser->field_stack_.push_back(std::make_pair(val, nullptr));
|
||||
return NoError();
|
||||
},
|
||||
@@ -2130,7 +2139,9 @@ CheckedError Parser::SkipAnyJsonValue() {
|
||||
[](const std::string &, size_t &fieldn, const StructDef *,
|
||||
void *state) -> CheckedError {
|
||||
auto *parser = static_cast<Parser *>(state);
|
||||
ECHECK(parser->SkipAnyJsonValue());
|
||||
ECHECK(parser->Recurse([&]() {
|
||||
return parser->SkipAnyJsonValue();
|
||||
}));
|
||||
fieldn++;
|
||||
return NoError();
|
||||
},
|
||||
@@ -2141,7 +2152,10 @@ CheckedError Parser::SkipAnyJsonValue() {
|
||||
return ParseVectorDelimiters(
|
||||
count,
|
||||
[](size_t &, void *state) -> CheckedError {
|
||||
return static_cast<Parser *>(state)->SkipAnyJsonValue();
|
||||
auto *parser = static_cast<Parser *>(state);
|
||||
return parser->Recurse([&]() {
|
||||
return parser->SkipAnyJsonValue();
|
||||
});
|
||||
},
|
||||
this);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user