diff --git a/configure.ac b/configure.ac index 7975d31..528861c 100644 --- a/configure.ac +++ b/configure.ac @@ -4399,6 +4399,37 @@ AC_DEFINE_UNQUOTED([DYNAMIC_INTERLEAVE], [$ntp_dynamic_interleave], [support dynamic interleave?]) AC_MSG_RESULT([$ntp_ok]) +AC_ARG_ENABLE(fuzztargets, + AS_HELP_STRING([--enable-fuzztargets], [Enable fuzz targets]),[enable_fuzztargets=$enableval],[enable_fuzztargets=no]) +AM_CONDITIONAL([BUILD_FUZZTARGETS], [test "x$enable_fuzztargets" = "xyes"]) +AS_IF([test "x$enable_fuzztargets" = "xyes"], [ + AC_PROG_CXX + AC_LANG_PUSH(C++) + AS_IF([test "x$LIB_FUZZING_ENGINE" = "x"], [ + LIB_FUZZING_ENGINE=-fsanitize=fuzzer + AC_SUBST(LIB_FUZZING_ENGINE) + ]) + tmp_saved_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $LIB_FUZZING_ENGINE" + AC_MSG_CHECKING([whether $CXX accepts $LIB_FUZZING_ENGINE]) + AC_LINK_IFELSE([AC_LANG_SOURCE([[ +#include +extern "C" int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size); +extern "C" int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size) { +(void)Data; +(void)Size; +return 0; +} + ]])], + [ AC_MSG_RESULT(yes) + has_sanitizefuzzer=yes], + [ AC_MSG_RESULT(no) ] + ) + _AC_LANG_PREFIX[]FLAGS=$tmp_saved_flags, [] + AC_LANG_POP() +]) +AM_CONDITIONAL([HAS_SANITIZEFUZZER], [test "x$has_sanitizefuzzer" = "xyes"]) + NTP_UNITYBUILD dnl gtest is needed for our tests subdirs. It would be nice if we could @@ -4459,6 +4490,7 @@ AC_CONFIG_FILES([tests/ntpd/Makefile]) AC_CONFIG_FILES([tests/ntpq/Makefile]) AC_CONFIG_FILES([tests/sandbox/Makefile]) AC_CONFIG_FILES([tests/sec-2853/Makefile]) +AC_CONFIG_FILES([tests/fuzz/Makefile]) AC_CONFIG_FILES([util/Makefile]) perllibdir="${datadir}/ntp/lib" diff --git a/ntpd/ntp_io.c b/ntpd/ntp_io.c index 7c3fdd4..190a373 100644 --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@ -503,7 +503,11 @@ io_open_sockets(void) * Create the sockets */ BLOCKIO(); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + create_sockets(4123); +#else create_sockets(NTP_PORT); +#endif UNBLOCKIO(); init_async_notifications(); diff --git a/tests/Makefile.am b/tests/Makefile.am index af502b9..60a2379 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -10,3 +10,6 @@ SUBDIRS += \ sec-2853 \ $(NULL) +if BUILD_FUZZTARGETS + SUBDIRS += fuzz +endif diff --git a/tests/fuzz/Makefile.am b/tests/fuzz/Makefile.am new file mode 100644 index 0000000..7f482b5 --- /dev/null +++ b/tests/fuzz/Makefile.am @@ -0,0 +1,13 @@ +include $(top_srcdir)/includes.mf + +bin_PROGRAMS = fuzz_ntpd_receive + +fuzz_ntpd_receive_SOURCES = fuzz_ntpd_receive.c ../../ntpd/ntp_io.c ../../ntpd/ntp_config.c ../../ntpd/ntp_scanner.c ../../ntpd/ntp_parser.y ../../ntpd/ntpd-opts.c +fuzz_ntpd_receive_CFLAGS = $(NTP_INCS) -I../../sntp/libopts -I../../ntpd/ +fuzz_ntpd_receive_LDADD = ../../ntpd/libntpd.a $(LIBPARSE) ../../libntp/libntp.a $(LDADD_LIBNTP) $(LIBOPTS_LDADD) $(PTHREAD_LIBS) $(LIBM) $(LDADD_NTP) $(LSCF) $(LDADD_LIBUTIL) + +if HAS_SANITIZEFUZZER + fuzz_ntpd_receive_LDFLAGS = $(LIB_FUZZING_ENGINE) -lstdc++ -stdlib=libc++ +else + fuzz_ntpd_receive_SOURCES += onefile.c +endif diff --git a/tests/fuzz/fuzz_ntpd_receive.c b/tests/fuzz/fuzz_ntpd_receive.c new file mode 100644 index 0000000..7cb8d99 --- /dev/null +++ b/tests/fuzz/fuzz_ntpd_receive.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include + +#include "config.h" +#include "recvbuff.h" +#include "ntpd.h" + +const char *Version = "libntpq 0.3beta"; +int listen_to_virtual_ips = TRUE; +int mdnstries = 5; +char const *progname = "fuzz_ntpd_receive"; +#ifdef HAVE_WORKING_FORK +int waitsync_fd_to_close = -1; /* -w/--wait-sync */ +#endif +int yydebug=0; + +static int initialized = 0; +int sockfd; +uint8_t itf_index; + +void fuzz_itf_selecter(void * data, interface_info_t * itf) { + endpt **ep = (endpt **)data; + if (itf_index == 0) { + *ep = itf->ep; + } + itf_index--; +} + +int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + struct recvbuf rbufp; + + if (initialized == 0) { + sockfd = open("/dev/null", O_RDWR ); + //adds interfaces + init_io(); + init_auth(); + init_util(); + init_restrict(); + init_mon(); + init_timer(); + init_lib(); + init_request(); + init_control(); + init_peer(); + init_proto(); + init_loopfilter(); + io_open_sockets(); + initialized = 1; + } + + if (Size < sizeof(l_fp)) { + return 0; + } + memcpy(&rbufp.recv_time, Data, sizeof(l_fp)); + Data += sizeof(l_fp); + Size -= sizeof(l_fp); + + if (Size < sizeof(sockaddr_u)) { + return 0; + } + memcpy(&rbufp.srcadr, Data, sizeof(sockaddr_u)); + memcpy(&rbufp.recv_srcadr, &rbufp.srcadr, sizeof(sockaddr_u)); + Data += sizeof(sockaddr_u); + Size -= sizeof(sockaddr_u); + + if (Size < 1) { + return 0; + } + itf_index = Data[0]; + rbufp.dstadr = NULL; + interface_enumerate(fuzz_itf_selecter, &rbufp.dstadr); + if (rbufp.dstadr == NULL) { + return 0; + } + Data++; + Size--; + + if (Size > RX_BUFF_SIZE) { + Size = RX_BUFF_SIZE; + } + rbufp.recv_length = Size; + memcpy(rbufp.recv_buffer, Data, Size); + + rbufp.msg_flags = 0; + rbufp.used = 0; + rbufp.link = NULL; + rbufp.fd = sockfd; + + receive(&rbufp); + return 0; +} diff --git a/tests/fuzz/onefile.c b/tests/fuzz/onefile.c new file mode 100644 index 0000000..74be306 --- /dev/null +++ b/tests/fuzz/onefile.c @@ -0,0 +1,51 @@ +#include +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +int main(int argc, char** argv) +{ + FILE * fp; + uint8_t *Data; + size_t Size; + + if (argc != 2) { + return 1; + } + //opens the file, get its size, and reads it into a buffer + fp = fopen(argv[1], "rb"); + if (fp == NULL) { + return 2; + } + if (fseek(fp, 0L, SEEK_END) != 0) { + fclose(fp); + return 2; + } + Size = ftell(fp); + if (Size == (size_t) -1) { + fclose(fp); + return 2; + } + if (fseek(fp, 0L, SEEK_SET) != 0) { + fclose(fp); + return 2; + } + Data = malloc(Size); + if (Data == NULL) { + fclose(fp); + return 2; + } + if (fread(Data, Size, 1, fp) != 1) { + fclose(fp); + free(Data); + return 2; + } + + //lauch fuzzer + LLVMFuzzerTestOneInput(Data, Size); + free(Data); + fclose(fp); + return 0; +} +