Compare commits

..

1 Commits

Author SHA1 Message Date
Olek
6ff495fd9b Fix: Perform array size check (#6030)
The `ledger_entry` and `deposit_preauth` requests require an array of credentials. However, the array size is not checked before is gets processing. This fix adds checks and return errors in case array size is too big.
2025-11-19 16:58:18 +00:00
5 changed files with 27 additions and 77 deletions

View File

@@ -191,7 +191,6 @@ ApplyView::dirRemove(
uint256 const& key,
bool keepRoot)
{
keepRoot = false;
auto node = peek(keylet::page(directory, page));
if (!node)

View File

@@ -1103,7 +1103,7 @@ class LedgerEntry_test : public beast::unit_test::suite
checkErrorValue(
jrr[jss::result],
"malformedAuthorizedCredentials",
"Invalid field 'authorized_credentials', not array.");
"Invalid field 'authorized_credentials', array empty.");
}
{
@@ -1144,7 +1144,7 @@ class LedgerEntry_test : public beast::unit_test::suite
checkErrorValue(
jrr[jss::result],
"malformedAuthorizedCredentials",
"Invalid field 'authorized_credentials', not array.");
"Invalid field 'authorized_credentials', array too long.");
}
}

View File

@@ -3096,42 +3096,4 @@ ValidVault::finalize(
return true;
}
//------------------------------------------------------------------------------
void
NoEmptyDirectory::visitEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after)
{
if (isDelete)
return;
if (before && before->getType() != ltDIR_NODE)
return;
if (after && after->getType() != ltDIR_NODE)
return;
if (!after->isFieldPresent(sfOwner))
// Not an account dir
return;
bad_ = after->at(sfIndexes).empty();
}
bool
NoEmptyDirectory::finalize(
STTx const& tx,
TER const result,
XRPAmount const,
ReadView const& view,
beast::Journal const& j)
{
if (bad_)
{
JLOG(j.fatal()) << "Invariant failed: empty owner directory.";
return false;
}
return true;
}
} // namespace ripple

View File

@@ -783,30 +783,6 @@ public:
beast::Journal const&);
};
/**
* @brief Invariants: An account's directory should never be empty
*
*/
class NoEmptyDirectory
{
bool bad_ = false;
public:
void
visitEntry(
bool,
std::shared_ptr<SLE const> const&,
std::shared_ptr<SLE const> const&);
bool
finalize(
STTx const&,
TER const,
XRPAmount const,
ReadView const&,
beast::Journal const&);
};
// additional invariant checks can be declared above and then added to this
// tuple
using InvariantChecks = std::tuple<
@@ -830,8 +806,7 @@ using InvariantChecks = std::tuple<
ValidPermissionedDEX,
ValidAMM,
ValidPseudoAccounts,
ValidVault,
NoEmptyDirectory>;
ValidVault>;
/**
* @brief get a tuple of all invariant checks

View File

@@ -16,8 +16,6 @@
#include <xrpl/protocol/STXChainBridge.h>
#include <xrpl/protocol/jss.h>
#include <functional>
namespace ripple {
static Expected<uint256, Json::Value>
@@ -178,18 +176,41 @@ static Expected<STArray, Json::Value>
parseAuthorizeCredentials(Json::Value const& jv)
{
if (!jv.isArray())
{
return LedgerEntryHelpers::invalidFieldError(
"malformedAuthorizedCredentials",
jss::authorized_credentials,
"array");
STArray arr(sfAuthorizeCredentials, jv.size());
}
std::uint32_t const n = jv.size();
if (n > maxCredentialsArraySize)
{
return Unexpected(LedgerEntryHelpers::malformedError(
"malformedAuthorizedCredentials",
"Invalid field '" + std::string(jss::authorized_credentials) +
"', array too long."));
}
if (n == 0)
{
return Unexpected(LedgerEntryHelpers::malformedError(
"malformedAuthorizedCredentials",
"Invalid field '" + std::string(jss::authorized_credentials) +
"', array empty."));
}
STArray arr(sfAuthorizeCredentials, n);
for (auto const& jo : jv)
{
if (!jo.isObject())
{
return LedgerEntryHelpers::invalidFieldError(
"malformedAuthorizedCredentials",
jss::authorized_credentials,
"array");
}
if (auto const value = LedgerEntryHelpers::hasRequired(
jo,
{jss::issuer, jss::credential_type},
@@ -260,13 +281,6 @@ parseDepositPreauth(Json::Value const& dp, Json::StaticString const fieldName)
auto const arr = parseAuthorizeCredentials(ac);
if (!arr.has_value())
return Unexpected(arr.error());
if (arr->empty() || (arr->size() > maxCredentialsArraySize))
{
return LedgerEntryHelpers::invalidFieldError(
"malformedAuthorizedCredentials",
jss::authorized_credentials,
"array");
}
auto const& sorted = credentials::makeSorted(arr.value());
if (sorted.empty())