mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Limit nesting of json commands
This commit is contained in:
committed by
Scott Schurr
parent
718d217158
commit
0ec66b3dbc
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user