From 366e3e1f89d99c62b548087384487b62fd602e17 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Tue, 16 Feb 2021 09:56:47 +0000 Subject: [PATCH] fuzz: Add FUZZED_SOCKET_FAKE_LATENCY mode to FuzzedSock to allow for fuzzing timeout logic --- src/netbase.cpp | 18 +++++++++--------- src/test/fuzz/socks5.cpp | 10 ++++++++++ src/test/fuzz/util.h | 3 +++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/netbase.cpp b/src/netbase.cpp index 53d786084b6..88c36ed86c0 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -39,7 +39,7 @@ int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; bool fNameLookup = DEFAULT_NAME_LOOKUP; // Need ample time for negotiation for very slow proxies such as Tor (milliseconds) -static const int SOCKS5_RECV_TIMEOUT = 20 * 1000; +int g_socks5_recv_timeout = 20 * 1000; static std::atomic interruptSocks5Recv(false); enum Network ParseNetwork(const std::string& net_in) { @@ -455,7 +455,7 @@ bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, return error("Error sending to proxy"); } uint8_t pchRet1[2]; - if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) { + if ((recvr = InterruptibleRecv(pchRet1, 2, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port); return false; } @@ -478,7 +478,7 @@ bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, } LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); uint8_t pchRetA[2]; - if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) { + if ((recvr = InterruptibleRecv(pchRetA, 2, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { return error("Error reading proxy authentication response"); } if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) { @@ -503,7 +503,7 @@ bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, return error("Error sending to proxy"); } uint8_t pchRet2[4]; - if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) { + if ((recvr = InterruptibleRecv(pchRet2, 4, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { if (recvr == IntrRecvError::Timeout) { /* If a timeout happens here, this effectively means we timed out while connecting * to the remote node. This is very common for Tor, so do not print an @@ -527,16 +527,16 @@ bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, uint8_t pchRet3[256]; switch (pchRet2[3]) { - case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, sock); break; - case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, sock); break; + case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, g_socks5_recv_timeout, sock); break; + case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, g_socks5_recv_timeout, sock); break; case SOCKS5Atyp::DOMAINNAME: { - recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, sock); + recvr = InterruptibleRecv(pchRet3, 1, g_socks5_recv_timeout, sock); if (recvr != IntrRecvError::OK) { return error("Error reading from proxy"); } int nRecv = pchRet3[0]; - recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, sock); + recvr = InterruptibleRecv(pchRet3, nRecv, g_socks5_recv_timeout, sock); break; } default: return error("Error: malformed proxy response"); @@ -544,7 +544,7 @@ bool Socks5(const std::string& strDest, int port, const ProxyCredentials* auth, if (recvr != IntrRecvError::OK) { return error("Error reading from proxy"); } - if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, sock)) != IntrRecvError::OK) { + if ((recvr = InterruptibleRecv(pchRet3, 2, g_socks5_recv_timeout, sock)) != IntrRecvError::OK) { return error("Error reading from proxy"); } LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest); diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp index 1f2f8ee7c3a..123ee042ee6 100644 --- a/src/test/fuzz/socks5.cpp +++ b/src/test/fuzz/socks5.cpp @@ -11,9 +11,16 @@ #include #include +namespace { +int default_socks5_recv_timeout; +}; + +extern int g_socks5_recv_timeout; + void initialize_socks5() { static const auto testing_setup = MakeNoLogFileContext(); + default_socks5_recv_timeout = g_socks5_recv_timeout; } FUZZ_TARGET_INIT(socks5, initialize_socks5) @@ -23,6 +30,9 @@ FUZZ_TARGET_INIT(socks5, initialize_socks5) proxy_credentials.username = fuzzed_data_provider.ConsumeRandomLengthString(512); proxy_credentials.password = fuzzed_data_provider.ConsumeRandomLengthString(512); InterruptSocks5(fuzzed_data_provider.ConsumeBool()); + // Set FUZZED_SOCKET_FAKE_LATENCY=1 to exercise recv timeout code paths. This + // will slow down fuzzing. + g_socks5_recv_timeout = (fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) ? 1 : default_socks5_recv_timeout; FuzzedSock fuzzed_sock = ConsumeSock(fuzzed_data_provider); // This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within // a few seconds of fuzzing. diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 4b7b4c88c83..daded0959fc 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -642,6 +642,9 @@ public: } return len; } + if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) { + std::this_thread::sleep_for(std::chrono::milliseconds{2}); + } return random_bytes.size(); }