Skip to content

Commit 297c888

Browse files
committed
net: make V2Transport preallocate receive buffer space
1 parent 3ffa5fb commit 297c888

File tree

1 file changed

+37
-0
lines changed

1 file changed

+37
-0
lines changed

src/net.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,9 @@ size_t V2Transport::GetMaxBytesToProcess() noexcept
13171317
bool V2Transport::ReceivedBytes(Span<const uint8_t>& msg_bytes) noexcept
13181318
{
13191319
AssertLockNotHeld(m_recv_mutex);
1320+
/** How many bytes to allocate in the receive buffer at most above what is received so far. */
1321+
static constexpr size_t MAX_RESERVE_AHEAD = 256 * 1024;
1322+
13201323
LOCK(m_recv_mutex);
13211324
if (m_recv_state == RecvState::V1) return m_v1_fallback.ReceivedBytes(msg_bytes);
13221325

@@ -1327,6 +1330,40 @@ bool V2Transport::ReceivedBytes(Span<const uint8_t>& msg_bytes) noexcept
13271330
while (!msg_bytes.empty()) {
13281331
// Decide how many bytes to copy from msg_bytes to m_recv_buffer.
13291332
size_t max_read = GetMaxBytesToProcess();
1333+
1334+
// Reserve space in the buffer if there is not enough.
1335+
if (m_recv_buffer.size() + std::min(msg_bytes.size(), max_read) > m_recv_buffer.capacity()) {
1336+
switch (m_recv_state) {
1337+
case RecvState::KEY_MAYBE_V1:
1338+
case RecvState::KEY:
1339+
case RecvState::GARB_GARBTERM:
1340+
// During the initial states (key/garbage), allocate once to fit the maximum (4111
1341+
// bytes).
1342+
m_recv_buffer.reserve(MAX_GARBAGE_LEN + BIP324Cipher::GARBAGE_TERMINATOR_LEN);
1343+
break;
1344+
case RecvState::GARBAUTH:
1345+
case RecvState::VERSION:
1346+
case RecvState::APP: {
1347+
// During states where a packet is being received, as much as is expected but never
1348+
// more than MAX_RESERVE_AHEAD bytes in addition to what is received so far.
1349+
// This means attackers that want to cause us to waste allocated memory are limited
1350+
// to MAX_RESERVE_AHEAD above the largest allowed message contents size, and to
1351+
// MAX_RESERVE_AHEAD more than they've actually sent us.
1352+
size_t alloc_add = std::min(max_read, msg_bytes.size() + MAX_RESERVE_AHEAD);
1353+
m_recv_buffer.reserve(m_recv_buffer.size() + alloc_add);
1354+
break;
1355+
}
1356+
case RecvState::APP_READY:
1357+
// The buffer is empty in this state.
1358+
Assume(m_recv_buffer.empty());
1359+
break;
1360+
case RecvState::V1:
1361+
// Should have bailed out above.
1362+
Assume(false);
1363+
break;
1364+
}
1365+
}
1366+
13301367
// Can't read more than provided input.
13311368
max_read = std::min(msg_bytes.size(), max_read);
13321369
// Copy data to buffer.

0 commit comments

Comments
 (0)