diff --git a/contrib/epee/include/net/http_protocol_handler.h b/contrib/epee/include/net/http_protocol_handler.h index bcd7516..51ed923 100644 --- a/contrib/epee/include/net/http_protocol_handler.h +++ b/contrib/epee/include/net/http_protocol_handler.h @@ -32,6 +32,7 @@ #define _HTTP_SERVER_H_ #include +#include #include #include "net_utils_base.h" #include "to_nonconst_iterator.h" @@ -58,6 +59,7 @@ namespace net_utils std::vector m_access_control_origins; authentication_type m_auth_type; boost::optional m_user; + size_t m_max_content_length{std::numeric_limits::max()}; critical_section m_lock; }; @@ -144,6 +146,7 @@ namespace net_utils config_type& m_config; bool m_want_close; size_t m_newlines; + size_t m_bytes_read; protected: i_service_endpoint* m_psnd_hndlr; t_connection_context& m_conn_context; diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl index 915daed..06ee0b4 100644 --- a/contrib/epee/include/net/http_protocol_handler.inl +++ b/contrib/epee/include/net/http_protocol_handler.inl @@ -206,6 +206,7 @@ namespace net_utils m_config(config), m_want_close(false), m_newlines(0), + m_bytes_read(0), m_psnd_hndlr(psnd_hndlr), m_conn_context(conn_context) { @@ -221,6 +222,7 @@ namespace net_utils m_query_info.clear(); m_len_summary = 0; m_newlines = 0; + m_bytes_read = 0; return true; } //-------------------------------------------------------------------------------------------- @@ -243,6 +245,14 @@ namespace net_utils size_t ndel; + m_bytes_read += buf.size(); + if (m_bytes_read > m_config.m_max_content_length) + { + LOG_ERROR("simple_http_connection_handler::handle_buff_in: Too much data: got " << m_bytes_read); + m_state = http_state_error; + return false; + } + if(m_cache.size()) m_cache += buf; else diff --git a/src/cryptonote_basic/verification_context.h b/src/cryptonote_basic/verification_context.h index e405b95..db3cc67 100644 --- a/src/cryptonote_basic/verification_context.h +++ b/src/cryptonote_basic/verification_context.h @@ -50,6 +50,7 @@ namespace cryptonote bool m_fee_too_low; bool m_not_rct; bool m_too_few_outputs; + bool m_tx_extra_too_big; }; struct block_verification_context diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 9255c28..1a3ab7a 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -112,8 +112,11 @@ #define CRYPTONOTE_MEMPOOL_TX_LIVETIME (86400 * 3) #define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 +// Mandatory tx content (16 outputs) + 1 custom tag + 32 bytes/recipient = 1060 +#define MAX_TX_EXTRA_SIZE 1060 #define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT 1000 +#define MAX_RPC_CONTENT_LENGTH 1048576 // 1 MB #define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000 #define P2P_LOCAL_GRAY_PEERLIST_LIMIT 5000 diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 60723c3..3ddbe6e 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -444,6 +444,8 @@ namespace cryptonote if (!sort_tx_extra(tx.extra, tx.extra)) return false; + CHECK_AND_ASSERT_MES(tx.extra.size() <= MAX_TX_EXTRA_SIZE, false, "TX extra size (" << tx.extra.size() << ") is greater than max allowed (" << MAX_TX_EXTRA_SIZE << ")"); + //check money if(summary_outs_money > summary_inputs_money ) { diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 8274b4c..6cb247e 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -162,6 +162,15 @@ namespace cryptonote return false; } + size_t tx_extra_size = tx.extra.size(); + if (!kept_by_block && tx_extra_size > MAX_TX_EXTRA_SIZE) + { + LOG_PRINT_L1("transaction tx-extra is too big: " << tx_extra_size << " bytes, the limit is: " << MAX_TX_EXTRA_SIZE); + tvc.m_verifivation_failed = true; + tvc.m_tx_extra_too_big = true; + return false; + } + // if the transaction came from a block popped from the chain, // don't check if we have its key images as spent. // TODO: Investigate why not? diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 5467866..e212914 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -240,6 +240,8 @@ namespace cryptonote if (rpc_config->login) http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password()); + m_net_server.get_config_object().m_max_content_length = MAX_RPC_CONTENT_LENGTH; + auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); }; return epee::http_server_impl_base::init( rng, std::move(port), std::move(rpc_config->bind_ip), @@ -1191,6 +1193,8 @@ namespace cryptonote add_reason(reason, "tx is not ringct"); if ((res.too_few_outputs = tvc.m_too_few_outputs)) add_reason(reason, "too few outputs"); + if ((res.tx_extra_too_big = tvc.m_tx_extra_too_big)) + add_reason(reason, "tx-extra too big"); const std::string punctuation = reason.empty() ? "" : ": "; if (tvc.m_verifivation_failed) { @@ -2772,6 +2776,14 @@ namespace cryptonote if (use_bootstrap_daemon_if_necessary(invoke_http_mode::JON_RPC, "get_output_distribution", req, res, r)) return r; + const bool restricted = m_restricted && ctx; + if (restricted && req.amounts != std::vector(1, 0)) + { + error_resp.code = CORE_RPC_ERROR_CODE_RESTRICTED; + error_resp.message = "Restricted RPC can only get output distribution for rct outputs. Use your own node."; + return false; + } + size_t n_0 = 0, n_non0 = 0; for (uint64_t amount: req.amounts) if (amount) ++n_non0; else ++n_0; @@ -2812,6 +2824,13 @@ namespace cryptonote if (use_bootstrap_daemon_if_necessary(invoke_http_mode::BIN, "/get_output_distribution.bin", req, res, r)) return r; + const bool restricted = m_restricted && ctx; + if (restricted && req.amounts != std::vector(1, 0)) + { + res.status = "Restricted RPC can only get output distribution for rct outputs. Use your own node."; + return false; + } + size_t n_0 = 0, n_non0 = 0; for (uint64_t amount: req.amounts) if (amount) ++n_non0; else ++n_0; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 5d85cc0..dcf59b6 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -87,7 +87,7 @@ namespace cryptonote // advance which version they will stop working with // Don't go over 32767 for any of these #define CORE_RPC_VERSION_MAJOR 3 -#define CORE_RPC_VERSION_MINOR 0 +#define CORE_RPC_VERSION_MINOR 1 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -564,6 +564,7 @@ namespace cryptonote bool not_rct; bool too_few_outputs; bool sanity_check_failed; + bool tx_extra_too_big; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_PARENT(rpc_response_base) @@ -579,6 +580,7 @@ namespace cryptonote KV_SERIALIZE(not_rct) KV_SERIALIZE(too_few_outputs) KV_SERIALIZE(sanity_check_failed) + KV_SERIALIZE(tx_extra_too_big) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init response; diff --git a/src/rpc/core_rpc_server_error_codes.h b/src/rpc/core_rpc_server_error_codes.h index 93f12bd..c126daf 100644 --- a/src/rpc/core_rpc_server_error_codes.h +++ b/src/rpc/core_rpc_server_error_codes.h @@ -43,6 +43,7 @@ #define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB_SIZE -10 #define CORE_RPC_ERROR_CODE_UNSUPPORTED_RPC -11 #define CORE_RPC_ERROR_CODE_MINING_TO_SUBADDRESS -12 +#define CORE_RPC_ERROR_CODE_RESTRICTED -14 #define CORE_RPC_ERROR_CODE_INVALID_CLIENT -15 #define CORE_RPC_ERROR_CODE_STALE_PAYMENT -18 @@ -61,6 +62,7 @@ static inline const char *get_rpc_server_error_message(int64_t code) case CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB_SIZE: return "Wrong block blob size"; case CORE_RPC_ERROR_CODE_UNSUPPORTED_RPC: return "Unsupported RPC"; case CORE_RPC_ERROR_CODE_MINING_TO_SUBADDRESS: return "Mining to subaddress is not supported"; + case CORE_RPC_ERROR_CODE_RESTRICTED: return "Restricted RPC"; case CORE_RPC_ERROR_CODE_INVALID_CLIENT: return "Invalid client"; case CORE_RPC_ERROR_CODE_STALE_PAYMENT: return "Stale payment"; default: MERROR("Unknown error: " << code); return "Unknown error";