net.cpp
1 // Copyright (c) 2009-2022 The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 5 #include <test/fuzz/util/net.h> 6 7 #include <compat/compat.h> 8 #include <netaddress.h> 9 #include <node/protocol_version.h> 10 #include <protocol.h> 11 #include <test/fuzz/FuzzedDataProvider.h> 12 #include <test/fuzz/util.h> 13 #include <test/util/net.h> 14 #include <util/sock.h> 15 #include <util/time.h> 16 17 #include <array> 18 #include <cassert> 19 #include <cerrno> 20 #include <cstdint> 21 #include <cstdlib> 22 #include <cstring> 23 #include <thread> 24 #include <vector> 25 26 class CNode; 27 28 CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider, FastRandomContext* rand) noexcept 29 { 30 struct NetAux { 31 Network net; 32 CNetAddr::BIP155Network bip155; 33 size_t len; 34 }; 35 36 static constexpr std::array<NetAux, 6> nets{ 37 NetAux{.net = Network::NET_IPV4, .bip155 = CNetAddr::BIP155Network::IPV4, .len = ADDR_IPV4_SIZE}, 38 NetAux{.net = Network::NET_IPV6, .bip155 = CNetAddr::BIP155Network::IPV6, .len = ADDR_IPV6_SIZE}, 39 NetAux{.net = Network::NET_ONION, .bip155 = CNetAddr::BIP155Network::TORV3, .len = ADDR_TORV3_SIZE}, 40 NetAux{.net = Network::NET_I2P, .bip155 = CNetAddr::BIP155Network::I2P, .len = ADDR_I2P_SIZE}, 41 NetAux{.net = Network::NET_CJDNS, .bip155 = CNetAddr::BIP155Network::CJDNS, .len = ADDR_CJDNS_SIZE}, 42 NetAux{.net = Network::NET_INTERNAL, .bip155 = CNetAddr::BIP155Network{0}, .len = 0}, 43 }; 44 45 const size_t nets_index{rand == nullptr 46 ? fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, nets.size() - 1) 47 : static_cast<size_t>(rand->randrange(nets.size()))}; 48 49 const auto& aux = nets[nets_index]; 50 51 CNetAddr addr; 52 53 if (aux.net == Network::NET_INTERNAL) { 54 if (rand == nullptr) { 55 addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32)); 56 } else { 57 const auto v = rand->randbytes(32); 58 addr.SetInternal(std::string{v.begin(), v.end()}); 59 } 60 return addr; 61 } 62 63 DataStream s; 64 65 s << static_cast<uint8_t>(aux.bip155); 66 67 std::vector<uint8_t> addr_bytes; 68 if (rand == nullptr) { 69 addr_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(aux.len); 70 addr_bytes.resize(aux.len); 71 } else { 72 addr_bytes = rand->randbytes(aux.len); 73 } 74 if (aux.net == NET_IPV6 && addr_bytes[0] == CJDNS_PREFIX) { // Avoid generating IPv6 addresses that look like CJDNS. 75 addr_bytes[0] = 0x55; // Just an arbitrary number, anything != CJDNS_PREFIX would do. 76 } 77 if (aux.net == NET_CJDNS) { // Avoid generating CJDNS addresses that don't start with CJDNS_PREFIX because those are !IsValid(). 78 addr_bytes[0] = CJDNS_PREFIX; 79 } 80 s << addr_bytes; 81 82 s >> CAddress::V2_NETWORK(addr); 83 84 return addr; 85 } 86 87 CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept 88 { 89 return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}}; 90 } 91 92 template <typename P> 93 P ConsumeDeserializationParams(FuzzedDataProvider& fuzzed_data_provider) noexcept 94 { 95 constexpr std::array ADDR_ENCODINGS{ 96 CNetAddr::Encoding::V1, 97 CNetAddr::Encoding::V2, 98 }; 99 constexpr std::array ADDR_FORMATS{ 100 CAddress::Format::Disk, 101 CAddress::Format::Network, 102 }; 103 if constexpr (std::is_same_v<P, CNetAddr::SerParams>) { 104 return P{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)}; 105 } 106 if constexpr (std::is_same_v<P, CAddress::SerParams>) { 107 return P{{PickValue(fuzzed_data_provider, ADDR_ENCODINGS)}, PickValue(fuzzed_data_provider, ADDR_FORMATS)}; 108 } 109 } 110 template CNetAddr::SerParams ConsumeDeserializationParams(FuzzedDataProvider&) noexcept; 111 template CAddress::SerParams ConsumeDeserializationParams(FuzzedDataProvider&) noexcept; 112 113 FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) 114 : Sock{fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET)}, 115 m_fuzzed_data_provider{fuzzed_data_provider}, 116 m_selectable{fuzzed_data_provider.ConsumeBool()} 117 { 118 } 119 120 FuzzedSock::~FuzzedSock() 121 { 122 // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call 123 // close(m_socket) if m_socket is not INVALID_SOCKET. 124 // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which 125 // theoretically may concide with a real opened file descriptor). 126 m_socket = INVALID_SOCKET; 127 } 128 129 FuzzedSock& FuzzedSock::operator=(Sock&& other) 130 { 131 assert(false && "Move of Sock into FuzzedSock not allowed."); 132 return *this; 133 } 134 135 ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const 136 { 137 constexpr std::array send_errnos{ 138 EACCES, 139 EAGAIN, 140 EALREADY, 141 EBADF, 142 ECONNRESET, 143 EDESTADDRREQ, 144 EFAULT, 145 EINTR, 146 EINVAL, 147 EISCONN, 148 EMSGSIZE, 149 ENOBUFS, 150 ENOMEM, 151 ENOTCONN, 152 ENOTSOCK, 153 EOPNOTSUPP, 154 EPIPE, 155 EWOULDBLOCK, 156 }; 157 if (m_fuzzed_data_provider.ConsumeBool()) { 158 return len; 159 } 160 const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len); 161 if (r == -1) { 162 SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos); 163 } 164 return r; 165 } 166 167 ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const 168 { 169 // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted 170 // SetFuzzedErrNo() will always return the first element and we want to avoid Recv() 171 // returning -1 and setting errno to EAGAIN repeatedly. 172 constexpr std::array recv_errnos{ 173 ECONNREFUSED, 174 EAGAIN, 175 EBADF, 176 EFAULT, 177 EINTR, 178 EINVAL, 179 ENOMEM, 180 ENOTCONN, 181 ENOTSOCK, 182 EWOULDBLOCK, 183 }; 184 assert(buf != nullptr || len == 0); 185 if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) { 186 const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; 187 if (r == -1) { 188 SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); 189 } 190 return r; 191 } 192 std::vector<uint8_t> random_bytes; 193 bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()}; 194 if (m_peek_data.has_value()) { 195 // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`. 196 random_bytes.assign({m_peek_data.value()}); 197 if ((flags & MSG_PEEK) == 0) { 198 m_peek_data.reset(); 199 } 200 pad_to_len_bytes = false; 201 } else if ((flags & MSG_PEEK) != 0) { 202 // New call with `MSG_PEEK`. 203 random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1); 204 if (!random_bytes.empty()) { 205 m_peek_data = random_bytes[0]; 206 pad_to_len_bytes = false; 207 } 208 } else { 209 random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>( 210 m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len)); 211 } 212 if (random_bytes.empty()) { 213 const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; 214 if (r == -1) { 215 SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); 216 } 217 return r; 218 } 219 std::memcpy(buf, random_bytes.data(), random_bytes.size()); 220 if (pad_to_len_bytes) { 221 if (len > random_bytes.size()) { 222 std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size()); 223 } 224 return len; 225 } 226 if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) { 227 std::this_thread::sleep_for(std::chrono::milliseconds{2}); 228 } 229 return random_bytes.size(); 230 } 231 232 int FuzzedSock::Connect(const sockaddr*, socklen_t) const 233 { 234 // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted 235 // SetFuzzedErrNo() will always return the first element and we want to avoid Connect() 236 // returning -1 and setting errno to EAGAIN repeatedly. 237 constexpr std::array connect_errnos{ 238 ECONNREFUSED, 239 EAGAIN, 240 ECONNRESET, 241 EHOSTUNREACH, 242 EINPROGRESS, 243 EINTR, 244 ENETUNREACH, 245 ETIMEDOUT, 246 }; 247 if (m_fuzzed_data_provider.ConsumeBool()) { 248 SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos); 249 return -1; 250 } 251 return 0; 252 } 253 254 int FuzzedSock::Bind(const sockaddr*, socklen_t) const 255 { 256 // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted 257 // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to 258 // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN) 259 // repeatedly because proper code should retry on temporary errors, leading to an 260 // infinite loop. 261 constexpr std::array bind_errnos{ 262 EACCES, 263 EADDRINUSE, 264 EADDRNOTAVAIL, 265 EAGAIN, 266 }; 267 if (m_fuzzed_data_provider.ConsumeBool()) { 268 SetFuzzedErrNo(m_fuzzed_data_provider, bind_errnos); 269 return -1; 270 } 271 return 0; 272 } 273 274 int FuzzedSock::Listen(int) const 275 { 276 // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted 277 // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to 278 // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN) 279 // repeatedly because proper code should retry on temporary errors, leading to an 280 // infinite loop. 281 constexpr std::array listen_errnos{ 282 EADDRINUSE, 283 EINVAL, 284 EOPNOTSUPP, 285 }; 286 if (m_fuzzed_data_provider.ConsumeBool()) { 287 SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos); 288 return -1; 289 } 290 return 0; 291 } 292 293 std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const 294 { 295 constexpr std::array accept_errnos{ 296 ECONNABORTED, 297 EINTR, 298 ENOMEM, 299 }; 300 if (m_fuzzed_data_provider.ConsumeBool()) { 301 SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos); 302 return std::unique_ptr<FuzzedSock>(); 303 } 304 return std::make_unique<FuzzedSock>(m_fuzzed_data_provider); 305 } 306 307 int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const 308 { 309 constexpr std::array getsockopt_errnos{ 310 ENOMEM, 311 ENOBUFS, 312 }; 313 if (m_fuzzed_data_provider.ConsumeBool()) { 314 SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos); 315 return -1; 316 } 317 if (opt_val == nullptr) { 318 return 0; 319 } 320 std::memcpy(opt_val, 321 ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(), 322 *opt_len); 323 return 0; 324 } 325 326 int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const 327 { 328 constexpr std::array setsockopt_errnos{ 329 ENOMEM, 330 ENOBUFS, 331 }; 332 if (m_fuzzed_data_provider.ConsumeBool()) { 333 SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos); 334 return -1; 335 } 336 return 0; 337 } 338 339 int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const 340 { 341 constexpr std::array getsockname_errnos{ 342 ECONNRESET, 343 ENOBUFS, 344 }; 345 if (m_fuzzed_data_provider.ConsumeBool()) { 346 SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos); 347 return -1; 348 } 349 *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len); 350 return 0; 351 } 352 353 bool FuzzedSock::SetNonBlocking() const 354 { 355 constexpr std::array setnonblocking_errnos{ 356 EBADF, 357 EPERM, 358 }; 359 if (m_fuzzed_data_provider.ConsumeBool()) { 360 SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos); 361 return false; 362 } 363 return true; 364 } 365 366 bool FuzzedSock::IsSelectable() const 367 { 368 return m_selectable; 369 } 370 371 bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const 372 { 373 constexpr std::array wait_errnos{ 374 EBADF, 375 EINTR, 376 EINVAL, 377 }; 378 if (m_fuzzed_data_provider.ConsumeBool()) { 379 SetFuzzedErrNo(m_fuzzed_data_provider, wait_errnos); 380 return false; 381 } 382 if (occurred != nullptr) { 383 *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0; 384 } 385 return true; 386 } 387 388 bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const 389 { 390 for (auto& [sock, events] : events_per_sock) { 391 (void)sock; 392 events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0; 393 } 394 return true; 395 } 396 397 bool FuzzedSock::IsConnected(std::string& errmsg) const 398 { 399 if (m_fuzzed_data_provider.ConsumeBool()) { 400 return true; 401 } 402 errmsg = "disconnected at random by the fuzzer"; 403 return false; 404 } 405 406 void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept 407 { 408 connman.Handshake(node, 409 /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(), 410 /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), 411 /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), 412 /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()), 413 /*relay_txs=*/fuzzed_data_provider.ConsumeBool()); 414 }