blob: 1d7786ceec490a1bb89618665608ae8db74e3ffe [file] [log] [blame]
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 <sys/types.h>
+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 <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#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 <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+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;
+}
+