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 <memory>
16 #include <string>
17 #include <unistd.h>
18 #include <vector>
19 
20 const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
21 
22 std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets()
23 {
24  static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets;
25  return g_fuzz_targets;
26 }
27 
29 {
30  const auto it_ins = FuzzTargets().try_emplace(name, std::move(target), std::move(init), hidden);
31  Assert(it_ins.second);
32 }
33 
35 
36 void initialize()
37 {
38  // Terminate immediately if a fuzzing harness ever tries to create a TCP socket.
39  CreateSock = [](const CService&) -> std::unique_ptr<Sock> { std::terminate(); };
40 
41  // Terminate immediately if a fuzzing harness ever tries to perform a DNS lookup.
42  g_dns_lookup = [](const std::string& name, bool allow_lookup) {
43  if (allow_lookup) {
44  std::terminate();
45  }
46  return WrappedGetAddrInfo(name, false);
47  };
48 
49  bool should_abort{false};
50  if (std::getenv("PRINT_ALL_FUZZ_TARGETS_AND_ABORT")) {
51  for (const auto& t : FuzzTargets()) {
52  if (std::get<2>(t.second)) continue;
53  std::cout << t.first << std::endl;
54  }
55  should_abort = true;
56  }
57  if (const char* out_path = std::getenv("WRITE_ALL_FUZZ_TARGETS_AND_ABORT")) {
58  std::cout << "Writing all fuzz target names to '" << out_path << "'." << std::endl;
59  std::ofstream out_stream(out_path, std::ios::binary);
60  for (const auto& t : FuzzTargets()) {
61  if (std::get<2>(t.second)) continue;
62  out_stream << t.first << std::endl;
63  }
64  should_abort = true;
65  }
66  Assert(!should_abort);
67  std::string_view fuzz_target{Assert(std::getenv("FUZZ"))};
68  const auto it = FuzzTargets().find(fuzz_target);
69  Assert(it != FuzzTargets().end());
71  g_test_one_input = &std::get<0>(it->second);
72  std::get<1>(it->second)();
73 }
74 
75 #if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
76 static bool read_stdin(std::vector<uint8_t>& data)
77 {
78  uint8_t buffer[1024];
79  ssize_t length = 0;
80  while ((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
81  data.insert(data.end(), buffer, buffer + length);
82  }
83  return length == 0;
84 }
85 #endif
86 
87 // This function is used by libFuzzer
88 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
89 {
90  static const auto& test_one_input = *Assert(g_test_one_input);
91  test_one_input({data, size});
92  return 0;
93 }
94 
95 // This function is used by libFuzzer
96 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
97 {
98  initialize();
99  return 0;
100 }
101 
102 #if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
103 int main(int argc, char** argv)
104 {
105  initialize();
106  static const auto& test_one_input = *Assert(g_test_one_input);
107 #ifdef __AFL_INIT
108  // Enable AFL deferred forkserver mode. Requires compilation using
109  // afl-clang-fast++. See fuzzing.md for details.
110  __AFL_INIT();
111 #endif
112 
113 #ifdef __AFL_LOOP
114  // Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
115  // See fuzzing.md for details.
116  while (__AFL_LOOP(1000)) {
117  std::vector<uint8_t> buffer;
118  if (!read_stdin(buffer)) {
119  continue;
120  }
121  test_one_input(buffer);
122  }
123 #else
124  std::vector<uint8_t> buffer;
125  if (!read_stdin(buffer)) {
126  return 0;
127  }
128  test_one_input(buffer);
129 #endif
130  return 0;
131 }
132 #endif
CService
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:539
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:526
g_test_one_input
static TypeTestOneInput * g_test_one_input
Definition: fuzz.cpp:34
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:102
initialize
void initialize()
Definition: fuzz.cpp:36
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:28
G_TEST_LOG_FUN
const std::function< void(const std::string &)> G_TEST_LOG_FUN
This is connected to the logger.
Definition: fuzz.cpp:20
LLVMFuzzerInitialize
int LLVMFuzzerInitialize(int *argc, char ***argv)
Definition: fuzz.cpp:96
TypeHidden
bool TypeHidden
Definition: fuzz.h:25
name
const char * name
Definition: rest.cpp:43
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:22
fuzz.h
init
Definition: bitcoin-node.cpp:16
netbase.h
LLVMFuzzerTestOneInput
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
Definition: fuzz.cpp:88
sock.h
main
int main(int argc, char **argv)
Definition: bench_bitcoin.cpp:39