// 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 */ #include #include #include #include #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); }