diff options
author | Wladimir J. van der Laan <laanwj@protonmail.com> | 2021-03-16 13:07:52 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@protonmail.com> | 2021-03-16 13:11:59 +0100 |
commit | 1b6c463e033f861561d1a46ccf7eec069bbac09f (patch) | |
tree | a6175ed1a96ea54a5cfd275503ed6ffb65e9039a /src/util | |
parent | 77234793004a757426f67389d09bcee502033aa1 (diff) | |
parent | 7059e6d82275b44efc41675ee10760145b6c1073 (diff) |
Merge #21407: i2p: limit the size of incoming messages
7059e6d82275b44efc41675ee10760145b6c1073 test: add a test to ensure RecvUntilTerminator() limit works (Vasil Dimov)
80a5a8ea2b7ad512c74c29df5b504e9be6cf23a0 i2p: limit the size of incoming messages (Vasil Dimov)
Pull request description:
Put a limit on the amount of data `Sock::RecvUntilTerminator()` can read
if no terminator is received.
In the case of I2P this avoids a runaway (or malicious) I2P proxy
sending us tons of data without a terminator before a timeout is
triggered.
ACKs for top commit:
laanwj:
Re-ACK 7059e6d82275b44efc41675ee10760145b6c1073
Tree-SHA512: 21f3f3468c765c726cdc877eae847cdb4dbe225d94c5bd1849bd752c9761fac881c554f16ea7a685ad40312159d554e126c481e21c5fd83a6d947060b920373d
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/sock.cpp | 10 | ||||
-rw-r--r-- | src/util/sock.h | 5 |
2 files changed, 12 insertions, 3 deletions
diff --git a/src/util/sock.cpp b/src/util/sock.cpp index e13c52a16a..f9ecfef5d4 100644 --- a/src/util/sock.cpp +++ b/src/util/sock.cpp @@ -175,7 +175,8 @@ void Sock::SendComplete(const std::string& data, std::string Sock::RecvUntilTerminator(uint8_t terminator, std::chrono::milliseconds timeout, - CThreadInterrupt& interrupt) const + CThreadInterrupt& interrupt, + size_t max_data) const { const auto deadline = GetTime<std::chrono::milliseconds>() + timeout; std::string data; @@ -190,9 +191,14 @@ std::string Sock::RecvUntilTerminator(uint8_t terminator, // at a time is about 50 times slower. for (;;) { + if (data.size() >= max_data) { + throw std::runtime_error( + strprintf("Received too many bytes without a terminator (%u)", data.size())); + } + char buf[512]; - const ssize_t peek_ret{Recv(buf, sizeof(buf), MSG_PEEK)}; + const ssize_t peek_ret{Recv(buf, std::min(sizeof(buf), max_data - data.size()), MSG_PEEK)}; switch (peek_ret) { case -1: { diff --git a/src/util/sock.h b/src/util/sock.h index ecebb84205..4b0618dcff 100644 --- a/src/util/sock.h +++ b/src/util/sock.h @@ -135,13 +135,16 @@ public: * @param[in] terminator Character up to which to read from the socket. * @param[in] timeout Timeout for the entire operation. * @param[in] interrupt If this is signaled then the operation is canceled. + * @param[in] max_data The maximum amount of data (in bytes) to receive. If this many bytes + * are received and there is still no terminator, then this method will throw an exception. * @return The data that has been read, without the terminating character. * @throws std::runtime_error if the operation cannot be completed. In this case some bytes may * have been consumed from the socket. */ virtual std::string RecvUntilTerminator(uint8_t terminator, std::chrono::milliseconds timeout, - CThreadInterrupt& interrupt) const; + CThreadInterrupt& interrupt, + size_t max_data) const; /** * Check if still connected. |