rpc: add a sanity limit to a few RPC in restricted mode

This commit is contained in:
moneromooo-monero 2020-05-18 21:47:33 +00:00
parent 77a008f714
commit 4d3c2d0b7b
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
2 changed files with 46 additions and 6 deletions

View file

@ -68,6 +68,11 @@ using namespace epee;
#define DEFAULT_PAYMENT_DIFFICULTY 1000 #define DEFAULT_PAYMENT_DIFFICULTY 1000
#define DEFAULT_PAYMENT_CREDITS_PER_HASH 100 #define DEFAULT_PAYMENT_CREDITS_PER_HASH 100
#define RESTRICTED_BLOCK_HEADER_RANGE 1000
#define RESTRICTED_TRANSACTIONS_COUNT 100
#define RESTRICTED_SPENT_KEY_IMAGES_COUNT 5000
#define RESTRICTED_BLOCK_COUNT 1000
#define RPC_TRACKER(rpc) \ #define RPC_TRACKER(rpc) \
PERF_TIMER(rpc); \ PERF_TIMER(rpc); \
RPCTracker tracker(#rpc, PERF_TIMER_NAME(rpc)) RPCTracker tracker(#rpc, PERF_TIMER_NAME(rpc))
@ -639,6 +644,13 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_BY_HEIGHT>(invoke_http_mode::BIN, "/getblocks_by_height.bin", req, res, r)) if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_BY_HEIGHT>(invoke_http_mode::BIN, "/getblocks_by_height.bin", req, res, r))
return r; return r;
const bool restricted = m_restricted && ctx;
if (restricted && req.heights.size() > RESTRICTED_BLOCK_COUNT)
{
res.status = "Too many blocks requested in restricted mode";
return true;
}
res.status = "Failed"; res.status = "Failed";
res.blocks.clear(); res.blocks.clear();
res.blocks.reserve(req.heights.size()); res.blocks.reserve(req.heights.size());
@ -793,11 +805,17 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON, "/gettransactions", req, res, ok)) if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON, "/gettransactions", req, res, ok))
return ok; return ok;
CHECK_PAYMENT_MIN1(req, res, req.txs_hashes.size() * COST_PER_TX, false);
const bool restricted = m_restricted && ctx; const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL; const bool request_has_rpc_origin = ctx != NULL;
if (restricted && req.txs_hashes.size() > RESTRICTED_TRANSACTIONS_COUNT)
{
res.status = "Too many transactions requested in restricted mode";
return true;
}
CHECK_PAYMENT_MIN1(req, res, req.txs_hashes.size() * COST_PER_TX, false);
std::vector<crypto::hash> vh; std::vector<crypto::hash> vh;
for(const auto& tx_hex_str: req.txs_hashes) for(const auto& tx_hex_str: req.txs_hashes)
{ {
@ -1027,11 +1045,17 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_KEY_IMAGE_SPENT>(invoke_http_mode::JON, "/is_key_image_spent", req, res, ok)) if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_KEY_IMAGE_SPENT>(invoke_http_mode::JON, "/is_key_image_spent", req, res, ok))
return ok; return ok;
CHECK_PAYMENT_MIN1(req, res, req.key_images.size() * COST_PER_KEY_IMAGE, false);
const bool restricted = m_restricted && ctx; const bool restricted = m_restricted && ctx;
const bool request_has_rpc_origin = ctx != NULL; const bool request_has_rpc_origin = ctx != NULL;
if (restricted && req.key_images.size() > RESTRICTED_SPENT_KEY_IMAGES_COUNT)
{
res.status = "Too many key images queried in restricted mode";
return true;
}
CHECK_PAYMENT_MIN1(req, res, req.key_images.size() * COST_PER_KEY_IMAGE, false);
std::vector<crypto::key_image> key_images; std::vector<crypto::key_image> key_images;
for(const auto& ki_hex_str: req.key_images) for(const auto& ki_hex_str: req.key_images)
{ {
@ -2034,6 +2058,14 @@ namespace cryptonote
CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false); CHECK_PAYMENT_MIN1(req, res, COST_PER_BLOCK_HEADER, false);
const bool restricted = m_restricted && ctx;
if (restricted && req.hashes.size() > RESTRICTED_BLOCK_COUNT)
{
error_resp.code = CORE_RPC_ERROR_CODE_RESTRICTED;
error_resp.message = "Too many block headers requested in restricted mode";
return false;
}
auto get = [this](const std::string &hash, bool fill_pow_hash, block_header_response &block_header, bool restricted, epee::json_rpc::error& error_resp) -> bool { auto get = [this](const std::string &hash, bool fill_pow_hash, block_header_response &block_header, bool restricted, epee::json_rpc::error& error_resp) -> bool {
crypto::hash block_hash; crypto::hash block_hash;
bool hash_parsed = parse_hash256(hash, block_hash); bool hash_parsed = parse_hash256(hash, block_hash);
@ -2069,7 +2101,6 @@ namespace cryptonote
return true; return true;
}; };
const bool restricted = m_restricted && ctx;
if (!req.hash.empty()) if (!req.hash.empty())
{ {
if (!get(req.hash, req.fill_pow_hash, res.block_header, restricted, error_resp)) if (!get(req.hash, req.fill_pow_hash, res.block_header, restricted, error_resp))
@ -2101,6 +2132,14 @@ namespace cryptonote
error_resp.message = "Invalid start/end heights."; error_resp.message = "Invalid start/end heights.";
return false; return false;
} }
const bool restricted = m_restricted && ctx;
if (restricted && req.end_height - req.start_height > RESTRICTED_BLOCK_HEADER_RANGE)
{
error_resp.code = CORE_RPC_ERROR_CODE_RESTRICTED;
error_resp.message = "Too many block headers requested.";
return false;
}
CHECK_PAYMENT_MIN1(req, res, (req.end_height - req.start_height + 1) * COST_PER_BLOCK_HEADER, false); CHECK_PAYMENT_MIN1(req, res, (req.end_height - req.start_height + 1) * COST_PER_BLOCK_HEADER, false);
for (uint64_t h = req.start_height; h <= req.end_height; ++h) for (uint64_t h = req.start_height; h <= req.end_height; ++h)
{ {
@ -2127,7 +2166,6 @@ namespace cryptonote
return false; return false;
} }
res.headers.push_back(block_header_response()); res.headers.push_back(block_header_response());
const bool restricted = m_restricted && ctx;
bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.headers.back(), req.fill_pow_hash && !restricted); bool response_filled = fill_block_header_response(blk, false, block_height, block_hash, res.headers.back(), req.fill_pow_hash && !restricted);
if (!response_filled) if (!response_filled)
{ {

View file

@ -48,6 +48,7 @@
#define CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW -16 #define CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW -16
#define CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT -17 #define CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT -17
#define CORE_RPC_ERROR_CODE_STALE_PAYMENT -18 #define CORE_RPC_ERROR_CODE_STALE_PAYMENT -18
#define CORE_RPC_ERROR_CODE_RESTRICTED -19
static inline const char *get_rpc_server_error_message(int64_t code) static inline const char *get_rpc_server_error_message(int64_t code)
{ {
@ -70,6 +71,7 @@ static inline const char *get_rpc_server_error_message(int64_t code)
case CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW: return "Payment too low"; case CORE_RPC_ERROR_CODE_PAYMENT_TOO_LOW: return "Payment too low";
case CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT: return "Duplicate payment"; case CORE_RPC_ERROR_CODE_DUPLICATE_PAYMENT: return "Duplicate payment";
case CORE_RPC_ERROR_CODE_STALE_PAYMENT: return "Stale payment"; case CORE_RPC_ERROR_CODE_STALE_PAYMENT: return "Stale payment";
case CORE_RPC_ERROR_CODE_RESTRICTED: return "Parameters beyond restricted allowance";
default: MERROR("Unknown error: " << code); return "Unknown error"; default: MERROR("Unknown error: " << code); return "Unknown error";
} }
} }