1 // Copyright (c) 2021 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 <pubkey.h>
6 #include <test/fuzz/util.h>
7 #include <test/util/script.h>
8 #include <util/rbf.h>
9 #include <util/time.h>
10 #include <version.h>
11 
FuzzedSock(FuzzedDataProvider & fuzzed_data_provider)12 FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider)
13     : m_fuzzed_data_provider{fuzzed_data_provider}
14 {
15     m_socket = fuzzed_data_provider.ConsumeIntegralInRange<SOCKET>(INVALID_SOCKET - 1, INVALID_SOCKET);
16 }
17 
~FuzzedSock()18 FuzzedSock::~FuzzedSock()
19 {
20     // Sock::~Sock() will be called after FuzzedSock::~FuzzedSock() and it will call
21     // Sock::Reset() (not FuzzedSock::Reset()!) which will call CloseSocket(m_socket).
22     // Avoid closing an arbitrary file descriptor (m_socket is just a random very high number which
23     // theoretically may concide with a real opened file descriptor).
24     Reset();
25 }
26 
operator =(Sock && other)27 FuzzedSock& FuzzedSock::operator=(Sock&& other)
28 {
29     assert(false && "Move of Sock into FuzzedSock not allowed.");
30     return *this;
31 }
32 
Reset()33 void FuzzedSock::Reset()
34 {
35     m_socket = INVALID_SOCKET;
36 }
37 
Send(const void * data,size_t len,int flags) const38 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 
Recv(void * buf,size_t len,int flags) const70 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 
Connect(const sockaddr *,socklen_t) const135 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 
GetSockOpt(int level,int opt_name,void * opt_val,socklen_t * opt_len) const157 int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
158 {
159     constexpr std::array getsockopt_errnos{
160         ENOMEM,
161         ENOBUFS,
162     };
163     if (m_fuzzed_data_provider.ConsumeBool()) {
164         SetFuzzedErrNo(m_fuzzed_data_provider, getsockopt_errnos);
165         return -1;
166     }
167     if (opt_val == nullptr) {
168         return 0;
169     }
170     std::memcpy(opt_val,
171                 ConsumeFixedLengthByteVector(m_fuzzed_data_provider, *opt_len).data(),
172                 *opt_len);
173     return 0;
174 }
175 
Wait(std::chrono::milliseconds timeout,Event requested,Event * occurred) const176 bool FuzzedSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
177 {
178     constexpr std::array wait_errnos{
179         EBADF,
180         EINTR,
181         EINVAL,
182     };
183     if (m_fuzzed_data_provider.ConsumeBool()) {
184         SetFuzzedErrNo(m_fuzzed_data_provider, wait_errnos);
185         return false;
186     }
187     if (occurred != nullptr) {
188         *occurred = m_fuzzed_data_provider.ConsumeBool() ? requested : 0;
189     }
190     return true;
191 }
192 
IsConnected(std::string & errmsg) const193 bool FuzzedSock::IsConnected(std::string& errmsg) const
194 {
195     if (m_fuzzed_data_provider.ConsumeBool()) {
196         return true;
197     }
198     errmsg = "disconnected at random by the fuzzer";
199     return false;
200 }
201 
FillNode(FuzzedDataProvider & fuzzed_data_provider,CNode & node,bool init_version)202 void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept
203 {
204     const ServiceFlags remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
205     const NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
206     const int32_t version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
207     const bool filter_txs = fuzzed_data_provider.ConsumeBool();
208 
209     node.nServices = remote_services;
210     node.m_permissionFlags = permission_flags;
211     if (init_version) {
212         node.nVersion = version;
213         node.SetCommonVersion(std::min(version, PROTOCOL_VERSION));
214     }
215     if (node.m_tx_relay != nullptr) {
216         LOCK(node.m_tx_relay->cs_filter);
217         node.m_tx_relay->fRelayTxes = filter_txs;
218     }
219 }
220 
ConsumeMoney(FuzzedDataProvider & fuzzed_data_provider,const std::optional<CAmount> & max)221 CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::optional<CAmount>& max) noexcept
222 {
223     return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, max.value_or(MAX_MONEY));
224 }
225 
ConsumeTime(FuzzedDataProvider & fuzzed_data_provider,const std::optional<int64_t> & min,const std::optional<int64_t> & max)226 int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min, const std::optional<int64_t>& max) noexcept
227 {
228     // Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) disables mocktime.
229     static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z");
230     static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z");
231     return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(min.value_or(time_min), max.value_or(time_max));
232 }
233 
ConsumeTransaction(FuzzedDataProvider & fuzzed_data_provider,const std::optional<std::vector<uint256>> & prevout_txids,const int max_num_in,const int max_num_out)234 CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in, const int max_num_out) noexcept
235 {
236     CMutableTransaction tx_mut;
237     const auto p2wsh_op_true = fuzzed_data_provider.ConsumeBool();
238     tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ?
239                           CTransaction::CURRENT_VERSION :
240                           fuzzed_data_provider.ConsumeIntegral<int32_t>();
241     tx_mut.nLockTime = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
242     const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_in);
243     const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_out);
244     for (int i = 0; i < num_in; ++i) {
245         const auto& txid_prev = prevout_txids ?
246                                     PickValue(fuzzed_data_provider, *prevout_txids) :
247                                     ConsumeUInt256(fuzzed_data_provider);
248         const auto index_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, max_num_out);
249         const auto sequence = ConsumeSequence(fuzzed_data_provider);
250         const auto script_sig = p2wsh_op_true ? CScript{} : ConsumeScript(fuzzed_data_provider);
251         CScriptWitness script_wit;
252         if (p2wsh_op_true) {
253             script_wit.stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};
254         } else {
255             script_wit = ConsumeScriptWitness(fuzzed_data_provider);
256         }
257         CTxIn in;
258         in.prevout = COutPoint{txid_prev, index_out};
259         in.nSequence = sequence;
260         in.scriptSig = script_sig;
261         in.scriptWitness = script_wit;
262 
263         tx_mut.vin.push_back(in);
264     }
265     for (int i = 0; i < num_out; ++i) {
266         const auto amount = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-10, 50 * COIN + 10);
267         const auto script_pk = p2wsh_op_true ?
268                                    P2WSH_OP_TRUE :
269                                    ConsumeScript(fuzzed_data_provider, /* max_length */ 128, /* maybe_p2wsh */ true);
270         tx_mut.vout.emplace_back(amount, script_pk);
271     }
272     return tx_mut;
273 }
274 
ConsumeScriptWitness(FuzzedDataProvider & fuzzed_data_provider,const size_t max_stack_elem_size)275 CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size) noexcept
276 {
277     CScriptWitness ret;
278     const auto n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_stack_elem_size);
279     for (size_t i = 0; i < n_elements; ++i) {
280         ret.stack.push_back(ConsumeRandomLengthByteVector(fuzzed_data_provider));
281     }
282     return ret;
283 }
284 
ConsumeScript(FuzzedDataProvider & fuzzed_data_provider,const std::optional<size_t> & max_length,const bool maybe_p2wsh)285 CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length, const bool maybe_p2wsh) noexcept
286 {
287     const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
288     CScript r_script{b.begin(), b.end()};
289     if (maybe_p2wsh && fuzzed_data_provider.ConsumeBool()) {
290         uint256 script_hash;
291         CSHA256().Write(r_script.data(), r_script.size()).Finalize(script_hash.begin());
292         r_script.clear();
293         r_script << OP_0 << ToByteVector(script_hash);
294     }
295     return r_script;
296 }
297 
ConsumeSequence(FuzzedDataProvider & fuzzed_data_provider)298 uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept
299 {
300     return fuzzed_data_provider.ConsumeBool() ?
301                fuzzed_data_provider.PickValueInArray({
302                    CTxIn::SEQUENCE_FINAL,
303                    CTxIn::SEQUENCE_FINAL - 1,
304                    MAX_BIP125_RBF_SEQUENCE,
305                }) :
306                fuzzed_data_provider.ConsumeIntegral<uint32_t>();
307 }
308 
ConsumeTxDestination(FuzzedDataProvider & fuzzed_data_provider)309 CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept
310 {
311     CTxDestination tx_destination;
312     const size_t call_size{CallOneOf(
313         fuzzed_data_provider,
314         [&] {
315             tx_destination = CNoDestination{};
316         },
317         [&] {
318             tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)};
319         },
320         [&] {
321             tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)};
322         },
323         [&] {
324             tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)};
325         },
326         [&] {
327             tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)};
328         },
329         [&] {
330             tx_destination = WitnessV1Taproot{XOnlyPubKey{ConsumeUInt256(fuzzed_data_provider)}};
331         },
332         [&] {
333             WitnessUnknown witness_unknown{};
334             witness_unknown.version = fuzzed_data_provider.ConsumeIntegralInRange(2, 16);
335             std::vector<uint8_t> witness_unknown_program_1{fuzzed_data_provider.ConsumeBytes<uint8_t>(40)};
336             if (witness_unknown_program_1.size() < 2) {
337                 witness_unknown_program_1 = {0, 0};
338             }
339             witness_unknown.length = witness_unknown_program_1.size();
340             std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program);
341             tx_destination = witness_unknown;
342         })};
343     Assert(call_size == std::variant_size_v<CTxDestination>);
344     return tx_destination;
345 }
346 
ConsumeTxMemPoolEntry(FuzzedDataProvider & fuzzed_data_provider,const CTransaction & tx)347 CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
348 {
349     // Avoid:
350     // policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long'
351     //
352     // Reproduce using CFeeRate(348732081484775, 10).GetFeePerK()
353     const CAmount fee = std::min<CAmount>(ConsumeMoney(fuzzed_data_provider), std::numeric_limits<CAmount>::max() / static_cast<CAmount>(100000));
354     assert(MoneyRange(fee));
355     const int64_t time = fuzzed_data_provider.ConsumeIntegral<int64_t>();
356     const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
357     const bool spends_coinbase = fuzzed_data_provider.ConsumeBool();
358     const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, MAX_BLOCK_SIGOPS_COST);
359     return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}};
360 }
361 
ContainsSpentInput(const CTransaction & tx,const CCoinsViewCache & inputs)362 bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept
363 {
364     for (const CTxIn& tx_in : tx.vin) {
365         const Coin& coin = inputs.AccessCoin(tx_in.prevout);
366         if (coin.IsSpent()) {
367             return true;
368         }
369     }
370     return false;
371 }
372 
ConsumeNetAddr(FuzzedDataProvider & fuzzed_data_provider)373 CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
374 {
375     const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
376     CNetAddr net_addr;
377     if (network == Network::NET_IPV4) {
378         in_addr v4_addr = {};
379         v4_addr.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
380         net_addr = CNetAddr{v4_addr};
381     } else if (network == Network::NET_IPV6) {
382         if (fuzzed_data_provider.remaining_bytes() >= 16) {
383             in6_addr v6_addr = {};
384             memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16);
385             net_addr = CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
386         }
387     } else if (network == Network::NET_INTERNAL) {
388         net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32));
389     } else if (network == Network::NET_ONION) {
390         net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32));
391     }
392     return net_addr;
393 }
394 
open()395 FILE* FuzzedFileProvider::open()
396 {
397     SetFuzzedErrNo(m_fuzzed_data_provider);
398     if (m_fuzzed_data_provider.ConsumeBool()) {
399         return nullptr;
400     }
401     std::string mode;
402     CallOneOf(
403         m_fuzzed_data_provider,
404         [&] {
405             mode = "r";
406         },
407         [&] {
408             mode = "r+";
409         },
410         [&] {
411             mode = "w";
412         },
413         [&] {
414             mode = "w+";
415         },
416         [&] {
417             mode = "a";
418         },
419         [&] {
420             mode = "a+";
421         });
422 #if defined _GNU_SOURCE && !defined __ANDROID__
423     const cookie_io_functions_t io_hooks = {
424         FuzzedFileProvider::read,
425         FuzzedFileProvider::write,
426         FuzzedFileProvider::seek,
427         FuzzedFileProvider::close,
428     };
429     return fopencookie(this, mode.c_str(), io_hooks);
430 #else
431     (void)mode;
432     return nullptr;
433 #endif
434 }
435 
read(void * cookie,char * buf,size_t size)436 ssize_t FuzzedFileProvider::read(void* cookie, char* buf, size_t size)
437 {
438     FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
439     SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
440     if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
441         return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
442     }
443     const std::vector<uint8_t> random_bytes = fuzzed_file->m_fuzzed_data_provider.ConsumeBytes<uint8_t>(size);
444     if (random_bytes.empty()) {
445         return 0;
446     }
447     std::memcpy(buf, random_bytes.data(), random_bytes.size());
448     if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)random_bytes.size())) {
449         return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
450     }
451     fuzzed_file->m_offset += random_bytes.size();
452     return random_bytes.size();
453 }
454 
write(void * cookie,const char * buf,size_t size)455 ssize_t FuzzedFileProvider::write(void* cookie, const char* buf, size_t size)
456 {
457     FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
458     SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
459     const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
460     if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) {
461         return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
462     }
463     fuzzed_file->m_offset += n;
464     return n;
465 }
466 
seek(void * cookie,int64_t * offset,int whence)467 int FuzzedFileProvider::seek(void* cookie, int64_t* offset, int whence)
468 {
469     assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
470     FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
471     SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
472     int64_t new_offset = 0;
473     if (whence == SEEK_SET) {
474         new_offset = *offset;
475     } else if (whence == SEEK_CUR) {
476         if (AdditionOverflow(fuzzed_file->m_offset, *offset)) {
477             return -1;
478         }
479         new_offset = fuzzed_file->m_offset + *offset;
480     } else if (whence == SEEK_END) {
481         const int64_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 4096);
482         if (AdditionOverflow(n, *offset)) {
483             return -1;
484         }
485         new_offset = n + *offset;
486     }
487     if (new_offset < 0) {
488         return -1;
489     }
490     fuzzed_file->m_offset = new_offset;
491     *offset = new_offset;
492     return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
493 }
494 
close(void * cookie)495 int FuzzedFileProvider::close(void* cookie)
496 {
497     FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
498     SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
499     return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
500 }
501