Add stack overflow protection for text format

It already exists for wire and json formats
pull/5677/head
Vitaly Buka 6 years ago committed by Adam Cozzette
parent 8bbabb87a2
commit 6dcd81093c
  1. 8
      src/google/protobuf/text_format.cc
  2. 14
      src/google/protobuf/text_format_unittest.cc
  3. 2
      third_party/googletest

@ -262,6 +262,7 @@ class TextFormat::Parser::ParserImpl {
allow_unknown_enum_(allow_unknown_enum), allow_unknown_enum_(allow_unknown_enum),
allow_field_number_(allow_field_number), allow_field_number_(allow_field_number),
allow_partial_(allow_partial), allow_partial_(allow_partial),
recursion_budget_(io::CodedInputStream::GetDefaultRecursionLimit()),
had_errors_(false) { had_errors_(false) {
// For backwards-compatibility with proto1, we need to allow the 'f' suffix // For backwards-compatibility with proto1, we need to allow the 'f' suffix
// for floats. // for floats.
@ -631,6 +632,10 @@ label_skip_parsing:
bool ConsumeFieldMessage(Message* message, bool ConsumeFieldMessage(Message* message,
const Reflection* reflection, const Reflection* reflection,
const FieldDescriptor* field) { const FieldDescriptor* field) {
if (--recursion_budget_ < 0) {
ReportError("Message is too deep");
return false;
}
// If the parse information tree is not NULL, create a nested one // If the parse information tree is not NULL, create a nested one
// for the nested message. // for the nested message.
@ -648,6 +653,8 @@ label_skip_parsing:
delimiter)); delimiter));
} }
++recursion_budget_;
// Reset the parse information tree. // Reset the parse information tree.
parse_info_tree_ = parent; parse_info_tree_ = parent;
return true; return true;
@ -1179,6 +1186,7 @@ label_skip_parsing:
const bool allow_unknown_enum_; const bool allow_unknown_enum_;
const bool allow_field_number_; const bool allow_field_number_;
const bool allow_partial_; const bool allow_partial_;
int recursion_budget_;
bool had_errors_; bool had_errors_;
}; };

@ -1810,6 +1810,20 @@ TEST_F(TextFormatParserTest, ParseDeprecatedField) {
"\"deprecated_int32\"", 1, 21, &message, true); "\"deprecated_int32\"", 1, 21, &message, true);
} }
TEST_F(TextFormatParserTest, DeepRecursion) {
const char* format = "child: { $0 }";
std::string input;
for (int i = 0; i < 100; ++i)
input = strings::Substitute(format, input);
unittest::NestedTestAllTypes message;
ExpectSuccessAndTree(input, &message, nullptr);
input = strings::Substitute(format, input);
ExpectMessage(input,
"Message is too deep", 1, 908, &message, false);
}
class TextFormatMessageSetTest : public testing::Test { class TextFormatMessageSetTest : public testing::Test {
protected: protected:
static const char proto_debug_string_[]; static const char proto_debug_string_[];

@ -1 +1 @@
Subproject commit 5ec7f0c4a113e2f18ac2c6cc7df51ad6afc24081 Subproject commit c3bb0ee2a63279a803aaad956b9b26d74bf9e6e2
Loading…
Cancel
Save