Branch data Line data Source code
1 : : // Copyright (c) 2021-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 <consensus/amount.h>
6 : : #include <pubkey.h>
7 : : #include <test/fuzz/util.h>
8 : : #include <test/util/script.h>
9 : : #include <util/check.h>
10 : : #include <util/overflow.h>
11 [ + - ]: 173 : #include <util/rbf.h>
12 [ + - ]: 173 : #include <util/time.h>
13 : 173 : #include <version.h>
14 [ + - ]: 173 :
15 [ + - + - : 173 : #include <memory>
+ - ]
16 : :
17 : 755733 : std::vector<uint8_t> ConstructPubKeyBytes(FuzzedDataProvider& fuzzed_data_provider, Span<const uint8_t> byte_data, const bool compressed) noexcept
18 : : {
19 : : uint8_t pk_type;
20 [ + + ]: 755733 : if (compressed) {
21 [ + - ]: 653842 : pk_type = fuzzed_data_provider.PickValueInArray({0x02, 0x03});
22 : 653842 : } else {
23 [ + - ]: 101891 : pk_type = fuzzed_data_provider.PickValueInArray({0x04, 0x06, 0x07});
24 : : }
25 [ + - ]: 755733 : std::vector<uint8_t> pk_data{byte_data.begin(), byte_data.begin() + (compressed ? CPubKey::COMPRESSED_SIZE : CPubKey::SIZE)};
26 : 755733 : pk_data[0] = pk_type;
27 : 755733 : return pk_data;
28 [ + - ]: 755733 : }
29 : :
30 : 331756 : CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::optional<CAmount>& max) noexcept
31 : : {
32 [ + - + - ]: 331756 : return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, max.value_or(MAX_MONEY));
33 : : }
34 : :
35 : 1439943 : int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min, const std::optional<int64_t>& max) noexcept
36 : : {
37 : : // Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) disables mocktime.
38 : : static const int64_t time_min{946684801}; // 2000-01-01T00:00:01Z
39 : : static const int64_t time_max{4133980799}; // 2100-12-31T23:59:59Z
40 [ + - + - : 1439943 : return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(min.value_or(time_min), max.value_or(time_max));
+ - ]
41 : : }
42 : :
43 : 101267 : 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
44 : : {
45 [ + - ]: 101267 : CMutableTransaction tx_mut;
46 [ + - ]: 101267 : const auto p2wsh_op_true = fuzzed_data_provider.ConsumeBool();
47 [ + - + + ]: 109750 : tx_mut.nVersion = fuzzed_data_provider.ConsumeBool() ?
48 : : CTransaction::CURRENT_VERSION :
49 [ + - ]: 8483 : fuzzed_data_provider.ConsumeIntegral<int32_t>();
50 [ + - ]: 101267 : tx_mut.nLockTime = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
51 [ + - ]: 101267 : const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_in);
52 [ + - ]: 101267 : const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, max_num_out);
53 [ + + ]: 246806 : for (int i = 0; i < num_in; ++i) {
54 [ + - ]: 291078 : const auto& txid_prev = prevout_txids ?
55 [ + - + - ]: 145539 : PickValue(fuzzed_data_provider, *prevout_txids) :
56 : 0 : ConsumeUInt256(fuzzed_data_provider);
57 [ + - ]: 145539 : const auto index_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, max_num_out);
58 : 145539 : const auto sequence = ConsumeSequence(fuzzed_data_provider);
59 [ + + + - ]: 145539 : const auto script_sig = p2wsh_op_true ? CScript{} : ConsumeScript(fuzzed_data_provider);
60 [ + - ]: 145539 : CScriptWitness script_wit;
61 [ + + ]: 145539 : if (p2wsh_op_true) {
62 [ + - + - ]: 135750 : script_wit.stack = std::vector<std::vector<uint8_t>>{WITNESS_STACK_ELEM_OP_TRUE};
63 : 135750 : } else {
64 : 9789 : script_wit = ConsumeScriptWitness(fuzzed_data_provider);
65 : : }
66 [ + - ]: 145539 : CTxIn in;
67 [ + - ]: 145539 : in.prevout = COutPoint{txid_prev, index_out};
68 : 145539 : in.nSequence = sequence;
69 [ + - ]: 145539 : in.scriptSig = script_sig;
70 [ + - ]: 145539 : in.scriptWitness = script_wit;
71 : :
72 [ + - ]: 145539 : tx_mut.vin.push_back(in);
73 : 145539 : }
74 [ + + ]: 268022 : for (int i = 0; i < num_out; ++i) {
75 [ + - ]: 166755 : const auto amount = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-10, 50 * COIN + 10);
76 [ + + ]: 320214 : const auto script_pk = p2wsh_op_true ?
77 [ + - ]: 153459 : P2WSH_OP_TRUE :
78 : 13296 : ConsumeScript(fuzzed_data_provider, /*maybe_p2wsh=*/true);
79 [ + - ]: 166755 : tx_mut.vout.emplace_back(amount, script_pk);
80 : 166755 : }
81 : 101267 : return tx_mut;
82 [ + - ]: 101267 : }
83 : :
84 : 9789 : CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size) noexcept
85 : : {
86 [ + - ]: 9789 : CScriptWitness ret;
87 [ + - ]: 9789 : const auto n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_stack_elem_size);
88 [ + + ]: 29302 : for (size_t i = 0; i < n_elements; ++i) {
89 [ + - ]: 19513 : ret.stack.push_back(ConsumeRandomLengthByteVector(fuzzed_data_provider));
90 : 19513 : }
91 : 9789 : return ret;
92 [ + - ]: 9789 : }
93 : :
94 : 1200496 : CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const bool maybe_p2wsh) noexcept
95 : : {
96 [ + - ]: 1200496 : CScript r_script{};
97 : : {
98 : : // Keep a buffer of bytes to allow the fuzz engine to produce smaller
99 : : // inputs to generate CScripts with repeated data.
100 : : static constexpr unsigned MAX_BUFFER_SZ{128};
101 [ + - ]: 1200496 : std::vector<uint8_t> buffer(MAX_BUFFER_SZ, uint8_t{'a'});
102 [ + - + + ]: 17348448 : while (fuzzed_data_provider.ConsumeBool()) {
103 [ + - ]: 16147952 : CallOneOf(
104 : 16147952 : fuzzed_data_provider,
105 : 22156239 : [&] {
106 : : // Insert byte vector directly to allow malformed or unparsable scripts
107 : 6008287 : r_script.insert(r_script.end(), buffer.begin(), buffer.begin() + fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BUFFER_SZ));
108 : 6008287 : },
109 : 25722377 : [&] {
110 : : // Push a byte vector from the buffer
111 [ + - - + ]: 9574425 : r_script << std::vector<uint8_t>{buffer.begin(), buffer.begin() + fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BUFFER_SZ)};
112 : 9574425 : },
113 : 16214698 : [&] {
114 : : // Push multisig
115 : : // There is a special case for this to aid the fuzz engine
116 : : // navigate the highly structured multisig format.
117 : 66746 : r_script << fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 22);
118 : 66746 : int num_data{fuzzed_data_provider.ConsumeIntegralInRange(1, 22)};
119 [ + + ]: 822342 : while (num_data--) {
120 : 755596 : auto pubkey_bytes{ConstructPubKeyBytes(fuzzed_data_provider, buffer, fuzzed_data_provider.ConsumeBool())};
121 [ + - + + ]: 755596 : if (fuzzed_data_provider.ConsumeBool()) {
122 : 653818 : pubkey_bytes.back() = num_data; // Make each pubkey different
123 : 653818 : }
124 [ + - ]: 755596 : r_script << pubkey_bytes;
125 : 755596 : }
126 : 66746 : r_script << fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 22);
127 : 66746 : },
128 : 16238774 : [&] {
129 : : // Mutate the buffer
130 : 90822 : const auto vec{ConsumeRandomLengthByteVector(fuzzed_data_provider, /*max_length=*/MAX_BUFFER_SZ)};
131 [ + - ]: 90822 : std::copy(vec.begin(), vec.end(), buffer.begin());
132 : 90822 : },
133 : 16323599 : [&] {
134 : : // Push an integral
135 : 175647 : r_script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
136 : 175647 : },
137 : 16329338 : [&] {
138 : : // Push an opcode
139 : 181386 : r_script << ConsumeOpcodeType(fuzzed_data_provider);
140 : 181386 : },
141 : 16198591 : [&] {
142 : : // Push a scriptnum
143 : 50639 : r_script << ConsumeScriptNum(fuzzed_data_provider);
144 : 50639 : });
145 : : }
146 : 1200496 : }
147 [ + + + - : 1200496 : if (maybe_p2wsh && fuzzed_data_provider.ConsumeBool()) {
+ + ]
148 [ + - ]: 4024 : uint256 script_hash;
149 [ + - + - : 4024 : CSHA256().Write(r_script.data(), r_script.size()).Finalize(script_hash.begin());
+ - + - +
- + - ]
150 [ + - ]: 4024 : r_script.clear();
151 [ + - + - : 4024 : r_script << OP_0 << ToByteVector(script_hash);
+ - ]
152 : 4024 : }
153 : 1200496 : return r_script;
154 [ + - ]: 1200496 : }
155 : :
156 : 4853545 : uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept
157 : : {
158 [ + - + + ]: 9707090 : return fuzzed_data_provider.ConsumeBool() ?
159 [ + - ]: 1932369 : fuzzed_data_provider.PickValueInArray({
160 : : CTxIn::SEQUENCE_FINAL,
161 : : CTxIn::MAX_SEQUENCE_NONFINAL,
162 : : MAX_BIP125_RBF_SEQUENCE,
163 : : }) :
164 [ + - ]: 2921176 : fuzzed_data_provider.ConsumeIntegral<uint32_t>();
165 : : }
166 : :
167 : 3390 : CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept
168 : : {
169 [ + - ]: 3390 : CTxDestination tx_destination;
170 [ + - ]: 3390 : const size_t call_size{CallOneOf(
171 : 3390 : fuzzed_data_provider,
172 : 4461 : [&] {
173 : 1071 : tx_destination = CNoDestination{};
174 : 1071 : },
175 : 3527 : [&] {
176 : 137 : bool compressed = fuzzed_data_provider.ConsumeBool();
177 [ + - + - ]: 137 : CPubKey pk{ConstructPubKeyBytes(
178 : 137 : fuzzed_data_provider,
179 [ + - ]: 137 : ConsumeFixedLengthByteVector(fuzzed_data_provider, (compressed ? CPubKey::COMPRESSED_SIZE : CPubKey::SIZE)),
180 : 137 : compressed
181 : : )};
182 : 137 : tx_destination = PubKeyDestination{pk};
183 : 137 : },
184 : 3441 : [&] {
185 : 51 : tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)};
186 : 51 : },
187 : 3428 : [&] {
188 : 38 : tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)};
189 : 38 : },
190 : 4690 : [&] {
191 : 1300 : tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)};
192 : 1300 : },
193 : 3556 : [&] {
194 : 166 : tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)};
195 : 166 : },
196 : 3455 : [&] {
197 : 65 : tx_destination = WitnessV1Taproot{XOnlyPubKey{ConsumeUInt256(fuzzed_data_provider)}};
198 : 65 : },
199 : 3952 : [&] {
200 : 562 : std::vector<unsigned char> program{ConsumeRandomLengthByteVector(fuzzed_data_provider, /*max_length=*/40)};
201 [ + + ]: 562 : if (program.size() < 2) {
202 [ + - ]: 85 : program = {0, 0};
203 : 85 : }
204 [ + - ]: 562 : tx_destination = WitnessUnknown{fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(2, 16), program};
205 : 562 : })};
206 [ + - ]: 3390 : Assert(call_size == std::variant_size_v<CTxDestination>);
207 : 3390 : return tx_destination;
208 [ + - ]: 3390 : }
209 : :
210 : 11960 : CKey ConsumePrivateKey(FuzzedDataProvider& fuzzed_data_provider, std::optional<bool> compressed) noexcept
211 : : {
212 [ + - ]: 11960 : auto key_data = fuzzed_data_provider.ConsumeBytes<uint8_t>(32);
213 [ + - ]: 11960 : key_data.resize(32);
214 : 11960 : CKey key;
215 [ + + + - : 11960 : bool compressed_value = compressed ? *compressed : fuzzed_data_provider.ConsumeBool();
+ - ]
216 [ + - ]: 11960 : key.Set(key_data.begin(), key_data.end(), compressed_value);
217 : 11960 : return key;
218 [ + - ]: 11960 : }
219 : :
220 : 241 : bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept
221 : : {
222 [ + + ]: 1167 : for (const CTxIn& tx_in : tx.vin) {
223 [ + - ]: 973 : const Coin& coin = inputs.AccessCoin(tx_in.prevout);
224 [ + - + + ]: 973 : if (coin.IsSpent()) {
225 : 47 : return true;
226 : : }
227 : : }
228 : 194 : return false;
229 : 241 : }
230 : :
231 : 2787 : FILE* FuzzedFileProvider::open()
232 : : {
233 : 2787 : SetFuzzedErrNo(m_fuzzed_data_provider);
234 [ + + ]: 2787 : if (m_fuzzed_data_provider.ConsumeBool()) {
235 : 133 : return nullptr;
236 : : }
237 : 2654 : std::string mode;
238 [ + - ]: 2654 : CallOneOf(
239 : 2654 : m_fuzzed_data_provider,
240 : 4842 : [&] {
241 : 2188 : mode = "r";
242 : 2188 : },
243 : 2811 : [&] {
244 : 157 : mode = "r+";
245 : 157 : },
246 : 2693 : [&] {
247 : 39 : mode = "w";
248 : 39 : },
249 : 2773 : [&] {
250 : 119 : mode = "w+";
251 : 119 : },
252 : 2714 : [&] {
253 : 60 : mode = "a";
254 : 60 : },
255 : 2745 : [&] {
256 : 91 : mode = "a+";
257 : 91 : });
258 : : #if defined _GNU_SOURCE && !defined __ANDROID__
259 : 2654 : const cookie_io_functions_t io_hooks = {
260 : : FuzzedFileProvider::read,
261 : : FuzzedFileProvider::write,
262 : : FuzzedFileProvider::seek,
263 : : FuzzedFileProvider::close,
264 : : };
265 : 2654 : return fopencookie(this, mode.c_str(), io_hooks);
266 : : #else
267 : : (void)mode;
268 : : return nullptr;
269 : : #endif
270 : 2787 : }
271 : :
272 : 15822 : ssize_t FuzzedFileProvider::read(void* cookie, char* buf, size_t size)
273 : : {
274 : 15822 : FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
275 : 15822 : SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
276 [ + - + - : 15822 : if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
+ + ]
277 : 3029 : return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
278 : : }
279 : 12793 : const std::vector<uint8_t> random_bytes = fuzzed_file->m_fuzzed_data_provider.ConsumeBytes<uint8_t>(size);
280 [ + + ]: 12793 : if (random_bytes.empty()) {
281 : 1323 : return 0;
282 : : }
283 : 11470 : std::memcpy(buf, random_bytes.data(), random_bytes.size());
284 [ - + ]: 11470 : if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)random_bytes.size())) {
285 [ # # ]: 0 : return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
286 : : }
287 : 11470 : fuzzed_file->m_offset += random_bytes.size();
288 : 11470 : return random_bytes.size();
289 : 15822 : }
290 : :
291 : 2754 : ssize_t FuzzedFileProvider::write(void* cookie, const char* buf, size_t size)
292 : : {
293 : 2754 : FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
294 : 2754 : SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
295 : 2754 : const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
296 [ - + ]: 2754 : if (AdditionOverflow(fuzzed_file->m_offset, (int64_t)n)) {
297 : 0 : return 0;
298 : : }
299 : 2754 : fuzzed_file->m_offset += n;
300 : 2754 : return n;
301 : 2754 : }
302 : :
303 : 836 : int FuzzedFileProvider::seek(void* cookie, int64_t* offset, int whence)
304 : : {
305 [ + - + - : 836 : assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
+ - ]
306 : 836 : FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
307 : 836 : SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
308 : 836 : int64_t new_offset = 0;
309 [ + - ]: 836 : if (whence == SEEK_SET) {
310 : 0 : new_offset = *offset;
311 [ + - ]: 836 : } else if (whence == SEEK_CUR) {
312 [ - + ]: 836 : if (AdditionOverflow(fuzzed_file->m_offset, *offset)) {
313 : 0 : return -1;
314 : : }
315 : 836 : new_offset = fuzzed_file->m_offset + *offset;
316 [ # # ]: 836 : } else if (whence == SEEK_END) {
317 : 0 : const int64_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 4096);
318 [ # # ]: 0 : if (AdditionOverflow(n, *offset)) {
319 : 0 : return -1;
320 : : }
321 : 0 : new_offset = n + *offset;
322 : 0 : }
323 [ + + ]: 836 : if (new_offset < 0) {
324 : 233 : return -1;
325 : : }
326 : 603 : fuzzed_file->m_offset = new_offset;
327 : 603 : *offset = new_offset;
328 : 603 : return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
329 : 836 : }
330 : :
331 : 2654 : int FuzzedFileProvider::close(void* cookie)
332 : : {
333 : 2654 : FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
334 : 2654 : SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
335 : 2654 : return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
336 : : }
|