From a19598cf9851cb238a4b5caa04f9ae7281532352 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 22 Apr 2020 13:54:41 +0000 Subject: [PATCH 1/8] tests: Add fuzzing harness for functions in system.h (ArgsManager) --- src/Makefile.test.include | 11 +++- src/test/fuzz/system.cpp | 123 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 src/test/fuzz/system.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 06dc59cf5c1..e2977b51e17 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -64,13 +64,12 @@ FUZZ_TARGETS = \ test/fuzz/parse_numbers \ test/fuzz/parse_script \ test/fuzz/parse_univalue \ - test/fuzz/prevector \ test/fuzz/partial_merkle_tree_deserialize \ test/fuzz/partially_signed_transaction_deserialize \ test/fuzz/pow \ test/fuzz/prefilled_transaction_deserialize \ test/fuzz/primitives_transaction \ - test/fuzz/process_messages \ + test/fuzz/prevector \ test/fuzz/process_message \ test/fuzz/process_message_addr \ test/fuzz/process_message_block \ @@ -96,6 +95,7 @@ FUZZ_TARGETS = \ test/fuzz/process_message_tx \ test/fuzz/process_message_verack \ test/fuzz/process_message_version \ + test/fuzz/process_messages \ test/fuzz/protocol \ test/fuzz/psbt \ test/fuzz/psbt_input_deserialize \ @@ -116,6 +116,7 @@ FUZZ_TARGETS = \ test/fuzz/string \ test/fuzz/strprintf \ test/fuzz/sub_net_deserialize \ + test/fuzz/system \ test/fuzz/timedata \ test/fuzz/transaction \ test/fuzz/tx_in \ @@ -969,6 +970,12 @@ test_fuzz_sub_net_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) test_fuzz_sub_net_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) test_fuzz_sub_net_deserialize_SOURCES = test/fuzz/deserialize.cpp +test_fuzz_system_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +test_fuzz_system_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +test_fuzz_system_LDADD = $(FUZZ_SUITE_LD_COMMON) +test_fuzz_system_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +test_fuzz_system_SOURCES = test/fuzz/system.cpp + test_fuzz_timedata_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_fuzz_timedata_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_timedata_LDADD = $(FUZZ_SUITE_LD_COMMON) diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp new file mode 100644 index 00000000000..7f378c2b13b --- /dev/null +++ b/src/test/fuzz/system.cpp @@ -0,0 +1,123 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include +#include +#include + +namespace { +std::string GetArgumentName(const std::string& name) +{ + size_t idx = name.find('='); + if (idx == std::string::npos) { + idx = name.size(); + } + return name.substr(0, idx); +} +} // namespace + +void test_one_input(const std::vector& buffer) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + ArgsManager args_manager{}; + + if (fuzzed_data_provider.ConsumeBool()) { + SetupHelpOptions(args_manager); + } + + while (fuzzed_data_provider.ConsumeBool()) { + switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) { + case 0: { + args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16)); + break; + } + case 1: { + args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); + break; + } + case 2: { + args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); + break; + } + case 3: { + args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool()); + break; + } + case 4: { + const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN}); + // Avoid hitting: + // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. + const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16)); + if (args_manager.GetArgFlags(argument_name) != nullopt) { + break; + } + args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral(), options_category); + break; + } + case 5: { + // Avoid hitting: + // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. + const std::vector names = ConsumeRandomLengthStringVector(fuzzed_data_provider); + std::vector hidden_arguments; + for (const std::string& name : names) { + const std::string hidden_argument = GetArgumentName(name); + if (args_manager.GetArgFlags(hidden_argument) != nullopt) { + continue; + } + if (std::find(hidden_arguments.begin(), hidden_arguments.end(), hidden_argument) != hidden_arguments.end()) { + continue; + } + hidden_arguments.push_back(hidden_argument); + } + args_manager.AddHiddenArgs(hidden_arguments); + break; + } + case 6: { + args_manager.ClearArgs(); + break; + } + case 7: { + const std::vector random_arguments = ConsumeRandomLengthStringVector(fuzzed_data_provider); + std::vector argv; + argv.resize(random_arguments.size()); + for (const std::string& random_argument : random_arguments) { + argv.push_back(random_argument.c_str()); + } + try { + std::string error; + (void)args_manager.ParseParameters(argv.size(), argv.data(), error); + } catch (const std::logic_error&) { + } + break; + } + } + } + + const std::string s1 = fuzzed_data_provider.ConsumeRandomLengthString(16); + const std::string s2 = fuzzed_data_provider.ConsumeRandomLengthString(16); + const int64_t i64 = fuzzed_data_provider.ConsumeIntegral(); + const bool b = fuzzed_data_provider.ConsumeBool(); + + (void)args_manager.GetArg(s1, i64); + (void)args_manager.GetArg(s1, s2); + (void)args_manager.GetArgFlags(s1); + (void)args_manager.GetArgs(s1); + (void)args_manager.GetBoolArg(s1, b); + try { + (void)args_manager.GetChainName(); + } catch (const std::runtime_error&) { + } + (void)args_manager.GetHelpMessage(); + (void)args_manager.GetUnrecognizedSections(); + (void)args_manager.GetUnsuitableSectionOnlyArgs(); + (void)args_manager.IsArgNegated(s1); + (void)args_manager.IsArgSet(s1); + + (void)HelpRequested(args_manager); +} From a4e3d13df6a6f48974f541de0b5b061e8078ba9a Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 22 Apr 2020 13:56:40 +0000 Subject: [PATCH 2/8] tests: Add fuzzing coverage for StringForFeeReason(...) --- src/test/fuzz/fees.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/fuzz/fees.cpp b/src/test/fuzz/fees.cpp index 090994263ea..f29acace232 100644 --- a/src/test/fuzz/fees.cpp +++ b/src/test/fuzz/fees.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -23,4 +24,6 @@ void test_one_input(const std::vector& buffer) const CAmount rounded_fee = fee_filter_rounder.round(current_minimum_fee); assert(MoneyRange(rounded_fee)); } + const FeeReason fee_reason = fuzzed_data_provider.PickValueInArray({FeeReason::NONE, FeeReason::HALF_ESTIMATE, FeeReason::FULL_ESTIMATE, FeeReason::DOUBLE_ESTIMATE, FeeReason::CONSERVATIVE, FeeReason::MEMPOOL_MIN, FeeReason::PAYTXFEE, FeeReason::FALLBACK, FeeReason::REQUIRED}); + (void)StringForFeeReason(fee_reason); } From 90b635e84e432e5a3682864f15274dba6acfbded Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 22 Apr 2020 13:57:15 +0000 Subject: [PATCH 3/8] tests: Add fuzzing coverage for CHECK_NONFATAL(...) --- src/test/fuzz/integer.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index 9dbf0fcc90f..d5b5ec3c9a9 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -24,8 +24,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -287,8 +288,12 @@ void test_one_input(const std::vector& buffer) try { const uint64_t deserialized_u64 = ReadCompactSize(stream); assert(u64 == deserialized_u64 && stream.empty()); - } - catch (const std::ios_base::failure&) { + } catch (const std::ios_base::failure&) { } } + + try { + CHECK_NONFATAL(b); + } catch (const NonFatalCheckError&) { + } } From 1532259fcae8712777e1cedefc91224ee60a6aaa Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 22 Apr 2020 13:57:28 +0000 Subject: [PATCH 4/8] tests: Add fuzzing coverage for FormatHDKeypath(...) and WriteHDKeypath(...) --- src/test/fuzz/parse_hd_keypath.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/fuzz/parse_hd_keypath.cpp b/src/test/fuzz/parse_hd_keypath.cpp index 9a23f4b2d43..f668ca8c48b 100644 --- a/src/test/fuzz/parse_hd_keypath.cpp +++ b/src/test/fuzz/parse_hd_keypath.cpp @@ -2,12 +2,22 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include +#include #include +#include +#include + void test_one_input(const std::vector& buffer) { const std::string keypath_str(buffer.begin(), buffer.end()); std::vector keypath; (void)ParseHDKeypath(keypath_str, keypath); + + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + const std::vector random_keypath = ConsumeRandomLengthIntegralVector(fuzzed_data_provider); + (void)FormatHDKeypath(random_keypath); + (void)WriteHDKeypath(random_keypath); } From dde508b8b03a4a144331cb1ff97f1349b491c402 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 22 Apr 2020 13:57:35 +0000 Subject: [PATCH 5/8] tests: Add fuzzing coverage for ParseFixedPoint(...) --- src/test/fuzz/string.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp index 3de0cf8db7c..49bee0e81ff 100644 --- a/src/test/fuzz/string.cpp +++ b/src/test/fuzz/string.cpp @@ -115,4 +115,8 @@ void test_one_input(const std::vector& buffer) assert(data_stream.empty()); assert(deserialized_string == random_string_1); } + { + int64_t amount_out; + (void)ParseFixedPoint(random_string_1, fuzzed_data_provider.ConsumeIntegralInRange(0, 1024), &amount_out); + } } From 103b6ecce0f8e6d1366962c8748794067b2485fe Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 22 Apr 2020 13:53:50 +0000 Subject: [PATCH 6/8] tests: Add fuzzing coverage for TransactionErrorString(...) --- src/Makefile.test.include | 7 +++++++ src/test/fuzz/kitchen_sink.cpp | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/test/fuzz/kitchen_sink.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index e2977b51e17..69d02f17d57 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -49,6 +49,7 @@ FUZZ_TARGETS = \ test/fuzz/key \ test/fuzz/key_io \ test/fuzz/key_origin_info_deserialize \ + test/fuzz/kitchen_sink \ test/fuzz/locale \ test/fuzz/merkle_block_deserialize \ test/fuzz/merkleblock \ @@ -568,6 +569,12 @@ test_fuzz_key_origin_info_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) test_fuzz_key_origin_info_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) test_fuzz_key_origin_info_deserialize_SOURCES = test/fuzz/deserialize.cpp +test_fuzz_kitchen_sink_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +test_fuzz_kitchen_sink_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +test_fuzz_kitchen_sink_LDADD = $(FUZZ_SUITE_LD_COMMON) +test_fuzz_kitchen_sink_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +test_fuzz_kitchen_sink_SOURCES = test/fuzz/kitchen_sink.cpp + test_fuzz_locale_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_fuzz_locale_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_locale_LDADD = $(FUZZ_SUITE_LD_COMMON) diff --git a/src/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp new file mode 100644 index 00000000000..92c56ae58d5 --- /dev/null +++ b/src/test/fuzz/kitchen_sink.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include +#include + +// The fuzzing kitchen sink: Fuzzing harness for functions that need to be +// fuzzed but a.) don't belong in any existing fuzzing harness file, and +// b.) are not important enough to warrant their own fuzzing harness file. +void test_one_input(const std::vector& buffer) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + + const TransactionError transaction_error = fuzzed_data_provider.PickValueInArray({TransactionError::OK, TransactionError::MISSING_INPUTS, TransactionError::ALREADY_IN_CHAIN, TransactionError::P2P_DISABLED, TransactionError::MEMPOOL_REJECTED, TransactionError::MEMPOOL_ERROR, TransactionError::INVALID_PSBT, TransactionError::PSBT_MISMATCH, TransactionError::SIGHASH_MISMATCH, TransactionError::MAX_FEE_EXCEEDED}); + (void)TransactionErrorString(transaction_error); +} From e1e181fad1a73e9dee38a2bd74518e1b8d446930 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 22 Apr 2020 14:40:32 +0000 Subject: [PATCH 7/8] tests: Add fuzzing coverage for JSONRPCTransactionError(...) and RPCErrorFromTransactionError(...) --- src/test/fuzz/kitchen_sink.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp index 92c56ae58d5..af6dc713223 100644 --- a/src/test/fuzz/kitchen_sink.cpp +++ b/src/test/fuzz/kitchen_sink.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include @@ -18,5 +19,7 @@ void test_one_input(const std::vector& buffer) FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const TransactionError transaction_error = fuzzed_data_provider.PickValueInArray({TransactionError::OK, TransactionError::MISSING_INPUTS, TransactionError::ALREADY_IN_CHAIN, TransactionError::P2P_DISABLED, TransactionError::MEMPOOL_REJECTED, TransactionError::MEMPOOL_ERROR, TransactionError::INVALID_PSBT, TransactionError::PSBT_MISMATCH, TransactionError::SIGHASH_MISMATCH, TransactionError::MAX_FEE_EXCEEDED}); + (void)JSONRPCTransactionError(transaction_error); + (void)RPCErrorFromTransactionError(transaction_error); (void)TransactionErrorString(transaction_error); } From 32b6b386a5499b1f8439f80d8fc1ee573bc31a53 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Sun, 26 Apr 2020 20:25:18 +0000 Subject: [PATCH 8/8] tests: Sort fuzzing harnesses --- src/Makefile.test.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 69d02f17d57..48db60f0866 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -69,8 +69,8 @@ FUZZ_TARGETS = \ test/fuzz/partially_signed_transaction_deserialize \ test/fuzz/pow \ test/fuzz/prefilled_transaction_deserialize \ - test/fuzz/primitives_transaction \ test/fuzz/prevector \ + test/fuzz/primitives_transaction \ test/fuzz/process_message \ test/fuzz/process_message_addr \ test/fuzz/process_message_block \