Bitcoin Core  22.99.0
P2P Digital Currency
fuzz.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2021 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 <test/fuzz/fuzz.h>
6 
7 #include <netaddress.h>
8 #include <netbase.h>
10 #include <util/check.h>
11 #include <util/sock.h>
12 
13 #include <cstdint>
14 #include <exception>
15 #include <functional>
16 #include <memory>
17 #include <string>
18 #include <unistd.h>
19 #include <vector>
20 
21 const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
22 
30 static std::vector<const char*> g_args;
31 
32 static void SetArgs(int argc, char** argv) {
33  for (int i = 1; i < argc; ++i) {
34  // Only take into account arguments that start with `--`. The others are for the fuzz engine:
35  // `fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5`
36  if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == '-') {
37  g_args.push_back(argv[i]);
38  }
39  }
40 }
41 
42 const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS = []() {
43  return g_args;
44 };
45 
46 std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets()
47 {
48  static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets;
49  return g_fuzz_targets;
50 }
51 
53 {
54  const auto it_ins = FuzzTargets().try_emplace(name, std::move(target), std::move(init), hidden);
55  Assert(it_ins.second);
56 }
57 
59 
60 void initialize()
61 {
62  // Terminate immediately if a fuzzing harness ever tries to create a TCP socket.
63  CreateSock = [](const CService&) -> std::unique_ptr<Sock> { std::terminate(); };
64 
65  // Terminate immediately if a fuzzing harness ever tries to perform a DNS lookup.
66  g_dns_lookup = [](const std::string& name, bool allow_lookup) {
67  if (allow_lookup) {
68  std::terminate();
69  }
70  return WrappedGetAddrInfo(name, false);
71  };
72 
73  bool should_abort{false};
74  if (std::getenv("PRINT_ALL_FUZZ_TARGETS_AND_ABORT")) {
75  for (const auto& t : FuzzTargets()) {
76  if (std::get<2>(t.second)) continue;
77  std::cout << t.first << std::endl;
78  }
79  should_abort = true;
80  }
81  if (const char* out_path = std::getenv("WRITE_ALL_FUZZ_TARGETS_AND_ABORT")) {
82  std::cout << "Writing all fuzz target names to '" << out_path << "'." << std::endl;
83  std::ofstream out_stream(out_path, std::ios::binary);
84  for (const auto& t : FuzzTargets()) {
85  if (std::get<2>(t.second)) continue;
86  out_stream << t.first << std::endl;
87  }
88  should_abort = true;
89  }
90  Assert(!should_abort);
91  std::string_view fuzz_target{Assert(std::getenv("FUZZ"))};
92  const auto it = FuzzTargets().find(fuzz_target);
93  Assert(it != FuzzTargets().end());
95  g_test_one_input = &std::get<0>(it->second);
96  std::get<1>(it->second)();
97 }
98 
99 #if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
100 static bool read_stdin(std::vector<uint8_t>& data)
101 {
102  uint8_t buffer[1024];
103  ssize_t length = 0;
104  while ((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
105  data.insert(data.end(), buffer, buffer + length);
106  }
107  return length == 0;
108 }
109 #endif
110 
111 // This function is used by libFuzzer
112 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
113 {
114  static const auto& test_one_input = *Assert(g_test_one_input);
115  test_one_input({data, size});
116  return 0;
117 }
118 
119 // This function is used by libFuzzer
120 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
121 {
122  SetArgs(*argc, *argv);
123  initialize();
124  return 0;
125 }
126 
127 #if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
128 int main(int argc, char** argv)
129 {
130  initialize();
131  static const auto& test_one_input = *Assert(g_test_one_input);
132 #ifdef __AFL_INIT
133  // Enable AFL deferred forkserver mode. Requires compilation using
134  // afl-clang-fast++. See fuzzing.md for details.
135  __AFL_INIT();
136 #endif
137 
138 #ifdef __AFL_LOOP
139  // Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
140  // See fuzzing.md for details.
141  while (__AFL_LOOP(1000)) {
142  std::vector<uint8_t> buffer;
143  if (!read_stdin(buffer)) {
144  continue;
145  }
146  test_one_input(buffer);
147  }
148 #else
149  std::vector<uint8_t> buffer;
150  if (!read_stdin(buffer)) {
151  return 0;
152  }
153  test_one_input(buffer);
154 #endif
155  return 0;
156 }
157 #endif
CService
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:528
check.h
fuzz_target
void fuzz_target(FuzzBufferType buffer, const std::string &LIMIT_TO_MESSAGE_TYPE)
Definition: process_message.cpp:67
setup_common.h
CreateSock
std::function< std::unique_ptr< Sock >const CService &)> CreateSock
Socket factory.
Definition: netbase.cpp:529
g_test_one_input
static TypeTestOneInput * g_test_one_input
Definition: fuzz.cpp:58
Assert
#define Assert(val)
Identity function.
Definition: check.h:57
TypeInitialize
std::function< void()> TypeInitialize
Definition: fuzz.h:24
fsbridge::ofstream
fs::ofstream ofstream
Definition: fs.h:235
G_TEST_COMMAND_LINE_ARGUMENTS
const std::function< std::vector< const char * >)> G_TEST_COMMAND_LINE_ARGUMENTS
Retrieve the command line arguments.
Definition: fuzz.cpp:42
initialize
void initialize()
Definition: fuzz.cpp:60
g_dns_lookup
DNSLookupFn g_dns_lookup
Definition: netbase.cpp:85
netaddress.h
FuzzFrameworkRegisterTarget
void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init, TypeHidden hidden)
Definition: fuzz.cpp:52
G_TEST_LOG_FUN
const std::function< void(const std::string &)> G_TEST_LOG_FUN
This is connected to the logger.
Definition: fuzz.cpp:21
LLVMFuzzerInitialize
int LLVMFuzzerInitialize(int *argc, char ***argv)
Definition: fuzz.cpp:120
TypeHidden
bool TypeHidden
Definition: fuzz.h:25
name
const char * name
Definition: rest.cpp:52
TypeTestOneInput
std::function< void(FuzzBufferType)> TypeTestOneInput
Definition: fuzz.h:23
WrappedGetAddrInfo
std::vector< CNetAddr > WrappedGetAddrInfo(const std::string &name, bool allow_lookup)
Wrapper for getaddrinfo(3).
Definition: netbase.cpp:43
FuzzTargets
std::map< std::string_view, std::tuple< TypeTestOneInput, TypeInitialize, TypeHidden > > & FuzzTargets()
Definition: fuzz.cpp:46
fuzz.h
init
Definition: bitcoin-gui.cpp:16
netbase.h
LLVMFuzzerTestOneInput
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
Definition: fuzz.cpp:112
SetArgs
static void SetArgs(int argc, char **argv)
Definition: fuzz.cpp:32
g_args
static std::vector< const char * > g_args
A copy of the command line arguments that start with --.
Definition: fuzz.cpp:30
sock.h
main
int main(int argc, char **argv)
Definition: bench_bitcoin.cpp:46
ByteUnit::t
@ t