Fixed unsafe usage of log::Stream buffers

pull/166/head
SChernykh 2 years ago
parent c45689b02b
commit 1a35177633

@ -72,7 +72,7 @@ JSONRPCRequest::JSONRPCRequest(const char* address, int port, const char* req, C
m_request.reserve(std::max<size_t>(len + 128, log::Stream::BUF_SIZE + 1)); m_request.reserve(std::max<size_t>(len + 128, log::Stream::BUF_SIZE + 1));
m_request.resize(log::Stream::BUF_SIZE + 1); m_request.resize(log::Stream::BUF_SIZE + 1);
log::Stream s(m_request.data()); log::Stream s(m_request.data(), m_request.size());
s << "POST " << uri << " HTTP/1.1\nContent-Type: application/json\nContent-Length: " << len << "\n\n"; s << "POST " << uri << " HTTP/1.1\nContent-Type: application/json\nContent-Length: " << len << "\n\n";
m_request.resize(s.m_pos); m_request.resize(s.m_pos);

@ -35,8 +35,10 @@ struct Stream
{ {
enum params : int { BUF_SIZE = 1024 - 1 }; enum params : int { BUF_SIZE = 1024 - 1 };
explicit FORCEINLINE Stream(char* buf) : m_pos(0), m_numberWidth(1), m_buf(buf), m_bufSize(BUF_SIZE) {} template<size_t N>
FORCEINLINE Stream(char* buf, size_t size) : m_pos(0), m_numberWidth(1), m_buf(buf), m_bufSize(static_cast<int>(size) - 1) {} explicit FORCEINLINE Stream(char (&buf)[N]) : m_pos(0), m_numberWidth(1), m_buf(buf), m_bufSize(N - 1) {}
FORCEINLINE Stream(void* buf, size_t size) : m_pos(0), m_numberWidth(1), m_buf(reinterpret_cast<char*>(buf)), m_bufSize(static_cast<int>(size) - 1) {}
template<typename T> template<typename T>
struct Entry struct Entry

@ -37,6 +37,8 @@ static const char* seed_nodes_mini[] = { "seeds-mini.p2pool.io", "" };
static constexpr int DEFAULT_BACKLOG = 16; static constexpr int DEFAULT_BACKLOG = 16;
static constexpr uint64_t DEFAULT_BAN_TIME = 600; static constexpr uint64_t DEFAULT_BAN_TIME = 600;
static constexpr size_t SEND_BUF_MIN_SIZE = 256;
#include "tcp_server.inl" #include "tcp_server.inl"
namespace p2pool { namespace p2pool {
@ -310,9 +312,14 @@ void P2PServer::update_peer_list()
client->m_nextOutgoingPeerListRequest = cur_time + (60 + (get_random64() % 61)); client->m_nextOutgoingPeerListRequest = cur_time + (60 + (get_random64() % 61));
const bool result = send(client, const bool result = send(client,
[](void* buf) [](void* buf, size_t buf_size)
{ {
LOGINFO(5, "sending PEER_LIST_REQUEST"); LOGINFO(5, "sending PEER_LIST_REQUEST");
if (buf_size < SEND_BUF_MIN_SIZE) {
return 0;
}
*reinterpret_cast<uint8_t*>(buf) = static_cast<uint8_t>(MessageId::PEER_LIST_REQUEST); *reinterpret_cast<uint8_t*>(buf) = static_cast<uint8_t>(MessageId::PEER_LIST_REQUEST);
return 1; return 1;
}); });
@ -780,7 +787,8 @@ void P2PServer::on_broadcast()
} }
for (Broadcast* data : broadcast_queue) { for (Broadcast* data : broadcast_queue) {
send(client, [client, data](void* buf) { send(client, [client, data](void* buf, size_t buf_size) -> size_t
{
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
@ -798,9 +806,14 @@ void P2PServer::on_broadcast()
if (send_pruned) { if (send_pruned) {
LOGINFO(6, "sending BLOCK_BROADCAST (pruned) to " << log::Gray() << static_cast<char*>(client->m_addrString)); LOGINFO(6, "sending BLOCK_BROADCAST (pruned) to " << log::Gray() << static_cast<char*>(client->m_addrString));
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_BROADCAST);
const uint32_t len = static_cast<uint32_t>(data->pruned_blob.size()); const uint32_t len = static_cast<uint32_t>(data->pruned_blob.size());
if (buf_size < SEND_BUF_MIN_SIZE + 1 + sizeof(uint32_t) + len) {
return 0;
}
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_BROADCAST);
memcpy(p, &len, sizeof(uint32_t)); memcpy(p, &len, sizeof(uint32_t));
p += sizeof(uint32_t); p += sizeof(uint32_t);
@ -811,9 +824,14 @@ void P2PServer::on_broadcast()
} }
else { else {
LOGINFO(5, "sending BLOCK_BROADCAST (full) to " << log::Gray() << static_cast<char*>(client->m_addrString)); LOGINFO(5, "sending BLOCK_BROADCAST (full) to " << log::Gray() << static_cast<char*>(client->m_addrString));
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_BROADCAST);
const uint32_t len = static_cast<uint32_t>(data->blob.size()); const uint32_t len = static_cast<uint32_t>(data->blob.size());
if (buf_size < SEND_BUF_MIN_SIZE + 1 + sizeof(uint32_t) + len) {
return 0;
}
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_BROADCAST);
memcpy(p, &len, sizeof(uint32_t)); memcpy(p, &len, sizeof(uint32_t));
p += sizeof(uint32_t); p += sizeof(uint32_t);
@ -980,12 +998,17 @@ void P2PServer::download_missing_blocks()
} }
const bool result = send(client, const bool result = send(client,
[&id](void* buf) [&id](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id);
if (buf_size < SEND_BUF_MIN_SIZE) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id);
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST); *(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
memcpy(p, id.h, HASH_SIZE); memcpy(p, id.h, HASH_SIZE);
@ -1348,12 +1371,17 @@ bool P2PServer::P2PClient::send_handshake_challenge()
m_handshakeChallenge = owner->get_random64(); m_handshakeChallenge = owner->get_random64();
return owner->send(this, return owner->send(this,
[this, owner](void* buf) [this, owner](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending HANDSHAKE_CHALLENGE");
if (buf_size < SEND_BUF_MIN_SIZE) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending HANDSHAKE_CHALLENGE");
*(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_CHALLENGE); *(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_CHALLENGE);
uint64_t k = m_handshakeChallenge; uint64_t k = m_handshakeChallenge;
@ -1465,12 +1493,17 @@ void P2PServer::P2PClient::send_handshake_solution(const uint8_t (&challenge)[CH
} }
const bool result = work->server->send(work->client, const bool result = work->server->send(work->client,
[work](void* buf) [work](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending HANDSHAKE_SOLUTION");
if (buf_size < SEND_BUF_MIN_SIZE) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending HANDSHAKE_SOLUTION");
*(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_SOLUTION); *(p++) = static_cast<uint8_t>(MessageId::HANDSHAKE_SOLUTION);
memcpy(p, work->solution.h, HASH_SIZE); memcpy(p, work->solution.h, HASH_SIZE);
@ -1615,8 +1648,14 @@ bool P2PServer::P2PClient::on_handshake_solution(const uint8_t* buf)
} }
return m_owner->send(this, return m_owner->send(this,
[this](void* buf) [this](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending LISTEN_PORT and BLOCK_REQUEST for the chain tip");
if (buf_size < SEND_BUF_MIN_SIZE) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
on_after_handshake(p); on_after_handshake(p);
@ -1679,15 +1718,21 @@ bool P2PServer::P2PClient::on_block_request(const uint8_t* buf)
} }
return server->send(this, return server->send(this,
[&blob](void* buf) [&blob](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending BLOCK_RESPONSE");
const uint32_t len = static_cast<uint32_t>(blob.size());
if (buf_size < SEND_BUF_MIN_SIZE + 1 + sizeof(uint32_t) + len) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending BLOCK_RESPONSE");
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_RESPONSE); *(p++) = static_cast<uint8_t>(MessageId::BLOCK_RESPONSE);
const uint32_t len = static_cast<uint32_t>(blob.size());
memcpy(p, &len, sizeof(uint32_t)); memcpy(p, &len, sizeof(uint32_t));
p += sizeof(uint32_t); p += sizeof(uint32_t);
@ -1841,12 +1886,17 @@ bool P2PServer::P2PClient::on_peer_list_request(const uint8_t*)
} }
return server->send(this, return server->send(this,
[&peers, num_selected_peers](void* buf) [&peers, num_selected_peers](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending PEER_LIST_RESPONSE");
if (buf_size < SEND_BUF_MIN_SIZE + 2 + num_selected_peers * 19) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending PEER_LIST_RESPONSE");
*(p++) = static_cast<uint8_t>(MessageId::PEER_LIST_RESPONSE); *(p++) = static_cast<uint8_t>(MessageId::PEER_LIST_RESPONSE);
*(p++) = static_cast<uint8_t>(num_selected_peers); *(p++) = static_cast<uint8_t>(num_selected_peers);
@ -2002,12 +2052,17 @@ void P2PServer::P2PClient::post_handle_incoming_block(const uint32_t reset_count
} }
const bool result = m_owner->send(this, const bool result = m_owner->send(this,
[&id](void* buf) [&id](void* buf, size_t buf_size) -> size_t
{ {
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id);
if (buf_size < SEND_BUF_MIN_SIZE + 1 + HASH_SIZE) {
return 0;
}
uint8_t* p0 = reinterpret_cast<uint8_t*>(buf); uint8_t* p0 = reinterpret_cast<uint8_t*>(buf);
uint8_t* p = p0; uint8_t* p = p0;
LOGINFO(5, "sending BLOCK_REQUEST for id = " << id);
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST); *(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
memcpy(p, id.h, HASH_SIZE); memcpy(p, id.h, HASH_SIZE);

@ -267,7 +267,7 @@ bool StratumServer::on_login(StratumClient* client, uint32_t id, const char* log
} }
const bool result = send(client, const bool result = send(client,
[client, id, &hashing_blob, job_id, blob_size, target, height, &seed_hash](void* buf) [client, id, &hashing_blob, job_id, blob_size, target, height, &seed_hash](void* buf, size_t buf_size)
{ {
do { do {
client->m_rpcId = static_cast<uint32_t>(static_cast<StratumServer*>(client->m_owner)->get_random64()); client->m_rpcId = static_cast<uint32_t>(static_cast<StratumServer*>(client->m_owner)->get_random64());
@ -280,7 +280,7 @@ bool StratumServer::on_login(StratumClient* client, uint32_t id, const char* log
target_hex.m_size -= sizeof(uint32_t); target_hex.m_size -= sizeof(uint32_t);
} }
log::Stream s(reinterpret_cast<char*>(buf)); log::Stream s(buf, buf_size);
s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"result\":{\"id\":\""; s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"result\":{\"id\":\"";
s << log::Hex(client->m_rpcId) << "\",\"job\":{\"blob\":\""; s << log::Hex(client->m_rpcId) << "\",\"job\":{\"blob\":\"";
s << log::hex_buf(hashing_blob, blob_size) << "\",\"job_id\":\""; s << log::hex_buf(hashing_blob, blob_size) << "\",\"job_id\":\"";
@ -353,9 +353,9 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
if (!block.get_difficulties(template_id, mainchain_diff, sidechain_diff)) { if (!block.get_difficulties(template_id, mainchain_diff, sidechain_diff)) {
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a stale share"); LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a stale share");
return send(client, return send(client,
[id](void* buf) [id](void* buf, size_t buf_size)
{ {
log::Stream s(reinterpret_cast<char*>(buf)); log::Stream s(buf, buf_size);
s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Stale share\"}}\n"; s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Stale share\"}}\n";
return s.m_pos; return s.m_pos;
}); });
@ -419,9 +419,9 @@ bool StratumServer::on_submit(StratumClient* client, uint32_t id, const char* jo
LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a share with invalid job id"); LOGWARN(4, "client " << static_cast<char*>(client->m_addrString) << " got a share with invalid job id");
const bool result = send(client, const bool result = send(client,
[id](void* buf) [id](void* buf, size_t buf_size)
{ {
log::Stream s(reinterpret_cast<char*>(buf)); log::Stream s(buf, buf_size);
s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Invalid job id\"}}\n"; s << "{\"id\":" << id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Invalid job id\"}}\n";
return s.m_pos; return s.m_pos;
}); });
@ -570,7 +570,7 @@ void StratumServer::on_blobs_ready()
} }
const bool result = send(client, const bool result = send(client,
[data, target, hashing_blob, &job_id](void* buf) [data, target, hashing_blob, &job_id](void* buf, size_t buf_size)
{ {
log::hex_buf target_hex(reinterpret_cast<const uint8_t*>(&target), sizeof(uint64_t)); log::hex_buf target_hex(reinterpret_cast<const uint8_t*>(&target), sizeof(uint64_t));
@ -579,7 +579,7 @@ void StratumServer::on_blobs_ready()
target_hex.m_size -= sizeof(uint32_t); target_hex.m_size -= sizeof(uint32_t);
} }
log::Stream s(reinterpret_cast<char*>(buf)); log::Stream s(buf, buf_size);
s << "{\"jsonrpc\":\"2.0\",\"method\":\"job\",\"params\":{\"blob\":\""; s << "{\"jsonrpc\":\"2.0\",\"method\":\"job\",\"params\":{\"blob\":\"";
s << log::hex_buf(hashing_blob, data->m_blobSize) << "\",\"job_id\":\""; s << log::hex_buf(hashing_blob, data->m_blobSize) << "\",\"job_id\":\"";
s << log::Hex(job_id) << "\",\"target\":\""; s << log::Hex(job_id) << "\",\"target\":\"";
@ -739,9 +739,9 @@ void StratumServer::on_after_share_found(uv_work_t* req, int /*status*/)
if ((client->m_resetCounter.load() == share->m_clientResetCounter) && (client->m_rpcId == share->m_rpcId)) { if ((client->m_resetCounter.load() == share->m_clientResetCounter) && (client->m_rpcId == share->m_rpcId)) {
const bool result = server->send(client, const bool result = server->send(client,
[share](void* buf) [share](void* buf, size_t buf_size)
{ {
log::Stream s(reinterpret_cast<char*>(buf)); log::Stream s(buf, buf_size);
switch (share->m_result) { switch (share->m_result) {
case SubmittedShare::Result::STALE: case SubmittedShare::Result::STALE:
s << "{\"id\":" << share->m_id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Stale share\"}}\n"; s << "{\"id\":" << share->m_id << ",\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"Stale share\"}}\n";

@ -105,14 +105,14 @@ public:
struct SendCallbackBase struct SendCallbackBase
{ {
virtual ~SendCallbackBase() {} virtual ~SendCallbackBase() {}
virtual size_t operator()(void*) = 0; virtual size_t operator()(void*, size_t) = 0;
}; };
template<typename T> template<typename T>
struct SendCallback : public SendCallbackBase struct SendCallback : public SendCallbackBase
{ {
explicit FORCEINLINE SendCallback(T&& callback) : m_callback(std::move(callback)) {} explicit FORCEINLINE SendCallback(T&& callback) : m_callback(std::move(callback)) {}
size_t operator()(void* buf) override { return m_callback(buf); } size_t operator()(void* buf, size_t buf_size) override { return m_callback(buf, buf_size); }
private: private:
SendCallback& operator=(SendCallback&&) = delete; SendCallback& operator=(SendCallback&&) = delete;

@ -556,7 +556,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::send_internal(Client* client, Sen
// callback_buf is used in only 1 thread, so it's safe // callback_buf is used in only 1 thread, so it's safe
static uint8_t callback_buf[WRITE_BUF_SIZE]; static uint8_t callback_buf[WRITE_BUF_SIZE];
const size_t bytes_written = callback(callback_buf); const size_t bytes_written = callback(callback_buf, sizeof(callback_buf));
if (bytes_written > WRITE_BUF_SIZE) { if (bytes_written > WRITE_BUF_SIZE) {
LOGERR(0, "send callback wrote " << bytes_written << " bytes, expected no more than " << WRITE_BUF_SIZE << " bytes"); LOGERR(0, "send callback wrote " << bytes_written << " bytes, expected no more than " << WRITE_BUF_SIZE << " bytes");

Loading…
Cancel
Save