DescriptorScriptPubKeyMan
. Also, moves MockedDescriptorConverter
to fuzz/util/descriptor
to be used here and in descriptor
target.
DescriptorScriptPubKeyMan
#28578
DescriptorScriptPubKeyMan
. Also, moves MockedDescriptorConverter
to fuzz/util/descriptor
to be used here and in descriptor
target.
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
For detailed information about the code coverage, see the test coverage report.
See the guideline for information on the review process.
Type | Reviewers |
---|---|
ACK | maflcko, dergoegge |
Concept ACK | Ayush170-Future |
If your review is incorrectly listed, please react with ๐ to this comment and the bot will ignore it on the next update.
No conflicts as of last run.
21+{
22+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN);
23+ g_setup = testing_setup.get();
24+}
25+
26+static std::string CreateDescriptorString(FuzzedDataProvider& fuzzed_data_provider)
MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)
?
MockedDescriptorConverter
to a util file and use it here.
0@@ -0,0 +1,138 @@
1+// Copyright (c) 2022 The Bitcoin Core developers
0// Copyright (c) 2023-present The Bitcoin Core developers
nit: Wrong year? Also, for new code could omit the years completely, or use -present
to avoid having to ever touch it again.
28+ MOCKED_DESC_CONVERTER.Init();
29+}
30+
31+static DescriptorScriptPubKeyMan* CreateDescriptor(FuzzedDataProvider& fuzzed_data_provider, CWallet& keystore)
32+{
33+ const auto random_bytes{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
fuzzed_data_provider.ConsumeRandomLengthString
directly
0$ echo "cGsoJTg0KVwzKVwAQWlwZTgzKVwAQQAAAAAAADmDg4ODg4ODg4ODgYODg4ODg4Nwa2hhe3t7g4ODg4ODg4OD" | base64 --decode > scriptpubkeyman.crash
1$ FUZZ=scriptpubkeyman ./src/test/fuzz/fuzz scriptpubkeyman.crash
2...
3Running: scriptpubkeyman.crash
4fuzz: wallet/test/fuzz/scriptpubkeyman.cpp:93: auto wallet::(anonymous namespace)::scriptpubkeyman_fuzz_target(FuzzBufferType)::(anonymous class)::operator()() const: Assertion `spk_manager->GetDescriptorString(descriptor, fuzzed_data_provider.ConsumeBool())' failed.
5==1391778== ERROR: libFuzzer: deadly signal
6...
assert
, we can’t ensure it.
0$ echo "cGsoJTQxLyopXDMAXABhZGRyKGJjMYMxMTAwMDIwMDAwMDBnJyw2ZGRyKGI1bikp" | base64 --decode > scriptpubkeyman2.crash
1$ FUZZ=scriptpubkeyman ./src/test/fuzz/fuzz scriptpubkeyman2.crash
2...
3fuzz: wallet/scriptpubkeyman.cpp:2008: virtual util::Result<CTxDestination> wallet::DescriptorScriptPubKeyMan::GetNewDestination(const OutputType): Assertion `desc_addr_type' failed.
4==1499877== ERROR: libFuzzer: deadly signal
5...
0$ echo "dHIoJTA1LyopXDQXFw==" | base64 --decode > scriptpubkeyman3.crash
1$ FUZZ=scriptpubkeyman ./src/test/fuzz/fuzz scriptpubkeyman3.crash
2...
3terminate called after throwing an instance of 'std::runtime_error'
4 what(): GetNewDestination: Types are inconsistent. Stored type does not match type of newly generated address
5...
I would recommend that you run the targets that you write for a while before opening a PR. It could very well be that it finds actual bugs that we don’t want to be public right away.
I would recommend that you run the targets that you write for a while before opening a PR. It could very well be that it finds actual bugs that we don’t want to be public right away.
Sure, sorry for that, left it running but not in my main machine so didn’t get some of them. Force-pushed with a fix for GetNewDestination
. We can’t fuzz it with random outputs types because any inconsistence will throw a runtime error. Any other one will return a util::Error
. Left it running for some hours before pushing and will continue running it overnight.
ACK
Reviewed the whole code. Looks great to me!
Here’s a coverage report: https://dergoegge.github.io/bitcoin-coverage/pr28578/fuzz.coverage/index.html (~1000h CPU time).
Is there a reason not to cover more of DescriptorScriptPubKeyMan
in this PR? e.g. DescriptorScriptPubKeyMan::SignTransaction
or DescriptorScriptPubKeyMan::FillPSBT
.
Is there a reason not to cover more of DescriptorScriptPubKeyMan in this PR? e.g. DescriptorScriptPubKeyMan::SignTransaction or DescriptorScriptPubKeyMan::FillPSBT.
Not exactly, perhaps one of them may be very slow, let me test more functions and then I can add them all here, np.
141+ },
142+ [&] {
143+ std::optional<PartiallySignedTransaction> opt_psbt{ConsumeDeserializable<PartiallySignedTransaction>(fuzzed_data_provider)};
144+ if (!opt_psbt) {
145+ return;
146+ }
30+
31+static std::optional<std::pair<WalletDescriptor, FlatSigningProvider>> CreateWalletDescriptor(FuzzedDataProvider& fuzzed_data_provider)
32+{
33+ const std::string mocked_descriptor{fuzzed_data_provider.ConsumeRandomLengthString()};
34+ const auto desc_str{MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)};
35+ if (!desc_str.has_value()) return std::nullopt;
0@@ -0,0 +1,47 @@
1+// Copyright (c) 2023-present 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+#ifndef BITCOIN_TEST_FUZZ_UTIL_DESCRIPTOR_H
6+#define BITCOIN_TEST_FUZZ_UTIL_DESCRIPTOR_H
7+
8+#include <functional>
std::
includes in a new section
52+
53+FUZZ_TARGET(scriptpubkeyman, .init = initialize_spkm)
54+{
55+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
56+ const auto& node{g_setup->m_node};
57+ Chainstate* chainstate = &node.chainman->ActiveChainstate();
0 Chainstate& chainstate = node.chainman->ActiveChainstate();
any reason to turn a reference into a pointer when you can keep the reference?
37+ FlatSigningProvider keys;
38+ std::string error;
39+ std::unique_ptr<Descriptor> parsed_desc{Parse(desc_str.value(), keys, error, false)};
40+ if (!parsed_desc) return std::nullopt;
41+
42+ WalletDescriptor w_desc{WalletDescriptor(std::move(parsed_desc), 0, 0, 1, 1)};
0 WalletDescriptor w_desc{(std::move(parsed_desc), 0, 0, 1, 1)};
nit: no need to mention the type twice for a single symbol
0,0,1,1
, which is hard to understand without meaning.
lgtm ACK 47e5c9994c087d1826ccc0d539e916845b5648fb ๐
Signature:
0untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
1RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
2trusted comment: lgtm ACK 47e5c9994c087d1826ccc0d539e916845b5648fb ๐
3n6LCX8TDcBqt4LlIUR6QxLtOOGcMzxg9UC9JX6H6d7ZkevyCsXylwzmblnXut4yESlWL+QQbvGi+mc5kXm16BQ==
97+ assert(spk_manager->IsMine(spk) == ISMINE_SPENDABLE);
98+ CTxDestination dest;
99+ bool extract_dest{ExtractDestination(spk, dest)};
100+ if (extract_dest) {
101+ const std::string msg{fuzzed_data_provider.ConsumeRandomLengthString()};
102+ PKHash pk_hash{fuzzed_data_provider.ConsumeBool() ? PKHash{ConsumeUInt160(fuzzed_data_provider)} : *std::get_if<PKHash>(&dest)};
*std::get_if
may be UB? In any case, it would be good to submit fuzz inputs that cover everything here.
Null-dereference READ ยท wallet::scriptpubkeyman_fuzz_target
0Command: /mnt/scratch0/clusterfuzz/bot/builds/clusterfuzz-builds-honggfuzz_bitcoin-core_83aef6625aaeafa301867de74608b320f3c923fe/revisions/scriptpubkeyman
1 Time ran: 0.5496230125427246
2
3 Accepting input from '[STDIN]'
4 Usage for fuzzing: honggfuzz -P [flags] -- /mnt/scratch0/clusterfuzz/bot/builds/clusterfuzz-builds-honggfuzz_bitcoin-core_83aef6625aaeafa301867de74608b320f3c923fe/revisions/scriptpubkeyman
5 AddressSanitizer:DEADLYSIGNAL
6 =================================================================
7 ==14133==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x79a1f8670aeb bp 0x7ffd95472db0 sp 0x7ffd95472578 T0)
8 ==14133==The signal is caused by a READ memory access.
9 ==14133==Hint: address points to the zero page.
10 SCARINESS: 10 (null-deref)
11 [#0](/bitcoin-bitcoin/0/) 0x79a1f8670aeb in memcpy /build/glibc-SzIz7B/glibc-2.31/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:142
12 [#1](/bitcoin-bitcoin/1/) 0x589ab4429a18 in __asan_memcpy /src/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3
13 [#2](/bitcoin-bitcoin/2/) 0x589ab44cf869 in operator() [bitcoin-core/src/wallet/test/fuzz/scriptpubkeyman.cpp:0](https://github.com/bitcoin/bitcoin/blob/b5a271334ca81a6adcb1c608d85c83621a9eae47/src/wallet/test/fuzz/scriptpubkeyman.cpp#L0)
14 [#3](/bitcoin-bitcoin/3/) 0x589ab44cf869 in CallOneOf<(lambda at wallet/test/fuzz/scriptpubkeyman.cpp:75:13), (lambda at wallet/test/fuzz/scriptpubkeyman.cpp:87:13), (lambda at wallet/test/fuzz/scriptpubkeyman.cpp:94:13), (lambda at wallet/test/fuzz/scriptpubkeyman.cpp:108:13), (lambda at wallet/test/fuzz/scriptpubkeyman.cpp:117:13), (lambda at wallet/test/fuzz/scriptpubkeyman.cpp:121:13), (lambda at wallet/test/fuzz/scriptpubkeyman.cpp:135:13), (lambda at wallet/test/fuzz/scriptpubkeyman.cpp:149:13)> [bitcoin-core/src/test/fuzz/util.h:43](https://github.com/bitcoin/bitcoin/blob/b5a271334ca81a6adcb1c608d85c83621a9eae47/src/test/fuzz/util.h#L43):27
15 [#4](/bitcoin-bitcoin/4/) 0x589ab44cf869 in wallet::(anonymous namespace)::scriptpubkeyman_fuzz_target(Span<unsigned char const>) [bitcoin-core/src/wallet/test/fuzz/scriptpubkeyman.cpp:73](https://github.com/bitcoin/bitcoin/blob/b5a271334ca81a6adcb1c608d85c83621a9eae47/src/wallet/test/fuzz/scriptpubkeyman.cpp#L73):9
16 [#5](/bitcoin-bitcoin/5/) 0x589ab446d2d1 in __invoke<void (*&)(Span<const unsigned char>), Span<const unsigned char> > /usr/local/include/c++/v1/type_traits:3592:23
17 [#6](/bitcoin-bitcoin/6/) 0x589ab446d2d1 in __call<void (*&)(Span<const unsigned char>), Span<const unsigned char> > /usr/local/include/c++/v1/__functional/invoke.h:61:9
18 [#7](/bitcoin-bitcoin/7/) 0x589ab446d2d1 in operator() /usr/local/include/c++/v1/__functional/function.h:181:16
19 [#8](/bitcoin-bitcoin/8/) 0x589ab446d2d1 in std::__1::__function::__func<void (*)(Span<unsigned char const>), std::__1::allocator<void (*)(Span<unsigned char const>)>, void (Span<unsigned char const>)>::operator()(Span<unsigned char const>&&) /usr/local/include/c++/v1/__functional/function.h:355:12
20 [#9](/bitcoin-bitcoin/9/) 0x589ab49ef0b8 in operator() /usr/local/include/c++/v1/__functional/function.h:508:16
21 [#10](/bitcoin-bitcoin/10/) 0x589ab49ef0b8 in operator() /usr/local/include/c++/v1/__functional/function.h:1185:12
22 [#11](/bitcoin-bitcoin/11/) 0x589ab49ef0b8 in LLVMFuzzerTestOneInput [bitcoin-core/src/test/fuzz/fuzz.cpp:178](https://github.com/bitcoin/bitcoin/blob/b5a271334ca81a6adcb1c608d85c83621a9eae47/src/test/fuzz/fuzz.cpp#L178):5
23 [#12](/bitcoin-bitcoin/12/) 0x589ab642bdeb in main
24 [#13](/bitcoin-bitcoin/13/) 0x79a1f85d9082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/libc-start.c:308:16
25 [#14](/bitcoin-bitcoin/14/) 0x589ab43a93bd in _start