/work/testing/fuzzing/bootstrap_fuzz_test.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include <cassert> |
2 | | #include <cstddef> |
3 | | #include <cstdio> |
4 | | #include <functional> |
5 | | #include <memory> |
6 | | |
7 | | #include "../../toxcore/tox.h" |
8 | | #include "../../toxcore/tox_dispatch.h" |
9 | | #include "../../toxcore/tox_events.h" |
10 | | #include "../../toxcore/tox_private.h" |
11 | | #include "../support/public/fuzz_data.hh" |
12 | | #include "../support/public/fuzz_helpers.hh" |
13 | | #include "../support/public/simulated_environment.hh" |
14 | | |
15 | | namespace { |
16 | | |
17 | | using tox::test::configure_fuzz_memory_source; |
18 | | using tox::test::configure_fuzz_packet_source; |
19 | | using tox::test::FakeClock; |
20 | | using tox::test::Fuzz_Data; |
21 | | using tox::test::SimulatedEnvironment; |
22 | | |
23 | | template <typename T> |
24 | | using Ptr = std::unique_ptr<T, void (*)(T *)>; |
25 | | |
26 | | void setup_callbacks(Tox_Dispatch *dispatch) |
27 | 30 | { |
28 | 30 | tox_events_callback_conference_connected( |
29 | 30 | dispatch, [](const Tox_Event_Conference_Connected *event, void *user_data) { |
30 | 0 | assert(event == nullptr); |
31 | 0 | }); |
32 | 30 | tox_events_callback_conference_connected( |
33 | 30 | dispatch, [](const Tox_Event_Conference_Connected *event, void *user_data) { |
34 | 0 | assert(event == nullptr); |
35 | 0 | }); |
36 | 30 | tox_events_callback_conference_invite( |
37 | 30 | dispatch, [](const Tox_Event_Conference_Invite *event, void *user_data) { |
38 | 0 | assert(event == nullptr); |
39 | 0 | }); |
40 | 30 | tox_events_callback_conference_message( |
41 | 30 | dispatch, [](const Tox_Event_Conference_Message *event, void *user_data) { |
42 | 0 | assert(event == nullptr); |
43 | 0 | }); |
44 | 30 | tox_events_callback_conference_peer_list_changed( |
45 | 30 | dispatch, [](const Tox_Event_Conference_Peer_List_Changed *event, void *user_data) { |
46 | 0 | assert(event == nullptr); |
47 | 0 | }); |
48 | 30 | tox_events_callback_conference_peer_name( |
49 | 30 | dispatch, [](const Tox_Event_Conference_Peer_Name *event, void *user_data) { |
50 | 0 | assert(event == nullptr); |
51 | 0 | }); |
52 | 30 | tox_events_callback_conference_title(dispatch, |
53 | 30 | [](const Tox_Event_Conference_Title *event, void *user_data) { assert(event == nullptr); }); |
54 | 30 | tox_events_callback_file_chunk_request( |
55 | 30 | dispatch, [](const Tox_Event_File_Chunk_Request *event, void *user_data) { |
56 | 0 | assert(event == nullptr); |
57 | 0 | }); |
58 | 30 | tox_events_callback_file_recv(dispatch, |
59 | 30 | [](const Tox_Event_File_Recv *event, void *user_data) { assert(event == nullptr); }); |
60 | 30 | tox_events_callback_file_recv_chunk(dispatch, |
61 | 30 | [](const Tox_Event_File_Recv_Chunk *event, void *user_data) { assert(event == nullptr); }); |
62 | 30 | tox_events_callback_file_recv_control( |
63 | 30 | dispatch, [](const Tox_Event_File_Recv_Control *event, void *user_data) { |
64 | 0 | assert(event == nullptr); |
65 | 0 | }); |
66 | 30 | tox_events_callback_friend_connection_status( |
67 | 30 | dispatch, [](const Tox_Event_Friend_Connection_Status *event, void *user_data) { |
68 | 0 | assert(event == nullptr); |
69 | 0 | }); |
70 | 30 | tox_events_callback_friend_lossless_packet( |
71 | 30 | dispatch, [](const Tox_Event_Friend_Lossless_Packet *event, void *user_data) { |
72 | 0 | assert(event == nullptr); |
73 | 0 | }); |
74 | 30 | tox_events_callback_friend_lossy_packet( |
75 | 30 | dispatch, [](const Tox_Event_Friend_Lossy_Packet *event, void *user_data) { |
76 | 0 | assert(event == nullptr); |
77 | 0 | }); |
78 | 30 | tox_events_callback_friend_message(dispatch, |
79 | 30 | [](const Tox_Event_Friend_Message *event, void *user_data) { assert(event == nullptr); }); |
80 | 30 | tox_events_callback_friend_name(dispatch, |
81 | 30 | [](const Tox_Event_Friend_Name *event, void *user_data) { assert(event == nullptr); }); |
82 | 30 | tox_events_callback_friend_read_receipt( |
83 | 30 | dispatch, [](const Tox_Event_Friend_Read_Receipt *event, void *user_data) { |
84 | 0 | assert(event == nullptr); |
85 | 0 | }); |
86 | 30 | tox_events_callback_friend_request( |
87 | 30 | dispatch, [](const Tox_Event_Friend_Request *event, void *user_data) { |
88 | 0 | Tox *tox = static_cast<Tox *>(user_data); |
89 | 0 | Tox_Err_Friend_Add err; |
90 | 0 | tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &err); |
91 | 0 | if (!(err == TOX_ERR_FRIEND_ADD_OK || err == TOX_ERR_FRIEND_ADD_OWN_KEY |
92 | 0 | || err == TOX_ERR_FRIEND_ADD_ALREADY_SENT |
93 | 0 | || err == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM |
94 | 0 | || err == TOX_ERR_FRIEND_ADD_MALLOC)) { |
95 | 0 | printf("unexpected error: %s\n", tox_err_friend_add_to_string(err)); |
96 | 0 | } |
97 | 0 | }); |
98 | 30 | tox_events_callback_friend_status(dispatch, |
99 | 30 | [](const Tox_Event_Friend_Status *event, void *user_data) { assert(event == nullptr); }); |
100 | 30 | tox_events_callback_friend_status_message( |
101 | 30 | dispatch, [](const Tox_Event_Friend_Status_Message *event, void *user_data) { |
102 | 0 | assert(event == nullptr); |
103 | 0 | }); |
104 | 30 | tox_events_callback_friend_typing(dispatch, |
105 | 30 | [](const Tox_Event_Friend_Typing *event, void *user_data) { assert(event == nullptr); }); |
106 | 30 | tox_events_callback_self_connection_status( |
107 | 30 | dispatch, [](const Tox_Event_Self_Connection_Status *event, void *user_data) { |
108 | 0 | assert(event == nullptr); |
109 | 0 | }); |
110 | 30 | } |
111 | | |
112 | | void TestBootstrap(Fuzz_Data &input) |
113 | 104 | { |
114 | 104 | SimulatedEnvironment env{12345}; |
115 | 104 | env.fake_clock().advance(1000000000); // Match legacy behavior |
116 | 104 | auto node = env.create_node(33445); |
117 | 104 | configure_fuzz_memory_source(env.fake_memory(), input); |
118 | 104 | configure_fuzz_packet_source(*node->endpoint, input); |
119 | | |
120 | | // Create a second null system for tox_events_equal check |
121 | 104 | SimulatedEnvironment null_env{12346}; |
122 | 104 | auto null_node = null_env.create_node(0); // Port 0 (unbound/irrelevant) |
123 | | |
124 | 104 | Ptr<Tox_Options> opts(tox_options_new(nullptr), tox_options_free); |
125 | 104 | assert(opts != nullptr); |
126 | | |
127 | 104 | tox_options_set_log_callback(opts.get(), |
128 | 104 | [](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func, |
129 | 370 | const char *message, void *user_data) { |
130 | | // Log to stdout. |
131 | 370 | if (Fuzz_Data::FUZZ_DEBUG) { |
132 | | // Approximate level name mapping |
133 | 0 | char level_char = '?'; |
134 | 0 | switch (level) { |
135 | 0 | case TOX_LOG_LEVEL_TRACE: |
136 | 0 | level_char = 'T'; |
137 | 0 | break; |
138 | 0 | case TOX_LOG_LEVEL_DEBUG: |
139 | 0 | level_char = 'D'; |
140 | 0 | break; |
141 | 0 | case TOX_LOG_LEVEL_INFO: |
142 | 0 | level_char = 'I'; |
143 | 0 | break; |
144 | 0 | case TOX_LOG_LEVEL_WARNING: |
145 | 0 | level_char = 'W'; |
146 | 0 | break; |
147 | 0 | case TOX_LOG_LEVEL_ERROR: |
148 | 0 | level_char = 'E'; |
149 | 0 | break; |
150 | 0 | } |
151 | 0 | std::printf("[tox1] %c %s:%u(%s): %s\n", level_char, file, line, func, message); |
152 | 0 | } |
153 | 370 | }); |
154 | | |
155 | 104 | CONSUME1_OR_RETURN(const uint8_t, proxy_type, input); |
156 | 104 | if (proxy_type == 0) { |
157 | 6 | tox_options_set_proxy_type(opts.get(), TOX_PROXY_TYPE_NONE); |
158 | 98 | } else if (proxy_type == 1) { |
159 | 41 | tox_options_set_proxy_type(opts.get(), TOX_PROXY_TYPE_SOCKS5); |
160 | 41 | tox_options_set_proxy_host(opts.get(), "127.0.0.1"); |
161 | 41 | tox_options_set_proxy_port(opts.get(), 8080); |
162 | 57 | } else if (proxy_type == 2) { |
163 | 33 | tox_options_set_proxy_type(opts.get(), TOX_PROXY_TYPE_HTTP); |
164 | 33 | tox_options_set_proxy_host(opts.get(), "127.0.0.1"); |
165 | 33 | tox_options_set_proxy_port(opts.get(), 8080); |
166 | 33 | } |
167 | | |
168 | 104 | CONSUME1_OR_RETURN(const uint8_t, tcp_relay_enabled, input); |
169 | 100 | if (tcp_relay_enabled >= (UINT8_MAX / 2)) { |
170 | 43 | tox_options_set_tcp_port(opts.get(), 33445); |
171 | 43 | } |
172 | | |
173 | 100 | Tox_Options_Testing tox_options_testing; |
174 | 100 | tox_options_testing.operating_system = &node->system; |
175 | | |
176 | 100 | Tox_Err_New error_new; |
177 | 100 | Tox_Err_New_Testing error_new_testing; |
178 | 100 | Tox *tox = tox_new_testing(opts.get(), &error_new, &tox_options_testing, &error_new_testing); |
179 | | |
180 | 100 | if (tox == nullptr) { |
181 | | // It might fail, because some I/O happens in tox_new, and the fuzzer |
182 | | // might do things that make that I/O fail. |
183 | 70 | return; |
184 | 70 | } |
185 | | |
186 | 30 | assert(error_new == TOX_ERR_NEW_OK); |
187 | 30 | assert(error_new_testing == TOX_ERR_NEW_TESTING_OK); |
188 | | |
189 | 30 | uint8_t pub_key[TOX_PUBLIC_KEY_SIZE] = {0}; |
190 | | |
191 | | // These may fail, but that's ok. We ignore their return values. |
192 | 30 | tox_bootstrap(tox, "127.0.0.2", 33446, pub_key, nullptr); |
193 | 30 | tox_add_tcp_relay(tox, "127.0.0.2", 33446, pub_key, nullptr); |
194 | | |
195 | 30 | tox_events_init(tox); |
196 | | |
197 | 30 | Tox_Dispatch *dispatch = tox_dispatch_new(nullptr); |
198 | 30 | assert(dispatch != nullptr); |
199 | 30 | setup_callbacks(dispatch); |
200 | | |
201 | 30 | Ptr<Tox_Iterate_Options> iterate_opts( |
202 | 30 | tox_iterate_options_new(nullptr), tox_iterate_options_free); |
203 | 30 | tox_iterate_options_set_fail_hard(iterate_opts.get(), true); |
204 | | |
205 | 30 | std::size_t input_size = input.size(); |
206 | 30 | while (!input.empty()) { |
207 | 11 | Tox_Err_Events_Iterate error_iterate; |
208 | 11 | Tox_Events *events = tox_events_iterate(tox, iterate_opts.get(), &error_iterate); |
209 | 11 | assert(tox_events_equal(&null_node->system, events, events)); |
210 | 11 | tox_dispatch_invoke(dispatch, events, tox); |
211 | 11 | tox_events_free(events); |
212 | | |
213 | 11 | env.advance_time(200); |
214 | | |
215 | | // If no input was consumed, stop. |
216 | 11 | if (input_size == input.size()) { |
217 | 11 | break; |
218 | 11 | } |
219 | | |
220 | 0 | input_size = input.size(); |
221 | 0 | } |
222 | | |
223 | 30 | tox_dispatch_free(dispatch); |
224 | 30 | tox_kill(tox); |
225 | 30 | } |
226 | | |
227 | | } |
228 | | |
229 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, std::size_t size); |
230 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, std::size_t size) |
231 | 2.69k | { |
232 | 2.69k | Fuzz_Data input{data, size}; |
233 | 2.69k | TestBootstrap(input); |
234 | 2.69k | return 0; // Non-zero return values are reserved for future use. |
235 | 2.69k | } |