Limit nesting of json commands

This commit is contained in:
Howard Hinnant
2018-01-09 16:26:22 -05:00
committed by Scott Schurr
parent 718d217158
commit 0ec66b3dbc
3 changed files with 66 additions and 12 deletions

View File

@@ -29,6 +29,8 @@ namespace Json
// Implementation of class Reader
// ////////////////////////////////
constexpr unsigned Reader::nest_limit;
static
std::string
codePointToUTF8 (unsigned int cp)
@@ -118,8 +120,7 @@ Reader::parse ( const char* beginDoc, const char* endDoc,
nodes_.pop ();
nodes_.push ( &root );
bool successful = readValue ();
bool successful = readValue(0);
Token token;
skipCommentTokens ( token );
@@ -138,20 +139,22 @@ Reader::parse ( const char* beginDoc, const char* endDoc,
}
bool
Reader::readValue ()
Reader::readValue(unsigned depth)
{
Token token;
skipCommentTokens ( token );
if (depth > nest_limit)
return addError("Syntax error: maximum nesting depth exceeded", token);
bool successful = true;
switch ( token.type_ )
{
case tokenObjectBegin:
successful = readObject ( token );
successful = readObject(token, depth);
break;
case tokenArrayBegin:
successful = readArray ( token );
successful = readArray(token, depth);
break;
case tokenInteger:
@@ -427,7 +430,7 @@ Reader::readString ()
bool
Reader::readObject ( Token& tokenStart )
Reader::readObject(Token& tokenStart, unsigned depth)
{
Token tokenName;
std::string name;
@@ -469,7 +472,7 @@ Reader::readObject ( Token& tokenStart )
Value& value = currentValue ()[ name ];
nodes_.push ( &value );
bool ok = readValue ();
bool ok = readValue(depth+1);
nodes_.pop ();
if ( !ok ) // error already set
@@ -504,7 +507,7 @@ Reader::readObject ( Token& tokenStart )
bool
Reader::readArray ( Token& tokenStart )
Reader::readArray(Token& tokenStart, unsigned depth)
{
currentValue () = Value ( arrayValue );
skipSpaces ();
@@ -522,7 +525,7 @@ Reader::readArray ( Token& tokenStart )
{
Value& value = currentValue ()[ index++ ];
nodes_.push ( &value );
bool ok = readValue ();
bool ok = readValue(depth+1);
nodes_.pop ();
if ( !ok ) // error already set

View File

@@ -81,6 +81,8 @@ public:
*/
std::string getFormatedErrorMessages () const;
static constexpr unsigned nest_limit {1000};
private:
enum TokenType
{
@@ -129,9 +131,9 @@ private:
bool readCppStyleComment ();
bool readString ();
Reader::TokenType readNumber ();
bool readValue ();
bool readObject ( Token& token );
bool readArray ( Token& token );
bool readValue(unsigned depth);
bool readObject(Token& token, unsigned depth);
bool readArray (Token& token, unsigned depth);
bool decodeNumber ( Token& token );
bool decodeString ( Token& token );
bool decodeString ( Token& token, std::string& decoded );

View File

@@ -24,6 +24,8 @@
#include <ripple/beast/unit_test.h>
#include <ripple/beast/type_name.h>
#include <algorithm>
namespace ripple {
struct json_value_test : beast::unit_test::suite
@@ -249,6 +251,52 @@ struct json_value_test : beast::unit_test::suite
}
}
void test_nest_limits ()
{
Json::Reader r;
{
auto nest = [](std::uint32_t depth)->std::string {
std::string s = "{";
for (std::uint32_t i{1}; i <= depth; ++i)
s += "\"obj\":{";
for (std::uint32_t i{1}; i <= depth; ++i)
s += "}";
s += "}";
return s;
};
{
// Within object nest limit
auto json{nest(std::min(10u, Json::Reader::nest_limit))};
Json::Value j;
BEAST_EXPECT(r.parse(json, j));
}
{
// Exceed object nest limit
auto json{nest(Json::Reader::nest_limit + 1)};
Json::Value j;
BEAST_EXPECT(!r.parse(json, j));
}
}
auto nest = [](std::uint32_t depth)->std::string {
std::string s = "{";
for (std::uint32_t i{1}; i <= depth; ++i)
s += "\"array\":[{";
for (std::uint32_t i{1}; i <= depth; ++i)
s += "]}";
s += "}";
return s;
};
{
// Exceed array nest limit
auto json{nest(Json::Reader::nest_limit + 1)};
Json::Value j;
BEAST_EXPECT(!r.parse(json, j));
}
}
void run ()
{
test_bool ();
@@ -258,6 +306,7 @@ struct json_value_test : beast::unit_test::suite
test_move ();
test_comparisons ();
test_compact ();
test_nest_limits ();
}
};