Commit 9383e1ca authored by Kyle Nekritz's avatar Kyle Nekritz Committed by Facebook Github Bot 6

Add recursion limit to folly::parseJson.

Summary: Without this, malicious inputs can crash anything using folly::parseJson.

Reviewed By: yfeldblum

Differential Revision: D3219036

fb-gh-sync-id: 3604a060170c0201473c420035b21b018383789c
fbshipit-source-id: 3604a060170c0201473c420035b21b018383789c
parent a503da60
...@@ -379,7 +379,18 @@ struct Input { ...@@ -379,7 +379,18 @@ struct Input {
return opts_; return opts_;
} }
private: void incrementRecursionLevel() {
if (currentRecursionLevel_ > opts_.recursion_limit) {
error("recursion limit exceeded");
}
currentRecursionLevel_++;
}
void decrementRecursionLevel() {
currentRecursionLevel_--;
}
private:
void storeCurrent() { void storeCurrent() {
current_ = range_.empty() ? EOF : range_.front(); current_ = range_.empty() ? EOF : range_.front();
} }
...@@ -389,6 +400,21 @@ private: ...@@ -389,6 +400,21 @@ private:
json::serialization_opts const& opts_; json::serialization_opts const& opts_;
unsigned lineNum_; unsigned lineNum_;
int current_; int current_;
unsigned int currentRecursionLevel_{0};
};
class RecursionGuard {
public:
explicit RecursionGuard(Input& in) : in_(in) {
in_.incrementRecursionLevel();
}
~RecursionGuard() {
in_.decrementRecursionLevel();
}
private:
Input& in_;
}; };
dynamic parseValue(Input& in); dynamic parseValue(Input& in);
...@@ -627,6 +653,8 @@ std::string parseString(Input& in) { ...@@ -627,6 +653,8 @@ std::string parseString(Input& in) {
} }
dynamic parseValue(Input& in) { dynamic parseValue(Input& in) {
RecursionGuard guard(in);
in.skipWhitespace(); in.skipWhitespace();
return *in == '[' ? parseArray(in) : return *in == '[' ? parseArray(in) :
*in == '{' ? parseObject(in) : *in == '{' ? parseObject(in) :
......
...@@ -54,20 +54,20 @@ namespace json { ...@@ -54,20 +54,20 @@ namespace json {
struct serialization_opts { struct serialization_opts {
explicit serialization_opts() explicit serialization_opts()
: allow_non_string_keys(false) : allow_non_string_keys(false),
, javascript_safe(false) javascript_safe(false),
, pretty_formatting(false) pretty_formatting(false),
, encode_non_ascii(false) encode_non_ascii(false),
, validate_utf8(false) validate_utf8(false),
, allow_trailing_comma(false) allow_trailing_comma(false),
, sort_keys(false) sort_keys(false),
, skip_invalid_utf8(false) skip_invalid_utf8(false),
, allow_nan_inf(false) allow_nan_inf(false),
, double_mode(double_conversion::DoubleToStringConverter::SHORTEST) double_mode(double_conversion::DoubleToStringConverter::SHORTEST),
, double_num_digits(0) // ignored when mode is SHORTEST double_num_digits(0), // ignored when mode is SHORTEST
, double_fallback(false) double_fallback(false),
, parse_numbers_as_strings(false) parse_numbers_as_strings(false),
{} recursion_limit(100) {}
// If true, keys in an object can be non-strings. (In strict // If true, keys in an object can be non-strings. (In strict
// JSON, object keys must be strings.) This is used by dynamic's // JSON, object keys must be strings.) This is used by dynamic's
...@@ -115,6 +115,9 @@ namespace json { ...@@ -115,6 +115,9 @@ namespace json {
// Do not parse numbers. Instead, store them as strings and leave the // Do not parse numbers. Instead, store them as strings and leave the
// conversion up to the user. // conversion up to the user.
bool parse_numbers_as_strings; bool parse_numbers_as_strings;
// Recursion limit when parsing.
unsigned int recursion_limit;
}; };
/* /*
......
...@@ -517,3 +517,19 @@ TEST(Json, PrintTo) { ...@@ -517,3 +517,19 @@ TEST(Json, PrintTo) {
PrintTo(value, &oss); PrintTo(value, &oss);
EXPECT_EQ(expected, oss.str()); EXPECT_EQ(expected, oss.str());
} }
TEST(Json, RecursionLimit) {
std::string in;
for (int i = 0; i < 1000; i++) {
in.append("{\"x\":");
}
in.append("\"hi\"");
for (int i = 0; i < 1000; i++) {
in.append("}");
}
EXPECT_ANY_THROW(parseJson(in));
folly::json::serialization_opts opts_high_recursion_limit;
opts_high_recursion_limit.recursion_limit = 10000;
parseJson(in, opts_high_recursion_limit);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment