Coverage Report

Created: 2024-01-26 01:52

/work/testing/fuzzing/fuzz_support.cc
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2021-2022 The TokTok team.
3
 */
4
5
#include "fuzz_support.h"
6
7
#include <arpa/inet.h>
8
#include <sys/socket.h>
9
10
#include <algorithm>
11
#include <cassert>
12
#include <cerrno>
13
#include <climits>
14
#include <cstdio>
15
#include <cstring>
16
#include <memory>
17
18
#include "../../toxcore/crypto_core.h"
19
#include "../../toxcore/network.h"
20
#include "../../toxcore/tox_private.h"
21
#include "func_conversion.h"
22
23
// TODO(iphydf): Put this somewhere shared.
24
struct Network_Addr {
25
    struct sockaddr_storage addr;
26
    size_t size;
27
};
28
29
System::System(std::unique_ptr<Tox_System> in_sys, std::unique_ptr<Memory> in_mem,
30
    std::unique_ptr<Network> in_ns, std::unique_ptr<Random> in_rng)
31
    : sys(std::move(in_sys))
32
    , mem(std::move(in_mem))
33
    , ns(std::move(in_ns))
34
    , rng(std::move(in_rng))
35
3.39k
{
36
3.39k
}
37
0
System::System(System &&) = default;
38
39
3.39k
System::~System() { }
40
41
static int recv_common(Fuzz_Data &input, uint8_t *buf, size_t buf_len)
42
18.9k
{
43
18.9k
    if (input.size() < 2) {
44
568
        errno = ENOMEM;
45
568
        return -1;
46
568
    }
47
48
36.6k
    CONSUME_OR_ABORT(const uint8_t *fuzz_len_bytes, input, 2);
49
36.6k
    const std::size_t fuzz_len = (fuzz_len_bytes[0] << 8) | fuzz_len_bytes[1];
50
51
36.6k
    if (fuzz_len == 0xffff) {
52
9.13k
        errno = EWOULDBLOCK;
53
9.13k
        if (Fuzz_Data::DEBUG) {
54
0
            std::printf("recvfrom: no data for tox1\n");
55
0
        }
56
9.13k
        return -1;
57
9.13k
    }
58
59
9.20k
    if (Fuzz_Data::DEBUG) {
60
0
        std::printf(
61
0
            "recvfrom: %zu (%02x, %02x) for tox1\n", fuzz_len, input.data()[-2], input.data()[-1]);
62
0
    }
63
9.20k
    const size_t res = std::min(buf_len, std::min(fuzz_len, input.size()));
64
65
9.20k
    CONSUME_OR_ABORT(const uint8_t *data, input, res);
66
9.20k
    std::copy(data, data + res, buf);
67
68
9.20k
    return res;
69
9.20k
}
70
71
static void *report_alloc(const char *name, const char *func, std::size_t size, void *ptr)
72
44.2k
{
73
44.2k
    if (Fuzz_Data::DEBUG) {
74
0
        printf("%s: %s(%zu): %s\n", name, func, size, ptr == nullptr ? "false" : "true");
75
0
    }
76
44.2k
    return ptr;
77
44.2k
}
78
79
template <typename F, F Func, typename... Args>
80
static void *alloc_common(const char *func, std::size_t size, Fuzz_Data &data, Args... args)
81
48.8k
{
82
48.8k
    CONSUME1_OR_RETURN_VAL(
83
46.0k
        const bool, want_alloc, data, report_alloc("tox1", func, size, Func(args...)));
84
46.0k
    if (!want_alloc) {
85
4.60k
        return nullptr;
86
4.60k
    }
87
41.4k
    return report_alloc("tox1", func, size, Func(args...));
88
46.0k
}
unity_0_cxx.cxx:_ZL12alloc_commonIDoFPvmEXadL_Z6mallocEEJjEES0_PKcmR9Fuzz_DataDpT1_
Line
Count
Source
81
1.43k
{
82
1.43k
    CONSUME1_OR_RETURN_VAL(
83
1.31k
        const bool, want_alloc, data, report_alloc("tox1", func, size, Func(args...)));
84
1.31k
    if (!want_alloc) {
85
336
        return nullptr;
86
336
    }
87
981
    return report_alloc("tox1", func, size, Func(args...));
88
1.31k
}
unity_0_cxx.cxx:_ZL12alloc_commonIDoFPvmmEXadL_Z6callocEEJjjEES0_PKcmR9Fuzz_DataDpT1_
Line
Count
Source
81
38.0k
{
82
38.0k
    CONSUME1_OR_RETURN_VAL(
83
36.1k
        const bool, want_alloc, data, report_alloc("tox1", func, size, Func(args...)));
84
36.1k
    if (!want_alloc) {
85
1.19k
        return nullptr;
86
1.19k
    }
87
34.9k
    return report_alloc("tox1", func, size, Func(args...));
88
36.1k
}
unity_0_cxx.cxx:_ZL12alloc_commonIDoFPvS0_mEXadL_Z7reallocEEJS0_jEES0_PKcmR9Fuzz_DataDpT1_
Line
Count
Source
81
9.40k
{
82
9.40k
    CONSUME1_OR_RETURN_VAL(
83
8.53k
        const bool, want_alloc, data, report_alloc("tox1", func, size, Func(args...)));
84
8.53k
    if (!want_alloc) {
85
3.07k
        return nullptr;
86
3.07k
    }
87
5.45k
    return report_alloc("tox1", func, size, Func(args...));
88
8.53k
}
89
90
static constexpr Memory_Funcs fuzz_memory_funcs = {
91
    /* .malloc = */
92
1.43k
    ![](Fuzz_System *self, uint32_t size) {
93
1.43k
        return alloc_common<decltype(std::malloc), std::malloc>("malloc", size, self->data, size);
94
1.43k
    },
95
    /* .calloc = */
96
38.0k
    ![](Fuzz_System *self, uint32_t nmemb, uint32_t size) {
97
38.0k
        return alloc_common<decltype(std::calloc), std::calloc>(
98
38.0k
            "calloc", nmemb * size, self->data, nmemb, size);
99
38.0k
    },
100
    /* .realloc = */
101
9.40k
    ![](Fuzz_System *self, void *ptr, uint32_t size) {
102
9.40k
        return alloc_common<decltype(std::realloc), std::realloc>(
103
9.40k
            "realloc", size, self->data, ptr, size);
104
9.40k
    },
105
    /* .free = */
106
45.1k
    ![](Fuzz_System *self, void *ptr) { std::free(ptr); },
107
};
108
109
static constexpr Network_Funcs fuzz_network_funcs = {
110
1.27k
    /* .close = */ ![](Fuzz_System *self, int sock) { return 0; },
111
2.81k
    /* .accept = */ ![](Fuzz_System *self, int sock) { return 1337; },
112
651
    /* .bind = */ ![](Fuzz_System *self, int sock, const Network_Addr *addr) { return 0; },
113
16
    /* .listen = */ ![](Fuzz_System *self, int sock, int backlog) { return 0; },
114
    /* .recvbuf = */
115
7.22k
    ![](Fuzz_System *self, int sock) {
116
7.22k
        assert(sock == 42 || sock == 1337);
117
7.22k
        const size_t count = random_u16(self->rng.get());
118
7.22k
        return static_cast<int>(std::min(count, self->data.size()));
119
7.22k
    },
120
    /* .recv = */
121
4.05k
    ![](Fuzz_System *self, int sock, uint8_t *buf, size_t len) {
122
4.05k
        assert(sock == 42 || sock == 1337);
123
        // Receive data from the fuzzer.
124
4.05k
        return recv_common(self->data, buf, len);
125
4.05k
    },
126
    /* .recvfrom = */
127
14.8k
    ![](Fuzz_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
128
14.8k
        assert(sock == 42 || sock == 1337);
129
130
14.8k
        addr->addr = sockaddr_storage{};
131
        // Dummy Addr
132
14.8k
        addr->addr.ss_family = AF_INET;
133
134
        // We want an AF_INET address with dummy values
135
14.8k
        sockaddr_in *addr_in = reinterpret_cast<sockaddr_in *>(&addr->addr);
136
14.8k
        addr_in->sin_port = htons(33446);
137
14.8k
        addr_in->sin_addr.s_addr = htonl(0x7f000002);  // 127.0.0.2
138
14.8k
        addr->size = sizeof(struct sockaddr);
139
140
14.8k
        return recv_common(self->data, buf, len);
141
14.8k
    },
142
    /* .send = */
143
690
    ![](Fuzz_System *self, int sock, const uint8_t *buf, size_t len) {
144
690
        assert(sock == 42 || sock == 1337);
145
        // Always succeed.
146
690
        return static_cast<int>(len);
147
690
    },
148
    /* .sendto = */
149
15.2k
    ![](Fuzz_System *self, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
150
15.2k
        assert(sock == 42 || sock == 1337);
151
        // Always succeed.
152
15.2k
        return static_cast<int>(len);
153
15.2k
    },
154
1.01k
    /* .socket = */ ![](Fuzz_System *self, int domain, int type, int proto) { return 42; },
155
3.83k
    /* .socket_nonblock = */ ![](Fuzz_System *self, int sock, bool nonblock) { return 0; },
156
    /* .getsockopt = */
157
632
    ![](Fuzz_System *self, int sock, int level, int optname, void *optval, size_t *optlen) {
158
632
        std::memset(optval, 0, *optlen);
159
632
        return 0;
160
632
    },
161
    /* .setsockopt = */
162
2.53k
    ![](Fuzz_System *self, int sock, int level, int optname, const void *optval, size_t optlen) {
163
2.53k
        return 0;
164
2.53k
    },
165
};
166
167
static constexpr Random_Funcs fuzz_random_funcs = {
168
    /* .random_bytes = */
169
33.4k
    ![](Fuzz_System *self, uint8_t *bytes, size_t length) {
170
        // Amount of data is limited
171
33.4k
        const size_t bytes_read = std::min(length, self->data.size());
172
        // Initialize everything to make MSAN and others happy
173
33.4k
        std::memset(bytes, 0, length);
174
33.4k
        CONSUME_OR_ABORT(const uint8_t *data, self->data, bytes_read);
175
33.4k
        std::copy(data, data + bytes_read, bytes);
176
33.4k
        if (Fuzz_Data::DEBUG) {
177
0
            if (length == 1) {
178
0
                std::printf("rng: %d (0x%02x)\n", bytes[0], bytes[0]);
179
0
            } else {
180
0
                std::printf("rng: %02x..%02x[%zu]\n", bytes[0], bytes[length - 1], length);
181
0
            }
182
0
        }
183
33.4k
    },
184
    /* .random_uniform = */
185
0
    ![](Fuzz_System *self, uint32_t upper_bound) {
186
0
        uint32_t randnum = 0;
187
0
        if (upper_bound > 0) {
188
0
            self->rng->funcs->random_bytes(
189
0
                self, reinterpret_cast<uint8_t *>(&randnum), sizeof(randnum));
190
0
            randnum %= upper_bound;
191
0
        }
192
0
        return randnum;
193
0
    },
194
};
195
196
Fuzz_System::Fuzz_System(Fuzz_Data &input)
197
    : System{
198
        std::make_unique<Tox_System>(),
199
        std::make_unique<Memory>(Memory{&fuzz_memory_funcs, this}),
200
        std::make_unique<Network>(Network{&fuzz_network_funcs, this}),
201
        std::make_unique<Random>(Random{&fuzz_random_funcs, this}),
202
    }
203
    , data(input)
204
1.43k
{
205
127k
    sys->mono_time_callback = [](void *self) { return static_cast<Fuzz_System *>(self)->clock; };
206
1.43k
    sys->mono_time_user_data = this;
207
1.43k
    sys->mem = mem.get();
208
1.43k
    sys->ns = ns.get();
209
1.43k
    sys->rng = rng.get();
210
1.43k
}
211
212
static constexpr Memory_Funcs null_memory_funcs = {
213
    /* .malloc = */
214
126k
    ![](Null_System *self, uint32_t size) { return std::malloc(size); },
215
    /* .calloc = */
216
38.4k
    ![](Null_System *self, uint32_t nmemb, uint32_t size) { return std::calloc(nmemb, size); },
217
    /* .realloc = */
218
13.2k
    ![](Null_System *self, void *ptr, uint32_t size) { return std::realloc(ptr, size); },
219
    /* .free = */
220
174k
    ![](Null_System *self, void *ptr) { std::free(ptr); },
221
};
222
223
static constexpr Network_Funcs null_network_funcs = {
224
1.15k
    /* .close = */ ![](Null_System *self, int sock) { return 0; },
225
0
    /* .accept = */ ![](Null_System *self, int sock) { return 1337; },
226
1.15k
    /* .bind = */ ![](Null_System *self, int sock, const Network_Addr *addr) { return 0; },
227
0
    /* .listen = */ ![](Null_System *self, int sock, int backlog) { return 0; },
228
0
    /* .recvbuf = */ ![](Null_System *self, int sock) { return 0; },
229
    /* .recv = */
230
0
    ![](Null_System *self, int sock, uint8_t *buf, size_t len) {
231
        // Always fail.
232
0
        errno = ENOMEM;
233
0
        return -1;
234
0
    },
235
    /* .recvfrom = */
236
0
    ![](Null_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
237
        // Always fail.
238
0
        errno = ENOMEM;
239
0
        return -1;
240
0
    },
241
    /* .send = */
242
0
    ![](Null_System *self, int sock, const uint8_t *buf, size_t len) {
243
        // Always succeed.
244
0
        return static_cast<int>(len);
245
0
    },
246
    /* .sendto = */
247
0
    ![](Null_System *self, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
248
        // Always succeed.
249
0
        return static_cast<int>(len);
250
0
    },
251
1.15k
    /* .socket = */ ![](Null_System *self, int domain, int type, int proto) { return 42; },
252
1.15k
    /* .socket_nonblock = */ ![](Null_System *self, int sock, bool nonblock) { return 0; },
253
    /* .getsockopt = */
254
1.15k
    ![](Null_System *self, int sock, int level, int optname, void *optval, size_t *optlen) {
255
1.15k
        std::memset(optval, 0, *optlen);
256
1.15k
        return 0;
257
1.15k
    },
258
    /* .setsockopt = */
259
4.63k
    ![](Null_System *self, int sock, int level, int optname, const void *optval, size_t optlen) {
260
4.63k
        return 0;
261
4.63k
    },
262
};
263
264
static uint64_t simple_rng(uint64_t &seed)
265
453k
{
266
    // https://nuclear.llnl.gov/CNP/rng/rngman/node4.html
267
453k
    seed = 2862933555777941757LL * seed + 3037000493LL;
268
453k
    return seed;
269
453k
}
270
271
static constexpr Random_Funcs null_random_funcs = {
272
    /* .random_bytes = */
273
17.6k
    ![](Null_System *self, uint8_t *bytes, size_t length) {
274
471k
        for (size_t i = 0; i < length; ++i) {
275
453k
            bytes[i] = simple_rng(self->seed) & 0xff;
276
453k
        }
277
17.6k
    },
278
    /* .random_uniform = */
279
0
    ![](Null_System *self, uint32_t upper_bound) {
280
0
        return static_cast<uint32_t>(simple_rng(self->seed)) % upper_bound;
281
0
    },
282
};
283
284
Null_System::Null_System()
285
    : System{
286
        std::make_unique<Tox_System>(),
287
        std::make_unique<Memory>(Memory{&null_memory_funcs, this}),
288
        std::make_unique<Network>(Network{&null_network_funcs, this}),
289
        std::make_unique<Random>(Random{&null_random_funcs, this}),
290
    }
291
1.96k
{
292
1.96k
    sys->mono_time_callback = [](void *self) { return static_cast<Null_System *>(self)->clock; };
293
1.96k
    sys->mono_time_user_data = this;
294
1.96k
    sys->mem = mem.get();
295
1.96k
    sys->ns = ns.get();
296
1.96k
    sys->rng = rng.get();
297
1.96k
}
298
299
static uint16_t get_port(const Network_Addr *addr)
300
0
{
301
0
    if (addr->addr.ss_family == AF_INET6) {
302
0
        return reinterpret_cast<const sockaddr_in6 *>(&addr->addr)->sin6_port;
303
0
    } else {
304
0
        assert(addr->addr.ss_family == AF_INET);
305
0
        return reinterpret_cast<const sockaddr_in *>(&addr->addr)->sin_port;
306
0
    }
307
0
}
308
309
static constexpr Memory_Funcs record_memory_funcs = {
310
    /* .malloc = */
311
0
    ![](Record_System *self, uint32_t size) {
312
0
        self->push(true);
313
0
        return report_alloc(self->name_, "malloc", size, std::malloc(size));
314
0
    },
315
    /* .calloc = */
316
0
    ![](Record_System *self, uint32_t nmemb, uint32_t size) {
317
0
        self->push(true);
318
0
        return report_alloc(self->name_, "calloc", nmemb * size, std::calloc(nmemb, size));
319
0
    },
320
    /* .realloc = */
321
0
    ![](Record_System *self, void *ptr, uint32_t size) {
322
0
        self->push(true);
323
0
        return report_alloc(self->name_, "realloc", size, std::realloc(ptr, size));
324
0
    },
325
    /* .free = */
326
0
    ![](Record_System *self, void *ptr) { std::free(ptr); },
327
};
328
329
static constexpr Network_Funcs record_network_funcs = {
330
0
    /* .close = */ ![](Record_System *self, int sock) { return 0; },
331
0
    /* .accept = */ ![](Record_System *self, int sock) { return 2; },
332
    /* .bind = */
333
0
    ![](Record_System *self, int sock, const Network_Addr *addr) {
334
0
        const uint16_t port = get_port(addr);
335
0
        if (self->global_.bound.find(port) != self->global_.bound.end()) {
336
0
            errno = EADDRINUSE;
337
0
            return -1;
338
0
        }
339
0
        self->global_.bound.emplace(port, self);
340
0
        self->port = port;
341
0
        return 0;
342
0
    },
343
0
    /* .listen = */ ![](Record_System *self, int sock, int backlog) { return 0; },
344
0
    /* .recvbuf = */ ![](Record_System *self, int sock) { return 0; },
345
    /* .recv = */
346
0
    ![](Record_System *self, int sock, uint8_t *buf, size_t len) {
347
        // Always fail.
348
0
        errno = ENOMEM;
349
0
        return -1;
350
0
    },
351
    /* .recvfrom = */
352
0
    ![](Record_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
353
0
        assert(sock == 42);
354
0
        if (self->recvq.empty()) {
355
0
            self->push("\xff\xff");
356
0
            errno = EWOULDBLOCK;
357
0
            if (Fuzz_Data::DEBUG) {
358
0
                std::printf("%s: recvfrom: no data\n", self->name_);
359
0
            }
360
0
            return -1;
361
0
        }
362
0
        const auto [from, packet] = std::move(self->recvq.front());
363
0
        self->recvq.pop_front();
364
0
        const size_t recvlen = std::min(len, packet.size());
365
0
        std::copy(packet.begin(), packet.end(), buf);
366
367
0
        addr->addr = sockaddr_storage{};
368
        // Dummy Addr
369
0
        addr->addr.ss_family = AF_INET;
370
371
        // We want an AF_INET address with dummy values
372
0
        sockaddr_in *addr_in = reinterpret_cast<sockaddr_in *>(&addr->addr);
373
0
        addr_in->sin_port = from;
374
0
        addr_in->sin_addr.s_addr = htonl(0x7f000002);  // 127.0.0.2
375
0
        addr->size = sizeof(struct sockaddr);
376
377
0
        assert(recvlen > 0 && recvlen <= INT_MAX);
378
0
        self->push(uint8_t(recvlen >> 8));
379
0
        self->push(uint8_t(recvlen & 0xff));
380
0
        if (Fuzz_Data::DEBUG) {
381
0
            std::printf("%s: recvfrom: %zu (%02x, %02x)\n", self->name_, recvlen,
382
0
                self->recording().end()[-2], self->recording().end()[-1]);
383
0
        }
384
0
        self->push(buf, recvlen);
385
0
        return static_cast<int>(recvlen);
386
0
    },
387
    /* .send = */
388
0
    ![](Record_System *self, int sock, const uint8_t *buf, size_t len) {
389
        // Always succeed.
390
0
        return static_cast<int>(len);
391
0
    },
392
    /* .sendto = */
393
0
    ![](Record_System *self, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) {
394
0
        assert(sock == 42);
395
0
        auto backend = self->global_.bound.find(get_port(addr));
396
0
        assert(backend != self->global_.bound.end());
397
0
        backend->second->receive(self->port, buf, len);
398
0
        return static_cast<int>(len);
399
0
    },
400
0
    /* .socket = */ ![](Record_System *self, int domain, int type, int proto) { return 42; },
401
0
    /* .socket_nonblock = */ ![](Record_System *self, int sock, bool nonblock) { return 0; },
402
    /* .getsockopt = */
403
0
    ![](Record_System *self, int sock, int level, int optname, void *optval, size_t *optlen) {
404
0
        std::memset(optval, 0, *optlen);
405
0
        return 0;
406
0
    },
407
    /* .setsockopt = */
408
0
    ![](Record_System *self, int sock, int level, int optname, const void *optval, size_t optlen) {
409
0
        return 0;
410
0
    },
411
};
412
413
static constexpr Random_Funcs record_random_funcs = {
414
    /* .random_bytes = */
415
0
    ![](Record_System *self, uint8_t *bytes, size_t length) {
416
0
        for (size_t i = 0; i < length; ++i) {
417
0
            bytes[i] = simple_rng(self->seed_) & 0xff;
418
0
            self->push(bytes[i]);
419
0
        }
420
0
        if (Fuzz_Data::DEBUG) {
421
0
            std::printf(
422
0
                "%s: rng: %02x..%02x[%zu]\n", self->name_, bytes[0], bytes[length - 1], length);
423
0
        }
424
0
    },
425
    /* .random_uniform = */
426
    fuzz_random_funcs.random_uniform,
427
};
428
429
Record_System::Record_System(Global &global, uint64_t seed, const char *name)
430
    : System{
431
        std::make_unique<Tox_System>(),
432
        std::make_unique<Memory>(Memory{&record_memory_funcs, this}),
433
        std::make_unique<Network>(Network{&record_network_funcs, this}),
434
        std::make_unique<Random>(Random{&record_random_funcs, this}),
435
    }
436
    , global_(global)
437
    , seed_(seed)
438
    , name_(name)
439
0
{
440
0
    sys->mono_time_callback = [](void *self) { return static_cast<Record_System *>(self)->clock; };
441
0
    sys->mono_time_user_data = this;
442
0
    sys->mem = mem.get();
443
0
    sys->ns = ns.get();
444
0
    sys->rng = rng.get();
445
0
}
446
447
void Record_System::receive(uint16_t send_port, const uint8_t *buf, size_t len)
448
0
{
449
0
    assert(port != 0);
450
0
    recvq.emplace_back(send_port, std::vector<uint8_t>{buf, buf + len});
451
0
}