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