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
|
// Implementation of class Reader
|
||||||
// ////////////////////////////////
|
// ////////////////////////////////
|
||||||
|
|
||||||
|
constexpr unsigned Reader::nest_limit;
|
||||||
|
|
||||||
static
|
static
|
||||||
std::string
|
std::string
|
||||||
codePointToUTF8 (unsigned int cp)
|
codePointToUTF8 (unsigned int cp)
|
||||||
@@ -118,8 +120,7 @@ Reader::parse ( const char* beginDoc, const char* endDoc,
|
|||||||
nodes_.pop ();
|
nodes_.pop ();
|
||||||
|
|
||||||
nodes_.push ( &root );
|
nodes_.push ( &root );
|
||||||
|
bool successful = readValue(0);
|
||||||
bool successful = readValue ();
|
|
||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens ( token );
|
skipCommentTokens ( token );
|
||||||
|
|
||||||
@@ -138,20 +139,22 @@ Reader::parse ( const char* beginDoc, const char* endDoc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::readValue ()
|
Reader::readValue(unsigned depth)
|
||||||
{
|
{
|
||||||
Token token;
|
Token token;
|
||||||
skipCommentTokens ( token );
|
skipCommentTokens ( token );
|
||||||
|
if (depth > nest_limit)
|
||||||
|
return addError("Syntax error: maximum nesting depth exceeded", token);
|
||||||
bool successful = true;
|
bool successful = true;
|
||||||
|
|
||||||
switch ( token.type_ )
|
switch ( token.type_ )
|
||||||
{
|
{
|
||||||
case tokenObjectBegin:
|
case tokenObjectBegin:
|
||||||
successful = readObject ( token );
|
successful = readObject(token, depth);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tokenArrayBegin:
|
case tokenArrayBegin:
|
||||||
successful = readArray ( token );
|
successful = readArray(token, depth);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tokenInteger:
|
case tokenInteger:
|
||||||
@@ -427,7 +430,7 @@ Reader::readString ()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::readObject ( Token& tokenStart )
|
Reader::readObject(Token& tokenStart, unsigned depth)
|
||||||
{
|
{
|
||||||
Token tokenName;
|
Token tokenName;
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -469,7 +472,7 @@ Reader::readObject ( Token& tokenStart )
|
|||||||
|
|
||||||
Value& value = currentValue ()[ name ];
|
Value& value = currentValue ()[ name ];
|
||||||
nodes_.push ( &value );
|
nodes_.push ( &value );
|
||||||
bool ok = readValue ();
|
bool ok = readValue(depth+1);
|
||||||
nodes_.pop ();
|
nodes_.pop ();
|
||||||
|
|
||||||
if ( !ok ) // error already set
|
if ( !ok ) // error already set
|
||||||
@@ -504,7 +507,7 @@ Reader::readObject ( Token& tokenStart )
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::readArray ( Token& tokenStart )
|
Reader::readArray(Token& tokenStart, unsigned depth)
|
||||||
{
|
{
|
||||||
currentValue () = Value ( arrayValue );
|
currentValue () = Value ( arrayValue );
|
||||||
skipSpaces ();
|
skipSpaces ();
|
||||||
@@ -522,7 +525,7 @@ Reader::readArray ( Token& tokenStart )
|
|||||||
{
|
{
|
||||||
Value& value = currentValue ()[ index++ ];
|
Value& value = currentValue ()[ index++ ];
|
||||||
nodes_.push ( &value );
|
nodes_.push ( &value );
|
||||||
bool ok = readValue ();
|
bool ok = readValue(depth+1);
|
||||||
nodes_.pop ();
|
nodes_.pop ();
|
||||||
|
|
||||||
if ( !ok ) // error already set
|
if ( !ok ) // error already set
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::string getFormatedErrorMessages () const;
|
std::string getFormatedErrorMessages () const;
|
||||||
|
|
||||||
|
static constexpr unsigned nest_limit {1000};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum TokenType
|
enum TokenType
|
||||||
{
|
{
|
||||||
@@ -129,9 +131,9 @@ private:
|
|||||||
bool readCppStyleComment ();
|
bool readCppStyleComment ();
|
||||||
bool readString ();
|
bool readString ();
|
||||||
Reader::TokenType readNumber ();
|
Reader::TokenType readNumber ();
|
||||||
bool readValue ();
|
bool readValue(unsigned depth);
|
||||||
bool readObject ( Token& token );
|
bool readObject(Token& token, unsigned depth);
|
||||||
bool readArray ( Token& token );
|
bool readArray (Token& token, unsigned depth);
|
||||||
bool decodeNumber ( Token& token );
|
bool decodeNumber ( Token& token );
|
||||||
bool decodeString ( Token& token );
|
bool decodeString ( Token& token );
|
||||||
bool decodeString ( Token& token, std::string& decoded );
|
bool decodeString ( Token& token, std::string& decoded );
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#include <ripple/beast/unit_test.h>
|
#include <ripple/beast/unit_test.h>
|
||||||
#include <ripple/beast/type_name.h>
|
#include <ripple/beast/type_name.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
struct json_value_test : beast::unit_test::suite
|
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 ()
|
void run ()
|
||||||
{
|
{
|
||||||
test_bool ();
|
test_bool ();
|
||||||
@@ -258,6 +306,7 @@ struct json_value_test : beast::unit_test::suite
|
|||||||
test_move ();
|
test_move ();
|
||||||
test_comparisons ();
|
test_comparisons ();
|
||||||
test_compact ();
|
test_compact ();
|
||||||
|
test_nest_limits ();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user