1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
| | // SPDX-License-Identifier: GPL-2.0-or-later
/* fuzz.c - AFL++ fuzzing support: deterministic wrappers for
* clock_gettime() and getsockopt()
*
* Copyright Red Hat
* Author: Anshu Kumari <anskuma@redhat.com>
*/
#include <string.h>
#include <time.h>
#include <errno.h>
#include <netinet/tcp.h>
#include "passt.h"
#include "fuzz.h"
/* Undo macros so definitions here call the real syscalls */
#undef clock_gettime
#undef getsockopt
#define FUZZ_CLOCK_BASE_SEC 10000
static struct timespec fuzz_clock;
/**
* fuzz_clock_reset() - Reset clock to fixed baseline
*
* Called at the start of every __AFL_LOOP iteration so
* the clock is identical regardless of iteration number.
*/
void fuzz_clock_reset(void)
{
fuzz_clock.tv_sec = FUZZ_CLOCK_BASE_SEC;
fuzz_clock.tv_nsec = 0;
}
/**
* fuzz_clock_gettime() - Return deterministic time
* @clk: Clock ID
* @tp: Output timespec
*
* Return: 0 (always succeeds)
*/
int fuzz_clock_gettime(clockid_t clk, struct timespec *tp)
{
(void)clk;
*tp = fuzz_clock;
/* increment the timestamp by 1 micro sec monotonically */
fuzz_clock.tv_nsec += 1000;
if (fuzz_clock.tv_nsec >= 1000000000) {
fuzz_clock.tv_sec++;
fuzz_clock.tv_nsec -= 1000000000;
}
return 0;
}
/**
* fuzz_getsockopt() - Deterministic getsockopt wrapper
* @fd: Socket file descriptor
* @level: Protocol level
* @optname: Option name
* @optval: Output buffer
* @optlen: In/out option length
*
* For TCP_INFO: populates optval from the AFL++ shared memory buffer.
* For SO_RCVBUF, SO_SNDBUF: returns deterministic values.
*
* Return: 0 on success, -1 on error
*/
int fuzz_getsockopt(int fd, int level, int optname, void *optval,
socklen_t *optlen)
{
if (level == SOL_SOCKET) {
if (optname == SO_RCVBUF || optname == SO_SNDBUF) {
*(int *)optval = 212992; /* default linux buff size */
*optlen = sizeof(int);
return 0;
}
}
if (level == SOL_TCP && optname == TCP_INFO) {
size_t fill = *optlen;
size_t copy_len;
memset(optval, 0, fill);
if (fuzz_sockopt_data && fuzz_sockopt_data_len > 0) {
copy_len = MIN(fill, (size_t)fuzz_sockopt_data_len);
memcpy(optval, fuzz_sockopt_data, copy_len);
fuzz_sockopt_data += copy_len;
fuzz_sockopt_data_len -= copy_len;
*optlen = copy_len;
} else {
*optlen = 0;
}
return 0;
}
return getsockopt(fd, level, optname, optval, optlen);
}
|