|
2 | 2 | // Distributed under the MIT software license, see the accompanying |
3 | 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | 4 |
|
5 | | -#include <net_processing.h> |
6 | | -#include <netaddress.h> |
7 | | -#include <netmessagemaker.h> |
| 5 | +#include <consensus/amount.h> |
8 | 6 | #include <pubkey.h> |
9 | 7 | #include <test/fuzz/util.h> |
10 | 8 | #include <test/util/script.h> |
| 9 | +#include <util/check.h> |
11 | 10 | #include <util/overflow.h> |
12 | 11 | #include <util/time.h> |
13 | 12 | #include <version.h> |
14 | 13 |
|
15 | 14 | #include <memory> |
16 | 15 |
|
17 | | -FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) |
18 | | - : m_fuzzed_data_provider{fuzzed_data_provider}, m_selectable{fuzzed_data_provider.ConsumeBool()} |
19 | | -{ |
20 | | - m_socket = fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET); |
21 | | -} |
22 | | - |
23 | | -FuzzedSock::~FuzzedSock() |
24 | | -{ |
25 | | - // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call |
26 | | - // close(m_socket) if m_socket is not INVALID_SOCKET. |
27 | | - // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which |
28 | | - // theoretically may concide with a real opened file descriptor). |
29 | | - m_socket = INVALID_SOCKET; |
30 | | -} |
31 | | - |
32 | | -FuzzedSock& FuzzedSock::operator=(Sock&& other) |
33 | | -{ |
34 | | - assert(false && "Move of Sock into FuzzedSock not allowed."); |
35 | | - return *this; |
36 | | -} |
37 | | - |
38 | | -ssize_t FuzzedSock::Send(const void* data, size_t len, int flags) const |
39 | | -{ |
40 | | - constexpr std::array send_errnos{ |
41 | | - EACCES, |
42 | | - EAGAIN, |
43 | | - EALREADY, |
44 | | - EBADF, |
45 | | - ECONNRESET, |
46 | | - EDESTADDRREQ, |
47 | | - EFAULT, |
48 | | - EINTR, |
49 | | - EINVAL, |
50 | | - EISCONN, |
51 | | - EMSGSIZE, |
52 | | - ENOBUFS, |
53 | | - ENOMEM, |
54 | | - ENOTCONN, |
55 | | - ENOTSOCK, |
56 | | - EOPNOTSUPP, |
57 | | - EPIPE, |
58 | | - EWOULDBLOCK, |
59 | | - }; |
60 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
61 | | - return len; |
62 | | - } |
63 | | - const ssize_t r = m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(-1, len); |
64 | | - if (r == -1) { |
65 | | - SetFuzzedErrNo(m_fuzzed_data_provider, send_errnos); |
66 | | - } |
67 | | - return r; |
68 | | -} |
69 | | - |
70 | | -ssize_t FuzzedSock::Recv(void* buf, size_t len, int flags) const |
71 | | -{ |
72 | | - // Have a permanent error at recv_errnos[0] because when the fuzzed data is exhausted |
73 | | - // SetFuzzedErrNo() will always return the first element and we want to avoid Recv() |
74 | | - // returning -1 and setting errno to EAGAIN repeatedly. |
75 | | - constexpr std::array recv_errnos{ |
76 | | - ECONNREFUSED, |
77 | | - EAGAIN, |
78 | | - EBADF, |
79 | | - EFAULT, |
80 | | - EINTR, |
81 | | - EINVAL, |
82 | | - ENOMEM, |
83 | | - ENOTCONN, |
84 | | - ENOTSOCK, |
85 | | - EWOULDBLOCK, |
86 | | - }; |
87 | | - assert(buf != nullptr || len == 0); |
88 | | - if (len == 0 || m_fuzzed_data_provider.ConsumeBool()) { |
89 | | - const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; |
90 | | - if (r == -1) { |
91 | | - SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); |
92 | | - } |
93 | | - return r; |
94 | | - } |
95 | | - std::vector<uint8_t> random_bytes; |
96 | | - bool pad_to_len_bytes{m_fuzzed_data_provider.ConsumeBool()}; |
97 | | - if (m_peek_data.has_value()) { |
98 | | - // `MSG_PEEK` was used in the preceding `Recv()` call, return `m_peek_data`. |
99 | | - random_bytes.assign({m_peek_data.value()}); |
100 | | - if ((flags & MSG_PEEK) == 0) { |
101 | | - m_peek_data.reset(); |
102 | | - } |
103 | | - pad_to_len_bytes = false; |
104 | | - } else if ((flags & MSG_PEEK) != 0) { |
105 | | - // New call with `MSG_PEEK`. |
106 | | - random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>(1); |
107 | | - if (!random_bytes.empty()) { |
108 | | - m_peek_data = random_bytes[0]; |
109 | | - pad_to_len_bytes = false; |
110 | | - } |
111 | | - } else { |
112 | | - random_bytes = m_fuzzed_data_provider.ConsumeBytes<uint8_t>( |
113 | | - m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, len)); |
114 | | - } |
115 | | - if (random_bytes.empty()) { |
116 | | - const ssize_t r = m_fuzzed_data_provider.ConsumeBool() ? 0 : -1; |
117 | | - if (r == -1) { |
118 | | - SetFuzzedErrNo(m_fuzzed_data_provider, recv_errnos); |
119 | | - } |
120 | | - return r; |
121 | | - } |
122 | | - std::memcpy(buf, random_bytes.data(), random_bytes.size()); |
123 | | - if (pad_to_len_bytes) { |
124 | | - if (len > random_bytes.size()) { |
125 | | - std::memset((char*)buf + random_bytes.size(), 0, len - random_bytes.size()); |
126 | | - } |
127 | | - return len; |
128 | | - } |
129 | | - if (m_fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) { |
130 | | - std::this_thread::sleep_for(std::chrono::milliseconds{2}); |
131 | | - } |
132 | | - return random_bytes.size(); |
133 | | -} |
134 | | - |
135 | | -int FuzzedSock::Connect(const sockaddr*, socklen_t) const |
136 | | -{ |
137 | | - // Have a permanent error at connect_errnos[0] because when the fuzzed data is exhausted |
138 | | - // SetFuzzedErrNo() will always return the first element and we want to avoid Connect() |
139 | | - // returning -1 and setting errno to EAGAIN repeatedly. |
140 | | - constexpr std::array connect_errnos{ |
141 | | - ECONNREFUSED, |
142 | | - EAGAIN, |
143 | | - ECONNRESET, |
144 | | - EHOSTUNREACH, |
145 | | - EINPROGRESS, |
146 | | - EINTR, |
147 | | - ENETUNREACH, |
148 | | - ETIMEDOUT, |
149 | | - }; |
150 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
151 | | - SetFuzzedErrNo(m_fuzzed_data_provider, connect_errnos); |
152 | | - return -1; |
153 | | - } |
154 | | - return 0; |
155 | | -} |
156 | | - |
157 | | -int FuzzedSock::Bind(const sockaddr*, socklen_t) const |
158 | | -{ |
159 | | - // Have a permanent error at bind_errnos[0] because when the fuzzed data is exhausted |
160 | | - // SetFuzzedErrNo() will always set the global errno to bind_errnos[0]. We want to |
161 | | - // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN) |
162 | | - // repeatedly because proper code should retry on temporary errors, leading to an |
163 | | - // infinite loop. |
164 | | - constexpr std::array bind_errnos{ |
165 | | - EACCES, |
166 | | - EADDRINUSE, |
167 | | - EADDRNOTAVAIL, |
168 | | - EAGAIN, |
169 | | - }; |
170 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
171 | | - SetFuzzedErrNo(m_fuzzed_data_provider, bind_errnos); |
172 | | - return -1; |
173 | | - } |
174 | | - return 0; |
175 | | -} |
176 | | - |
177 | | -int FuzzedSock::Listen(int) const |
178 | | -{ |
179 | | - // Have a permanent error at listen_errnos[0] because when the fuzzed data is exhausted |
180 | | - // SetFuzzedErrNo() will always set the global errno to listen_errnos[0]. We want to |
181 | | - // avoid this method returning -1 and setting errno to a temporary error (like EAGAIN) |
182 | | - // repeatedly because proper code should retry on temporary errors, leading to an |
183 | | - // infinite loop. |
184 | | - constexpr std::array listen_errnos{ |
185 | | - EADDRINUSE, |
186 | | - EINVAL, |
187 | | - EOPNOTSUPP, |
188 | | - }; |
189 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
190 | | - SetFuzzedErrNo(m_fuzzed_data_provider, listen_errnos); |
191 | | - return -1; |
192 | | - } |
193 | | - return 0; |
194 | | -} |
195 | | - |
196 | | -std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const |
197 | | -{ |
198 | | - constexpr std::array accept_errnos{ |
199 | | - ECONNABORTED, |
200 | | - EINTR, |
201 | | - ENOMEM, |
202 | | - }; |
203 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
204 | | - SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos); |
205 | | - return std::unique_ptr<FuzzedSock>(); |
206 | | - } |
207 | | - return std::make_unique<FuzzedSock>(m_fuzzed_data_provider); |
208 | | -} |
209 | | - |
210 | | -int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const |
211 | | -{ |
212 | | - constexpr std::array getsockopt_errnos{ |
213 | | - ENOMEM, |
214 | | - ENOBUFS, |
215 | | - }; |
216 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
217 | | - SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos); |
218 | | - return -1; |
219 | | - } |
220 | | - if (opt_val == nullptr) { |
221 | | - return 0; |
222 | | - } |
223 | | - std::memcpy(opt_val, |
224 | | - ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(), |
225 | | - *opt_len); |
226 | | - return 0; |
227 | | -} |
228 | | - |
229 | | -int FuzzedSock::SetSockOpt(int, int, const void*, socklen_t) const |
230 | | -{ |
231 | | - constexpr std::array setsockopt_errnos{ |
232 | | - ENOMEM, |
233 | | - ENOBUFS, |
234 | | - }; |
235 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
236 | | - SetFuzzedErrNo(m_fuzzed_data_provider, setsockopt_errnos); |
237 | | - return -1; |
238 | | - } |
239 | | - return 0; |
240 | | -} |
241 | | - |
242 | | -int FuzzedSock::GetSockName(sockaddr* name, socklen_t* name_len) const |
243 | | -{ |
244 | | - constexpr std::array getsockname_errnos{ |
245 | | - ECONNRESET, |
246 | | - ENOBUFS, |
247 | | - }; |
248 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
249 | | - SetFuzzedErrNo(m_fuzzed_data_provider, getsockname_errnos); |
250 | | - return -1; |
251 | | - } |
252 | | - *name_len = m_fuzzed_data_provider.ConsumeData(name, *name_len); |
253 | | - return 0; |
254 | | -} |
255 | | - |
256 | | -bool FuzzedSock::SetNonBlocking() const |
257 | | -{ |
258 | | - constexpr std::array setnonblocking_errnos{ |
259 | | - EBADF, |
260 | | - EPERM, |
261 | | - }; |
262 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
263 | | - SetFuzzedErrNo(m_fuzzed_data_provider, setnonblocking_errnos); |
264 | | - return false; |
265 | | - } |
266 | | - return true; |
267 | | -} |
268 | | - |
269 | | -bool FuzzedSock::IsSelectable(bool is_select) const |
270 | | -{ |
271 | | - return m_selectable; |
272 | | -} |
273 | | - |
274 | | -bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, SocketEventsParams event_params, Event* occurred) const |
275 | | -{ |
276 | | - constexpr std::array wait_errnos{ |
277 | | - EBADF, |
278 | | - EINTR, |
279 | | - EINVAL, |
280 | | - }; |
281 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
282 | | - SetFuzzedErrNo(m_fuzzed_data_provider, wait_errnos); |
283 | | - return false; |
284 | | - } |
285 | | - if (occurred != nullptr) { |
286 | | - *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0; |
287 | | - } |
288 | | - return true; |
289 | | -} |
290 | | - |
291 | | -bool FuzzedSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock, SocketEventsParams event_params) const |
292 | | -{ |
293 | | - for (auto& [sock, events] : events_per_sock) { |
294 | | - (void)sock; |
295 | | - events.occurred = m_fuzzed_data_provider.ConsumeBool() ? events.requested : 0; |
296 | | - } |
297 | | - return true; |
298 | | -} |
299 | | - |
300 | | -bool FuzzedSock::IsConnected(std::string& errmsg) const |
301 | | -{ |
302 | | - if (m_fuzzed_data_provider.ConsumeBool()) { |
303 | | - return true; |
304 | | - } |
305 | | - errmsg = "disconnected at random by the fuzzer"; |
306 | | - return false; |
307 | | -} |
308 | | - |
309 | | -void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman, CNode& node) noexcept |
310 | | -{ |
311 | | - connman.Handshake(node, |
312 | | - /*successfully_connected=*/fuzzed_data_provider.ConsumeBool(), |
313 | | - /*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), |
314 | | - /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), |
315 | | - /*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()), |
316 | | - /*relay_txs=*/fuzzed_data_provider.ConsumeBool()); |
317 | | -} |
318 | | - |
319 | 16 | CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::optional<CAmount>& max) noexcept |
320 | 17 | { |
321 | 18 | return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, max.value_or(MAX_MONEY)); |
@@ -491,11 +188,6 @@ bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) n |
491 | 188 | return false; |
492 | 189 | } |
493 | 190 |
|
494 | | -CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept |
495 | | -{ |
496 | | - return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}}; |
497 | | -} |
498 | | - |
499 | 191 | FILE* FuzzedFileProvider::open() |
500 | 192 | { |
501 | 193 | SetFuzzedErrNo(m_fuzzed_data_provider); |
|
0 commit comments