mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Limit STVar recursion during deserialization (RIPD-1603):
Constructing deeply nested objects could allow an attacker to cause a server to overflow its available stack. We now enforce a 10-deep nesting limit, and signal an error if we encounter objects that are nested deeper. Acknowledgements: Ripple thanks Guido Vranken for responsibly disclosing this issues. Bug Bounties and Responsible Disclosures: We welcome reviews of the rippled codebase and urge reviewers to responsibly disclose any issues that they may find. For more on Ripple's Bug Bounty program, please visit https://ripple.com/bug-bounty
This commit is contained in:
committed by
Nikolaos D. Bougalis
parent
9af994ceb4
commit
881cd4cfad
@@ -721,92 +721,102 @@ static boost::optional <STObject> parseObject (
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
STObject data (inName);
|
||||
|
||||
for (auto const& fieldName : json.getMemberNames ())
|
||||
try
|
||||
{
|
||||
Json::Value const& value = json [fieldName];
|
||||
|
||||
auto const& field = SField::getField (fieldName);
|
||||
STObject data (inName);
|
||||
|
||||
if (field == sfInvalid)
|
||||
for (auto const& fieldName : json.getMemberNames ())
|
||||
{
|
||||
error = unknown_field (json_name, fieldName);
|
||||
Json::Value const& value = json [fieldName];
|
||||
|
||||
auto const& field = SField::getField (fieldName);
|
||||
|
||||
if (field == sfInvalid)
|
||||
{
|
||||
error = unknown_field (json_name, fieldName);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
switch (field.fieldType)
|
||||
{
|
||||
|
||||
// Object-style containers (which recurse).
|
||||
case STI_OBJECT:
|
||||
case STI_TRANSACTION:
|
||||
case STI_LEDGERENTRY:
|
||||
case STI_VALIDATION:
|
||||
if (! value.isObject ())
|
||||
{
|
||||
error = not_an_object (json_name, fieldName);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto ret = parseObject (json_name + "." + fieldName,
|
||||
value, field, depth + 1, error);
|
||||
if (! ret)
|
||||
return boost::none;
|
||||
data.emplace_back (std::move (*ret));
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Array-style containers (which recurse).
|
||||
case STI_ARRAY:
|
||||
try
|
||||
{
|
||||
auto array = parseArray (json_name + "." + fieldName,
|
||||
value, field, depth + 1, error);
|
||||
if (array == boost::none)
|
||||
return boost::none;
|
||||
data.emplace_back (std::move (*array));
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Everything else (types that don't recurse).
|
||||
default:
|
||||
{
|
||||
auto leaf =
|
||||
parseLeaf (json_name, fieldName, &inName, value, error);
|
||||
|
||||
if (!leaf)
|
||||
return boost::none;
|
||||
|
||||
data.emplace_back (std::move (*leaf));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Some inner object types have templates. Attempt to apply that.
|
||||
if (data.setTypeFromSField (inName) == STObject::typeSetFail)
|
||||
{
|
||||
error = template_mismatch (inName);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
switch (field.fieldType)
|
||||
{
|
||||
return std::move (data);
|
||||
|
||||
// Object-style containers (which recurse).
|
||||
case STI_OBJECT:
|
||||
case STI_TRANSACTION:
|
||||
case STI_LEDGERENTRY:
|
||||
case STI_VALIDATION:
|
||||
if (! value.isObjectOrNull ())
|
||||
{
|
||||
error = not_an_object (json_name, fieldName);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto ret = parseObject (json_name + "." + fieldName,
|
||||
value, field, depth + 1, error);
|
||||
if (! ret)
|
||||
return boost::none;
|
||||
data.emplace_back (std::move (*ret));
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Array-style containers (which recurse).
|
||||
case STI_ARRAY:
|
||||
try
|
||||
{
|
||||
auto array = parseArray (json_name + "." + fieldName,
|
||||
value, field, depth + 1, error);
|
||||
if (array == boost::none)
|
||||
return boost::none;
|
||||
data.emplace_back (std::move (*array));
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Everything else (types that don't recurse).
|
||||
default:
|
||||
{
|
||||
auto leaf =
|
||||
parseLeaf (json_name, fieldName, &inName, value, error);
|
||||
|
||||
if (!leaf)
|
||||
return boost::none;
|
||||
|
||||
data.emplace_back (std::move (*leaf));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Some inner object types have templates. Attempt to apply that.
|
||||
if (data.setTypeFromSField (inName) == STObject::typeSetFail)
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = template_mismatch (inName);
|
||||
error = invalid_data (json_name);
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
return std::move (data);
|
||||
}
|
||||
|
||||
static boost::optional <detail::STVar> parseArray (
|
||||
|
||||
Reference in New Issue
Block a user