Skip to content

Commit 7dd8dbd

Browse files
committed
intercept network, crypto and time
This fuzzing harness must be as deterministic as possible for the fuzzer to detect additional coverage reliably.
1 parent 9eb8879 commit 7dd8dbd

File tree

10 files changed

+317
-13
lines changed

10 files changed

+317
-13
lines changed

CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -543,15 +543,15 @@ if (BUILD_FUZZ_TESTS)
543543
# For coverage tests
544544
target_compile_definitions(toxcore_static PUBLIC "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION")
545545

546-
# Override network functions
547-
add_library(network_adapter testing/fuzzing/network_adapter.c)
546+
# Override network and random functions
547+
add_library(fuzz_adapter testing/fuzzing/fuzz_adapter.c)
548548

549549
# Fuzzes the toxsave API
550550
add_executable(toxsave_fuzzer testing/fuzzing/toxsave_harness.cc)
551-
target_link_libraries(toxsave_fuzzer toxcore_static network_adapter -fsanitize=fuzzer)
551+
target_link_libraries(toxsave_fuzzer toxcore_static fuzz_adapter -fsanitize=fuzzer)
552552

553553
# Fuzzes the bootstrap process
554554
add_executable(bootstrap_fuzzer testing/fuzzing/bootstrap_harness.cc)
555-
target_link_libraries(bootstrap_fuzzer toxcore_static network_adapter -fsanitize=fuzzer)
555+
target_link_libraries(bootstrap_fuzzer toxcore_static fuzz_adapter -fsanitize=fuzzer)
556556
endif()
557557

testing/fuzzing/bootstrap_harness.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
#include "../../toxcore/tox.h"
2-
#include "network_adapter.h"
3-
4-
#include <cstring>
51
#include <cassert>
2+
#include <cstring>
63

4+
#include "../../toxcore/tox.h"
5+
#include "fuzz_adapter.h"
76

87
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
98
network_adapter_init(data, size);

testing/fuzzing/fuzz_adapter.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#include "fuzz_adapter.h"
2+
3+
struct fuzz_buf {
4+
/* Monotonic counter for time replacement */
5+
uint64_t counter;
6+
/* Fuzz data buffer */
7+
const uint8_t *cur;
8+
const uint8_t *end;
9+
};
10+
11+
static struct fuzz_buf data;
12+
13+
#include <string.h>
14+
#include <arpa/inet.h>
15+
#include <sys/socket.h>
16+
17+
18+
void network_adapter_init(const uint8_t *buf, size_t length)
19+
{
20+
data.counter = 0;
21+
data.cur = buf;
22+
data.end = buf + length;
23+
}
24+
25+
ssize_t fuzz_sendto(int sockfd, const void *buf, size_t len,
26+
int flags, const struct sockaddr *addr,
27+
socklen_t addrlen)
28+
{
29+
return len;
30+
}
31+
32+
ssize_t fuzz_send(int sockfd, const void *buf, size_t len, int flags)
33+
{
34+
return len;
35+
}
36+
37+
static ssize_t recv_common(void *buf, size_t buf_len)
38+
{
39+
if (data.cur + 2 >= data.end) {
40+
return -1;
41+
}
42+
43+
uint16_t fuzz_len = (data.cur[0] << 8) | data.cur[1];
44+
data.cur += 2;
45+
46+
size_t available = data.end - data.cur;
47+
48+
size_t res = fuzz_len > available ? available : fuzz_len;
49+
res = buf_len > res ? res : buf_len;
50+
51+
memcpy(buf, data.cur, res);
52+
data.cur += res;
53+
54+
return res;
55+
}
56+
57+
ssize_t fuzz_recvfrom(int sockfd, void *buf, size_t len,
58+
int flags, struct sockaddr *src_addr,
59+
socklen_t *addr_len)
60+
{
61+
if (src_addr && addr_len && (sizeof(struct sockaddr) <= *addr_len)) {
62+
*src_addr = (struct sockaddr) {
63+
0
64+
};
65+
// Dummy Addr
66+
src_addr->sa_family = AF_INET;
67+
68+
// We want an AF_INET address with dummy values
69+
struct sockaddr_in *addr_in = (struct sockaddr_in *) src_addr;
70+
addr_in->sin_port = 12356;
71+
addr_in->sin_addr.s_addr = INADDR_LOOPBACK + 1;
72+
*addr_len = sizeof(struct sockaddr);
73+
}
74+
75+
return recv_common(buf, len);
76+
}
77+
78+
ssize_t fuzz_recv(int sockfd, void *buf, size_t len, int flags)
79+
{
80+
return recv_common(buf, len);
81+
}
82+
83+
void fuzz_random_bytes(uint8_t *rnd, size_t length)
84+
{
85+
// Amount of data is limited
86+
size_t available = data.end - data.cur;
87+
size_t bytes_read = length > available ? available : length;
88+
// Initialize everything to make MSAN and others happy
89+
memset(rnd, 0, length);
90+
memcpy(rnd, data.cur, bytes_read);
91+
data.cur += bytes_read;
92+
}
93+
94+
uint64_t fuzz_get_count(void)
95+
{
96+
return data.counter++;
97+
}

testing/fuzzing/fuzz_adapter.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later
2+
* Copyright © 2021 The TokTok team.
3+
*/
4+
5+
#ifndef C_TOXCORE_TESTING_FUZZING_FUZZ_ADAPTER_H
6+
#define C_TOXCORE_TESTING_FUZZING_FUZZ_ADAPTER_H
7+
8+
#include <stdint.h>
9+
#include <arpa/inet.h>
10+
#include <sys/socket.h>
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
/**
17+
* @brief Init function for the fuzzing harness
18+
* @param buf Begin of fuzz data
19+
* @param length Length of buf
20+
*/
21+
void network_adapter_init(const uint8_t *buf, size_t length);
22+
23+
/* The following functions intercept calls to standard network functions for fuzzing purposes and return data from the fuzz buffer. */
24+
25+
ssize_t fuzz_sendto(int sockfd, const void *buf, size_t len,
26+
int flags, const struct sockaddr *addr,
27+
socklen_t addrlen);
28+
29+
ssize_t fuzz_send(int sockfd, const void *buf, size_t len, int flags);
30+
31+
ssize_t fuzz_recvfrom(int sockfd, void *buf, size_t len,
32+
int flags, struct sockaddr *src_addr,
33+
socklen_t *addr_len);
34+
35+
ssize_t fuzz_recv(int sockfd, void *buf, size_t len, int flags);
36+
37+
/* The following functions intercept generation of random data */
38+
void fuzz_random_bytes(uint8_t *rnd, size_t length);
39+
40+
/* The following function replaces all time bases with a monotonic counter */
41+
42+
uint64_t fuzz_get_count(void);
43+
44+
#ifdef __cplusplus
45+
}
46+
#endif
47+
48+
#endif // C_TOXCORE_TESTING_FUZZING_FUZZ_ADAPTER_H

testing/fuzzing/toxsave_harness.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <cassert>
2+
13
#include "../../toxcore/tox.h"
24

35
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {

toxcore/LAN_discovery.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ static void fetch_broadcast_info(uint16_t port)
120120
}
121121
}
122122

123-
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
123+
#elif !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && (defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__))
124124

125125
static void fetch_broadcast_info(uint16_t port)
126126
{

toxcore/crypto_core.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@
2929
#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
3030
#endif
3131

32+
//!TOKSTYLE-
33+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
34+
#include "../testing/fuzzing/fuzz_adapter.h"
35+
#endif
36+
//!TOKSTYLE+
37+
3238
static_assert(CRYPTO_PUBLIC_KEY_SIZE == crypto_box_PUBLICKEYBYTES,
3339
"CRYPTO_PUBLIC_KEY_SIZE should be equal to crypto_box_PUBLICKEYBYTES");
3440
static_assert(CRYPTO_SECRET_KEY_SIZE == crypto_box_SECRETKEYBYTES,
@@ -48,6 +54,7 @@ static_assert(CRYPTO_SHA512_SIZE == crypto_hash_sha512_BYTES,
4854
static_assert(CRYPTO_PUBLIC_KEY_SIZE == 32,
4955
"CRYPTO_PUBLIC_KEY_SIZE is required to be 32 bytes for public_key_cmp to work");
5056

57+
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
5158
static uint8_t *crypto_malloc(size_t bytes)
5259
{
5360
return (uint8_t *)malloc(bytes);
@@ -61,10 +68,16 @@ static void crypto_free(uint8_t *ptr, size_t bytes)
6168

6269
free(ptr);
6370
}
71+
#endif // !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
6472

6573
int32_t public_key_cmp(const uint8_t *pk1, const uint8_t *pk2)
6674
{
75+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
76+
// Hope that this is better for the fuzzer
77+
return memcmp(pk1, pk2, CRYPTO_PUBLIC_KEY_SIZE) == 0 ? 0 : -1;
78+
#else
6779
return crypto_verify_32(pk1, pk2);
80+
#endif
6881
}
6982

7083
int32_t crypto_sha512_cmp(const uint8_t *cksum1, const uint8_t *cksum2)
@@ -131,6 +144,11 @@ int32_t encrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce,
131144
return -1;
132145
}
133146

147+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
148+
memcpy(encrypted, plain, length); // Don't encrypt anything
149+
memset(encrypted + length, 0, crypto_box_MACBYTES); // Zero MAC to avoid false alarms of uninitialized memory
150+
#else
151+
134152
const size_t size_temp_plain = length + crypto_box_ZEROBYTES;
135153
const size_t size_temp_encrypted = length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES;
136154

@@ -159,7 +177,7 @@ int32_t encrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce,
159177

160178
crypto_free(temp_plain, size_temp_plain);
161179
crypto_free(temp_encrypted, size_temp_encrypted);
162-
180+
#endif
163181
return length + crypto_box_MACBYTES;
164182
}
165183

@@ -170,6 +188,10 @@ int32_t decrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce,
170188
return -1;
171189
}
172190

191+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
192+
memcpy(plain, encrypted, length - crypto_box_MACBYTES); // Don't encrypt anything
193+
#else
194+
173195
const size_t size_temp_plain = length + crypto_box_ZEROBYTES;
174196
const size_t size_temp_encrypted = length + crypto_box_BOXZEROBYTES;
175197

@@ -197,6 +219,7 @@ int32_t decrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce,
197219

198220
crypto_free(temp_plain, size_temp_plain);
199221
crypto_free(temp_encrypted, size_temp_encrypted);
222+
#endif
200223
return length - crypto_box_MACBYTES;
201224
}
202225

@@ -295,7 +318,14 @@ void new_symmetric_key(uint8_t *key)
295318

296319
int32_t crypto_new_keypair(uint8_t *public_key, uint8_t *secret_key)
297320
{
321+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
322+
random_bytes(secret_key, CRYPTO_SECRET_KEY_SIZE);
323+
memset(public_key, 0, CRYPTO_PUBLIC_KEY_SIZE); // Make MSAN happy
324+
crypto_scalarmult_curve25519_base(public_key, secret_key);
325+
return 0;
326+
#else
298327
return crypto_box_keypair(public_key, secret_key);
328+
#endif
299329
}
300330

301331
void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key)
@@ -315,5 +345,9 @@ void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length)
315345

316346
void random_bytes(uint8_t *data, size_t length)
317347
{
348+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
349+
fuzz_random_bytes(data, length);
350+
#else
318351
randombytes(data, length);
352+
#endif
319353
}

toxcore/mono_time.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232

3333
#include "ccompat.h"
3434

35+
//!TOKSTYLE-
36+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
37+
#include "../testing/fuzzing/fuzz_adapter.h"
38+
#endif
39+
//!TOKSTYLE+
40+
3541
/* don't call into system billions of times for no reason */
3642
struct Mono_Time {
3743
uint64_t time;
@@ -98,6 +104,14 @@ static uint64_t current_time_monotonic_default(Mono_Time *mono_time, void *user_
98104
return time;
99105
}
100106

107+
108+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
109+
static uint64_t current_time_monotonic_dummy(Mono_Time *mono_time, void *user_data)
110+
{
111+
return fuzz_get_count();
112+
}
113+
#endif
114+
101115
Mono_Time *mono_time_new(void)
102116
{
103117
Mono_Time *mono_time = (Mono_Time *)calloc(1, sizeof(Mono_Time));
@@ -119,7 +133,11 @@ Mono_Time *mono_time_new(void)
119133
return nullptr;
120134
}
121135

136+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
137+
mono_time->current_time_callback = current_time_monotonic_dummy;
138+
#else
122139
mono_time->current_time_callback = current_time_monotonic_default;
140+
#endif
123141
mono_time->user_data = nullptr;
124142

125143
#ifdef OS_WIN32
@@ -136,7 +154,11 @@ Mono_Time *mono_time_new(void)
136154
#endif
137155

138156
mono_time->time = 0;
157+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
158+
mono_time->base_time = 0; // Maximum reproducibility
159+
#else
139160
mono_time->base_time = (uint64_t)time(nullptr) - (current_time_monotonic(mono_time) / 1000ULL);
161+
#endif
140162

141163
mono_time_update(mono_time);
142164

@@ -174,11 +196,16 @@ void mono_time_update(Mono_Time *mono_time)
174196

175197
uint64_t mono_time_get(const Mono_Time *mono_time)
176198
{
199+
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
200+
// Fuzzing is only single thread for now, no locking needed */
201+
return mono_time->time;
202+
#else
177203
uint64_t time = 0;
178204
pthread_rwlock_rdlock(mono_time->time_update_lock);
179205
time = mono_time->time;
180206
pthread_rwlock_unlock(mono_time->time_update_lock);
181207
return time;
208+
#endif
182209
}
183210

184211
bool mono_time_is_timeout(const Mono_Time *mono_time, uint64_t timestamp, uint64_t timeout)

0 commit comments

Comments
 (0)