Skip to content

Commit 4ea7c90

Browse files
committed
merge bitcoin#23408: Rework ConsumeScript
1 parent b8af7ea commit 4ea7c90

File tree

4 files changed

+69
-11
lines changed

4 files changed

+69
-11
lines changed

src/test/fuzz/script.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ void initialize_script()
3636
FUZZ_TARGET_INIT(script, initialize_script)
3737
{
3838
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
39-
const std::optional<CScript> script_opt = ConsumeDeserializable<CScript>(fuzzed_data_provider);
40-
if (!script_opt) return;
41-
const CScript script{*script_opt};
39+
const CScript script{ConsumeScript(fuzzed_data_provider)};
4240

4341
CompressedScript compressed;
4442
if (CompressScript(script, compressed)) {

src/test/fuzz/signature_checker.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ FUZZ_TARGET(signature_checker)
4747
{
4848
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
4949
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
50-
const auto script_1 = ConsumeScript(fuzzed_data_provider, 65536);
51-
const auto script_2 = ConsumeScript(fuzzed_data_provider, 65536);
50+
const auto script_1{ConsumeScript(fuzzed_data_provider)};
51+
const auto script_2{ConsumeScript(fuzzed_data_provider)};
5252
std::vector<std::vector<unsigned char>> stack;
5353
(void)EvalScript(stack, script_1, flags, FuzzedSignatureChecker(fuzzed_data_provider), SigVersion::BASE, nullptr);
5454
if (!IsValidFlagCombination(flags)) {

src/test/fuzz/util.cpp

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -349,16 +349,76 @@ CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider,
349349
}
350350
for (int i = 0; i < num_out; ++i) {
351351
const auto amount = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-10, 50 * COIN + 10);
352-
const auto script_pk = ConsumeScript(fuzzed_data_provider, /* max_length */ 128);
352+
const auto script_pk = ConsumeScript(fuzzed_data_provider);
353353
tx_mut.vout.emplace_back(amount, script_pk);
354354
}
355355
return tx_mut;
356356
}
357357

358-
CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length) noexcept
359-
{
360-
const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
361-
return {b.begin(), b.end()};
358+
CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept
359+
{
360+
CScript r_script{};
361+
{
362+
// Keep a buffer of bytes to allow the fuzz engine to produce smaller
363+
// inputs to generate CScripts with repeated data.
364+
static constexpr unsigned MAX_BUFFER_SZ{128};
365+
std::vector<uint8_t> buffer(MAX_BUFFER_SZ, uint8_t{'a'});
366+
while (fuzzed_data_provider.ConsumeBool()) {
367+
CallOneOf(
368+
fuzzed_data_provider,
369+
[&] {
370+
// Insert byte vector directly to allow malformed or unparsable scripts
371+
r_script.insert(r_script.end(), buffer.begin(), buffer.begin() + fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BUFFER_SZ));
372+
},
373+
[&] {
374+
// Push a byte vector from the buffer
375+
r_script << std::vector<uint8_t>{buffer.begin(), buffer.begin() + fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BUFFER_SZ)};
376+
},
377+
[&] {
378+
// Push multisig
379+
// There is a special case for this to aid the fuzz engine
380+
// navigate the highly structured multisig format.
381+
r_script << fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 22);
382+
int num_data{fuzzed_data_provider.ConsumeIntegralInRange(1, 22)};
383+
std::vector<uint8_t> pubkey_comp{buffer.begin(), buffer.begin() + CPubKey::COMPRESSED_SIZE};
384+
pubkey_comp.front() = fuzzed_data_provider.ConsumeIntegralInRange(2, 3); // Set first byte for GetLen() to pass
385+
std::vector<uint8_t> pubkey_uncomp{buffer.begin(), buffer.begin() + CPubKey::SIZE};
386+
pubkey_uncomp.front() = fuzzed_data_provider.ConsumeIntegralInRange(4, 7); // Set first byte for GetLen() to pass
387+
while (num_data--) {
388+
auto& pubkey{fuzzed_data_provider.ConsumeBool() ? pubkey_uncomp : pubkey_comp};
389+
if (fuzzed_data_provider.ConsumeBool()) {
390+
pubkey.back() = num_data; // Make each pubkey different
391+
}
392+
r_script << pubkey;
393+
}
394+
r_script << fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 22);
395+
},
396+
[&] {
397+
// Mutate the buffer
398+
const auto vec{ConsumeRandomLengthByteVector(fuzzed_data_provider, /*max_length=*/MAX_BUFFER_SZ)};
399+
std::copy(vec.begin(), vec.end(), buffer.begin());
400+
},
401+
[&] {
402+
// Push an integral
403+
r_script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
404+
},
405+
[&] {
406+
// Push an opcode
407+
r_script << ConsumeOpcodeType(fuzzed_data_provider);
408+
},
409+
[&] {
410+
// Push a scriptnum
411+
r_script << ConsumeScriptNum(fuzzed_data_provider);
412+
});
413+
}
414+
}
415+
if (fuzzed_data_provider.ConsumeBool()) {
416+
uint256 script_hash;
417+
CSHA256().Write(r_script.data(), r_script.size()).Finalize(script_hash.begin());
418+
r_script.clear();
419+
r_script << OP_0 << ToByteVector(script_hash);
420+
}
421+
return r_script;
362422
}
363423

364424
uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept

src/test/fuzz/util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ template <typename WeakEnumType, size_t size>
198198

199199
[[nodiscard]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept;
200200

201-
[[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept;
201+
[[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept;
202202

203203
[[nodiscard]] uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept;
204204

0 commit comments

Comments
 (0)