Merge #18736: test: Add fuzzing harnesses for various classes/functions in util/

32b6b386a5 tests: Sort fuzzing harnesses (practicalswift)
e1e181fad1 tests: Add fuzzing coverage for JSONRPCTransactionError(...) and RPCErrorFromTransactionError(...) (practicalswift)
103b6ecce0 tests: Add fuzzing coverage for TransactionErrorString(...) (practicalswift)
dde508b8b0 tests: Add fuzzing coverage for ParseFixedPoint(...) (practicalswift)
1532259fca tests: Add fuzzing coverage for FormatHDKeypath(...) and WriteHDKeypath(...) (practicalswift)
90b635e84e tests: Add fuzzing coverage for CHECK_NONFATAL(...) (practicalswift)
a4e3d13df6 tests: Add fuzzing coverage for StringForFeeReason(...) (practicalswift)
a19598cf98 tests: Add fuzzing harness for functions in system.h (ArgsManager) (practicalswift)

Pull request description:

  Add fuzzing harnesses for various classes/functions in `util/`.

  See [`doc/fuzzing.md`](https://github.com/bitcoin/bitcoin/blob/master/doc/fuzzing.md) for information on how to fuzz Bitcoin Core. Don't forget to contribute any coverage increasing inputs you find to the [Bitcoin Core fuzzing corpus repo](https://github.com/bitcoin-core/qa-assets).

  Happy fuzzing :)

Top commit has no ACKs.

Tree-SHA512: d27947220850c2a202c7740f44140c17545f45522596912452ccab0c2f5379abeb07cc769982c7855cb465059425206371a2b75ee1c285b03984161c9619d0b0
This commit is contained in:
MarcoFalke 2020-04-29 18:47:08 -04:00
commit 95a9165016
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
7 changed files with 189 additions and 5 deletions

View file

@ -49,6 +49,7 @@ FUZZ_TARGETS = \
test/fuzz/key \ test/fuzz/key \
test/fuzz/key_io \ test/fuzz/key_io \
test/fuzz/key_origin_info_deserialize \ test/fuzz/key_origin_info_deserialize \
test/fuzz/kitchen_sink \
test/fuzz/locale \ test/fuzz/locale \
test/fuzz/merkle_block_deserialize \ test/fuzz/merkle_block_deserialize \
test/fuzz/merkleblock \ test/fuzz/merkleblock \
@ -64,13 +65,12 @@ FUZZ_TARGETS = \
test/fuzz/parse_numbers \ test/fuzz/parse_numbers \
test/fuzz/parse_script \ test/fuzz/parse_script \
test/fuzz/parse_univalue \ test/fuzz/parse_univalue \
test/fuzz/prevector \
test/fuzz/partial_merkle_tree_deserialize \ test/fuzz/partial_merkle_tree_deserialize \
test/fuzz/partially_signed_transaction_deserialize \ test/fuzz/partially_signed_transaction_deserialize \
test/fuzz/pow \ test/fuzz/pow \
test/fuzz/prefilled_transaction_deserialize \ test/fuzz/prefilled_transaction_deserialize \
test/fuzz/prevector \
test/fuzz/primitives_transaction \ test/fuzz/primitives_transaction \
test/fuzz/process_messages \
test/fuzz/process_message \ test/fuzz/process_message \
test/fuzz/process_message_addr \ test/fuzz/process_message_addr \
test/fuzz/process_message_block \ test/fuzz/process_message_block \
@ -96,6 +96,7 @@ FUZZ_TARGETS = \
test/fuzz/process_message_tx \ test/fuzz/process_message_tx \
test/fuzz/process_message_verack \ test/fuzz/process_message_verack \
test/fuzz/process_message_version \ test/fuzz/process_message_version \
test/fuzz/process_messages \
test/fuzz/protocol \ test/fuzz/protocol \
test/fuzz/psbt \ test/fuzz/psbt \
test/fuzz/psbt_input_deserialize \ test/fuzz/psbt_input_deserialize \
@ -116,6 +117,7 @@ FUZZ_TARGETS = \
test/fuzz/string \ test/fuzz/string \
test/fuzz/strprintf \ test/fuzz/strprintf \
test/fuzz/sub_net_deserialize \ test/fuzz/sub_net_deserialize \
test/fuzz/system \
test/fuzz/timedata \ test/fuzz/timedata \
test/fuzz/transaction \ test/fuzz/transaction \
test/fuzz/tx_in \ test/fuzz/tx_in \
@ -567,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_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_key_origin_info_deserialize_SOURCES = test/fuzz/deserialize.cpp 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_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_locale_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_locale_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_locale_LDADD = $(FUZZ_SUITE_LD_COMMON) test_fuzz_locale_LDADD = $(FUZZ_SUITE_LD_COMMON)
@ -969,6 +977,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_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_sub_net_deserialize_SOURCES = test/fuzz/deserialize.cpp 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_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_timedata_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_timedata_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_timedata_LDADD = $(FUZZ_SUITE_LD_COMMON) test_fuzz_timedata_LDADD = $(FUZZ_SUITE_LD_COMMON)

View file

@ -8,6 +8,7 @@
#include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h> #include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h> #include <test/fuzz/util.h>
#include <util/fees.h>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
@ -23,4 +24,6 @@ void test_one_input(const std::vector<uint8_t>& buffer)
const CAmount rounded_fee = fee_filter_rounder.round(current_minimum_fee); const CAmount rounded_fee = fee_filter_rounder.round(current_minimum_fee);
assert(MoneyRange(rounded_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);
} }

View file

@ -24,8 +24,8 @@
#include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h> #include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h> #include <test/fuzz/util.h>
#include <time.h>
#include <uint256.h> #include <uint256.h>
#include <util/check.h>
#include <util/moneystr.h> #include <util/moneystr.h>
#include <util/strencodings.h> #include <util/strencodings.h>
#include <util/string.h> #include <util/string.h>
@ -35,6 +35,7 @@
#include <cassert> #include <cassert>
#include <chrono> #include <chrono>
#include <ctime>
#include <limits> #include <limits>
#include <set> #include <set>
#include <vector> #include <vector>
@ -287,8 +288,12 @@ void test_one_input(const std::vector<uint8_t>& buffer)
try { try {
const uint64_t deserialized_u64 = ReadCompactSize(stream); const uint64_t deserialized_u64 = ReadCompactSize(stream);
assert(u64 == deserialized_u64 && stream.empty()); 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&) {
} }
} }

View file

@ -0,0 +1,25 @@
// 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 <rpc/util.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <util/error.h>
#include <cstdint>
#include <vector>
// 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<uint8_t>& buffer)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const TransactionError transaction_error = fuzzed_data_provider.PickValueInArray<TransactionError>({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);
}

View file

@ -2,12 +2,22 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h> #include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <util/bip32.h> #include <util/bip32.h>
#include <cstdint>
#include <vector>
void test_one_input(const std::vector<uint8_t>& buffer) void test_one_input(const std::vector<uint8_t>& buffer)
{ {
const std::string keypath_str(buffer.begin(), buffer.end()); const std::string keypath_str(buffer.begin(), buffer.end());
std::vector<uint32_t> keypath; std::vector<uint32_t> keypath;
(void)ParseHDKeypath(keypath_str, keypath); (void)ParseHDKeypath(keypath_str, keypath);
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const std::vector<uint32_t> random_keypath = ConsumeRandomLengthIntegralVector<uint32_t>(fuzzed_data_provider);
(void)FormatHDKeypath(random_keypath);
(void)WriteHDKeypath(random_keypath);
} }

View file

@ -115,4 +115,8 @@ void test_one_input(const std::vector<uint8_t>& buffer)
assert(data_stream.empty()); assert(data_stream.empty());
assert(deserialized_string == random_string_1); assert(deserialized_string == random_string_1);
} }
{
int64_t amount_out;
(void)ParseFixedPoint(random_string_1, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 1024), &amount_out);
}
} }

123
src/test/fuzz/system.cpp Normal file
View file

@ -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 <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <util/system.h>
#include <cstdint>
#include <string>
#include <vector>
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<uint8_t>& 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<int>(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>({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<unsigned int>(), 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<std::string> names = ConsumeRandomLengthStringVector(fuzzed_data_provider);
std::vector<std::string> 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<std::string> random_arguments = ConsumeRandomLengthStringVector(fuzzed_data_provider);
std::vector<const char*> 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<int64_t>();
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);
}