AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/suricata.c])
AC_CONFIG_MACRO_DIR(m4)
- AM_INIT_AUTOMAKE([tar-ustar])
+ AM_INIT_AUTOMAKE([tar-ustar subdir-objects])
AC_LANG([C])
AC_PROG_CC_C99
# options
+
+ 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"])
+ AC_PROG_CXX
+ AS_IF([test "x$enable_fuzztargets" = "xyes"], [
+ AC_DEFINE([AFLFUZZ_NO_RANDOM], [1], [Disable all use of random functions])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[while (__AFL_LOOP(1000))]])],
+ [AC_DEFINE([AFLFUZZ_PERSISTANT_MODE], [1], [Enable AFL PERSISTANT_MODE])],
+ [])
+ AC_LANG_PUSH(C++)
+ tmp_saved_flags=$[]_AC_LANG_PREFIX[]FLAGS
+ AS_IF([test "x$LIB_FUZZING_ENGINE" = "x"], [
+ LIB_FUZZING_ENGINE=-fsanitize=fuzzer
+ AC_SUBST(LIB_FUZZING_ENGINE)
+ ])
+ _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_FUZZLDFLAGS], [test "x$has_sanitizefuzzer" = "xyes"])
+
# enable the running of unit tests
AC_ARG_ENABLE(unittests,
AS_HELP_STRING([--enable-unittests], [Enable compilation of the unit tests]),[enable_unittests=$enableval],[enable_unittests=no])
+ AS_IF([test "x$enable_fuzztargets" = "xyes"], [
+ export enable_unittests="yes"
+ ])
AS_IF([test "x$enable_unittests" = "xyes"], [
AC_DEFINE([UNITTESTS],[1],[Enable built-in unittests])
])
suricata-common.h threadvars.h tree.h \
util-validate.h
bin_PROGRAMS = suricata
+if BUILD_FUZZTARGETS
+ bin_PROGRAMS += fuzz_applayerprotodetectgetproto \
+ fuzz_applayerparserparse fuzz_siginit \
+ fuzz_confyamlloadstring fuzz_decodepcapfile \
+ fuzz_sigpcap fuzz_mimedecparseline fuzz_decodeder
+endif
-suricata_SOURCES = \
+COMMON_SOURCES = \
alert-debuglog.c alert-debuglog.h \
alert-fastlog.c alert-fastlog.h \
alert-prelude.c alert-prelude.h \
log-tcp-data.c log-tcp-data.h \
log-tlslog.c log-tlslog.h \
log-tlsstore.c log-tlsstore.h \
-main.c \
output.c output.h \
output-file.c output-file.h \
output-filedata.c output-filedata.h \
# set the include path found by configure
AM_CPPFLAGS = $(all_includes)
+suricata_SOURCES = main.c $(COMMON_SOURCES)
+
# the library search path.
suricata_LDFLAGS = $(all_libraries) ${SECLDFLAGS}
suricata_LDADD = $(HTP_LDADD) $(RUST_LDADD)
suricata_DEPENDENCIES = $(RUST_SURICATA_LIB)
+nodist_fuzz_applayerprotodetectgetproto_SOURCES = tests/fuzz/fuzz_applayerprotodetectgetproto.c $(COMMON_SOURCES)
+fuzz_applayerprotodetectgetproto_LDFLAGS = $(all_libraries) ${SECLDFLAGS}
+fuzz_applayerprotodetectgetproto_LDADD = $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD)
+if HAS_FUZZLDFLAGS
+ fuzz_applayerprotodetectgetproto_LDFLAGS += $(LIB_FUZZING_ENGINE)
+else
+ nodist_fuzz_applayerprotodetectgetproto_SOURCES += tests/fuzz/onefile.c
+endif
+# force usage of CXX for linker
+fuzz_applayerprotodetectgetproto_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(fuzz_applayerprotodetectgetproto_LDFLAGS) $(LDFLAGS) -o $@
+
+nodist_fuzz_applayerparserparse_SOURCES = tests/fuzz/fuzz_applayerparserparse.c $(COMMON_SOURCES)
+fuzz_applayerparserparse_LDFLAGS = $(all_libraries) ${SECLDFLAGS}
+fuzz_applayerparserparse_LDADD = $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD)
+if HAS_FUZZLDFLAGS
+ fuzz_applayerparserparse_LDFLAGS += $(LIB_FUZZING_ENGINE)
+else
+ nodist_fuzz_applayerparserparse_SOURCES += tests/fuzz/onefile.c
+endif
+fuzz_applayerparserparse_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(fuzz_applayerparserparse_LDFLAGS) $(LDFLAGS) -o $@
+
+nodist_fuzz_siginit_SOURCES = tests/fuzz/fuzz_siginit.c $(COMMON_SOURCES)
+fuzz_siginit_LDFLAGS = $(all_libraries) ${SECLDFLAGS}
+fuzz_siginit_LDADD = $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD)
+if HAS_FUZZLDFLAGS
+ fuzz_siginit_LDFLAGS += $(LIB_FUZZING_ENGINE)
+else
+ nodist_fuzz_siginit_SOURCES += tests/fuzz/onefile.c
+endif
+# force usage of CXX for linker
+fuzz_siginit_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(fuzz_siginit_LDFLAGS) $(LDFLAGS) -o $@
+
+nodist_fuzz_confyamlloadstring_SOURCES = tests/fuzz/fuzz_confyamlloadstring.c $(COMMON_SOURCES)
+fuzz_confyamlloadstring_LDFLAGS = $(all_libraries) ${SECLDFLAGS}
+fuzz_confyamlloadstring_LDADD = $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD)
+if HAS_FUZZLDFLAGS
+ fuzz_confyamlloadstring_LDFLAGS += $(LIB_FUZZING_ENGINE)
+else
+ nodist_fuzz_confyamlloadstring_SOURCES += tests/fuzz/onefile.c
+endif
+# force usage of CXX for linker
+fuzz_confyamlloadstring_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(fuzz_confyamlloadstring_LDFLAGS) $(LDFLAGS) -o $@
+
+nodist_fuzz_decodepcapfile_SOURCES = tests/fuzz/fuzz_decodepcapfile.c $(COMMON_SOURCES)
+fuzz_decodepcapfile_LDFLAGS = $(all_libraries) ${SECLDFLAGS}
+fuzz_decodepcapfile_LDADD = $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD)
+if HAS_FUZZLDFLAGS
+ fuzz_decodepcapfile_LDFLAGS += $(LIB_FUZZING_ENGINE)
+else
+ nodist_fuzz_decodepcapfile_SOURCES += tests/fuzz/onefile.c
+endif
+# force usage of CXX for linker
+fuzz_decodepcapfile_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(fuzz_decodepcapfile_LDFLAGS) $(LDFLAGS) -o $@
+
+nodist_fuzz_sigpcap_SOURCES = tests/fuzz/fuzz_sigpcap.c $(COMMON_SOURCES)
+fuzz_sigpcap_LDFLAGS = $(all_libraries) ${SECLDFLAGS}
+fuzz_sigpcap_LDADD = $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD)
+if HAS_FUZZLDFLAGS
+ fuzz_sigpcap_LDFLAGS += $(LIB_FUZZING_ENGINE)
+else
+ nodist_fuzz_sigpcap_SOURCES += tests/fuzz/onefile.c
+endif
+# force usage of CXX for linker
+fuzz_sigpcap_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(fuzz_sigpcap_LDFLAGS) $(LDFLAGS) -o $@
+
+nodist_fuzz_mimedecparseline_SOURCES = tests/fuzz/fuzz_mimedecparseline.c $(COMMON_SOURCES)
+fuzz_mimedecparseline_LDFLAGS = $(all_libraries) ${SECLDFLAGS}
+fuzz_mimedecparseline_LDADD = $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD)
+if HAS_FUZZLDFLAGS
+ fuzz_mimedecparseline_LDFLAGS += $(LIB_FUZZING_ENGINE)
+else
+ nodist_fuzz_mimedecparseline_SOURCES += tests/fuzz/onefile.c
+endif
+# force usage of CXX for linker
+fuzz_mimedecparseline_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(fuzz_mimedecparseline_LDFLAGS) $(LDFLAGS) -o $@
+
+nodist_fuzz_decodeder_SOURCES = tests/fuzz/fuzz_decodeder.c $(COMMON_SOURCES)
+fuzz_decodeder_LDFLAGS = $(all_libraries) ${SECLDFLAGS}
+fuzz_decodeder_LDADD = $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD)
+if HAS_FUZZLDFLAGS
+ fuzz_decodeder_LDFLAGS += $(LIB_FUZZING_ENGINE)
+else
+ nodist_fuzz_decodeder_SOURCES += tests/fuzz/onefile.c
+endif
+# force usage of CXX for linker
+fuzz_decodeder_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(fuzz_decodeder_LDFLAGS) $(LDFLAGS) -o $@
+
# default CFLAGS
AM_CFLAGS = ${OPTIMIZATION_CFLAGS} ${GCC_CFLAGS} ${CLANG_CFLAGS} \
${SECCFLAGS} ${PCAP_CFLAGS} -DLOCAL_STATE_DIR=\"$(localstatedir)\" \
--- /dev/null
+How to run fuzzing ?
+
+1) With oss-fuzz
+- install docker
+- run git clone --branch suricata --depth 1 https://github.com/catenacyber/oss-fuzz
+(we will use the original google repo once we merge this)
+- change directory into cloned repository : cd oss-fuzz
+- run python infra/helper.py build_image suricata
+- run python infra/helper.py build_fuzzers --sanitizer address suricata
+You can use undefined sanitizer (memory sanitizer does not work yet see https://github.com/google/oss-fuzz/issues/2145#issuecomment-485781098
+- run python infra/helper.py run_fuzzer suricata fuzz_siginit
+(or another fuzz target, try ls build/out/suricata/fuzz_*)
+
+To generate coverage :
+- run python infra/helper.py build_fuzzers --sanitizer=coverage suricata
+- get a corpus cf https://github.com/google/oss-fuzz/issues/2490
+- put your corpus in build/corpus/suricata/<fuzz_target_name>/
+- run python infra/helper.py coverage --no-corpus-download suricata
+
+2) With libfuzzer
+
+To compile the fuzz targets, you should do the following :
+```
+export CFLAGS="-g -fsanitize=address,fuzzer-no-link"
+export LDFLAGS="-g -fsanitize=address"
+export CC=clang
+./configure --enable-fuzztargets
+make
+```
+
+You can specify other sanitizers here such as undefined and memory
+
+Then you can run a target :
+./src/.libs/fuzz_target_x your_libfuzzer_options
+Where target_x is on file in `ls ./src/.libs/fuzz_*`
+
+If your clang does not support the compile flag "-fsanitize=fuzzer" (MacOS), you can run these same commands but you need first to install libfuzzer as libFuzzingEngine and you need to add `export LIB_FUZZING_ENGINE=/path/to/libFuzzer.a` before calling configure command
+
+To compile libFuzzer, you can do the following
+```
+svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer
+cd fuzzer
+./build.sh
+```
+
+
+3) With afl
+
+To compile the fuzz targets, you simply need to run
+```
+CC=afl-gcc ./configure --enable-fuzztargets
+CC=afl-gcc make
+```
+You can rather use afl-clang if needed.
+
+Then you can run afl as usual with each of the fuzz targets in ./src/.libs/
+afl-fuzz your_afl_options -- ./src/.libs/fuzz_target_x @@
--- /dev/null
+/**
+ * @file
+ * @author Philippe Antoine <contact@catenacyber.fr>
+ * fuzz target for AppLayerProtoDetectGetProto
+ */
+
+
+#include "suricata-common.h"
+#include "app-layer-detect-proto.h"
+#include "flow-util.h"
+#include "app-layer-parser.h"
+#include "util-unittest-helper.h"
+
+#define HEADER_LEN 6
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+AppLayerParserThreadCtx *alp_tctx = NULL;
+
+/* input buffer is structured this way :
+ * 6 bytes header,
+ * then sequence of buffers separated by magic bytes 01 D5 CA 7A */
+
+/* The 6 bytes header is
+ * alproto
+ * proto
+ * source port (uint16_t)
+ * destination port (uint16_t) */
+
+const uint8_t separator[] = {0x01, 0xD5, 0xCA, 0x7A};
+SCInstance suricata;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ Flow * f;
+ TcpSession ssn;
+ const uint8_t * albuffer;
+ uint8_t * alnext;
+ size_t alsize;
+ // used to find under and overflows
+ // otherwise overflows do not fail as they read the next packet
+ uint8_t * isolatedBuffer;
+
+ if (size < HEADER_LEN) {
+ return 0;
+ }
+
+ if (alp_tctx == NULL) {
+ //Redirects logs to /dev/null
+ setenv("SC_LOG_OP_IFACE", "file", 0);
+ setenv("SC_LOG_FILE", "/dev/null", 0);
+
+ InitGlobal();
+ run_mode = RUNMODE_PCAP_FILE;
+ GlobalsInitPreConfig();
+
+ //redirect logs to /tmp
+ ConfigSetLogDirectory("/tmp/");
+
+ PostConfLoadedSetup(&suricata);
+ alp_tctx = AppLayerParserThreadCtxAlloc();
+ }
+
+ if (data[0] >= ALPROTO_MAX) {
+ return 0;
+ }
+ //no UTHBuildFlow to have storage
+ f = FlowAlloc();
+ if (f == NULL) {
+ return 0;
+ }
+ f->flags |= FLOW_IPV4;
+ f->src.addr_data32[0] = 0x01020304;
+ f->dst.addr_data32[0] = 0x05060708;
+ f->sp = (data[2] << 8) | data[3];
+ f->dp = (data[4] << 8) | data[5];
+ f->proto = data[1];
+ memset(&ssn, 0, sizeof(TcpSession));
+ f->protoctx = &ssn;
+ f->protomap = FlowGetProtoMapping(f->proto);
+ f->alproto = data[0];
+
+ /*
+ * We want to fuzz multiple calls to AppLayerParserParse
+ * because some parts of the code are only reached after
+ * multiple packets (in SMTP for example).
+ * So we treat our input as a list of buffers with magic separator.
+ */
+ albuffer = data + HEADER_LEN;
+ alsize = size - HEADER_LEN;
+ uint8_t flags = STREAM_START;
+ int flip = 0;
+ alnext = memmem(albuffer, alsize, separator, 4);
+ while (alnext) {
+ if (flip) {
+ flags |= STREAM_TOCLIENT;
+ flags &= ~(STREAM_TOSERVER);
+ flip = 0;
+ } else {
+ flags |= STREAM_TOSERVER;
+ flags &= ~(STREAM_TOCLIENT);
+ flip = 1;
+ }
+
+ if (alnext != albuffer) {
+ // only if we have some data
+ isolatedBuffer = malloc(alnext - albuffer);
+ if (isolatedBuffer == NULL) {
+ return 0;
+ }
+ memcpy(isolatedBuffer, albuffer, alnext - albuffer);
+ (void) AppLayerParserParse(NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, alnext - albuffer);
+ free(isolatedBuffer);
+ flags &= ~(STREAM_START);
+ }
+ alsize -= alnext - albuffer + 4;
+ albuffer = alnext + 4;
+ if (alsize == 0) {
+ break;
+ }
+ alnext = memmem(albuffer, alsize, separator, 4);
+ }
+ if (alsize > 0 ) {
+ flags |= STREAM_EOF;
+ isolatedBuffer = malloc(alsize);
+ if (isolatedBuffer == NULL) {
+ return 0;
+ }
+ memcpy(isolatedBuffer, albuffer, alsize);
+ (void) AppLayerParserParse(NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, alsize);
+ free(isolatedBuffer);
+ }
+
+ FlowFree(f);
+
+ return 0;
+}
--- /dev/null
+/**
+ * @file
+ * @author Philippe Antoine <contact@catenacyber.fr>
+ * fuzz target for AppLayerProtoDetectGetProto
+ */
+
+
+#include "suricata-common.h"
+#include "app-layer-detect-proto.h"
+#include "flow-util.h"
+#include "app-layer-parser.h"
+#include "util-unittest-helper.h"
+
+
+#define HEADER_LEN 6
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+AppLayerProtoDetectThreadCtx *alpd_tctx = NULL;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ Flow *f;
+ TcpSession ssn;
+ bool reverse;
+
+ if (size < HEADER_LEN) {
+ return 0;
+ }
+
+ if (alpd_tctx == NULL) {
+ //global init
+ InitGlobal();
+ run_mode = RUNMODE_UNITTEST;
+ MpmTableSetup();
+ SpmTableSetup();
+ AppLayerProtoDetectSetup();
+ AppLayerParserSetup();
+ AppLayerParserRegisterProtocolParsers();
+ alpd_tctx = AppLayerProtoDetectGetCtxThread();
+ }
+
+ f = UTHBuildFlow(AF_INET, "1.2.3.4", "5.6.7.8", (data[2] << 8) | data[3], (data[4] << 8) | data[5]);
+ if (f == NULL) {
+ return 0;
+ }
+ f->proto = data[1];
+ memset(&ssn, 0, sizeof(TcpSession));
+ f->protoctx = &ssn;
+ f->protomap = FlowGetProtoMapping(f->proto);
+
+ AppLayerProtoDetectGetProto(alpd_tctx, f, data+HEADER_LEN, size-HEADER_LEN, f->proto, data[0], &reverse);
+ UTHFreeFlow(f);
+
+ return 0;
+}
--- /dev/null
+/**
+ * @file
+ * @author Philippe Antoine <contact@catenacyber.fr>
+ * fuzz target for ConfYamlLoadString
+ */
+
+
+#include "suricata-common.h"
+#include "conf-yaml-loader.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static int initialized = 0;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (initialized == 0) {
+ //Redirects logs to /dev/null
+ setenv("SC_LOG_OP_IFACE", "file", 0);
+ setenv("SC_LOG_FILE", "/dev/null", 0);
+ //global init
+ InitGlobal();
+ run_mode = RUNMODE_UNITTEST;
+ initialized = 1;
+ }
+
+ ConfYamlLoadString((const char *) data, size);
+
+ return 0;
+}
--- /dev/null
+/**
+ * @file
+ * @author Philippe Antoine <contact@catenacyber.fr>
+ * fuzz target for DecodeDer
+ */
+
+
+#include "suricata-common.h"
+#include "util-decode-der.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static int initialized = 0;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (initialized == 0) {
+ //Redirects logs to /dev/null
+ setenv("SC_LOG_OP_IFACE", "file", 0);
+ setenv("SC_LOG_FILE", "/dev/null", 0);
+ //global init
+ InitGlobal();
+ run_mode = RUNMODE_UNITTEST;
+ initialized = 1;
+ }
+ uint32_t errcode = 0;
+
+ Asn1Generic *a = DecodeDer(data, size, &errcode);
+ DerFree(a);
+
+ return 0;
+}
--- /dev/null
+/**
+ * @file
+ * @author Philippe Antoine <contact@catenacyber.fr>
+ * fuzz target for AppLayerProtoDetectGetProto
+ */
+
+
+#include <pcap/pcap.h>
+
+#include "suricata-common.h"
+#include "app-layer-detect-proto.h"
+#include "defrag.h"
+#include "tm-modules.h"
+#include "tm-threads.h"
+#include "source-pcap-file.h"
+#include "util-unittest-helper.h"
+#include "conf-yaml-loader.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static int initialized = 0;
+SCInstance suricata;
+
+const char configNoChecksum[] = "\
+%YAML 1.1\n\
+---\n\
+pcap-file:\n\
+\n\
+ checksum-checks: no\n\
+";
+
+ThreadVars *tv;
+DecodeThreadVars *dtv;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ void *ptv = NULL;
+
+ if (initialized == 0) {
+ //Redirects logs to /dev/null
+ setenv("SC_LOG_OP_IFACE", "file", 0);
+ setenv("SC_LOG_FILE", "/dev/null", 0);
+
+ InitGlobal();
+ run_mode = RUNMODE_PCAP_FILE;
+
+ //redirect logs to /tmp
+ ConfigSetLogDirectory("/tmp/");
+ //disables checksums validation for fuzzing
+ if (ConfYamlLoadString(configNoChecksum, strlen(configNoChecksum)) != 0) {
+ abort();
+ }
+
+ PostConfLoadedSetup(&suricata);
+
+ RunModeInitialize();
+ TimeModeSetOffline();
+ PcapFileGlobalInit();
+
+ tv = TmThreadCreatePacketHandler("fuzz",
+ "packetpool", "packetpool",
+ "packetpool", "packetpool",
+ "pktacqloop");
+ if (tv == NULL) {
+ return 0;
+ }
+ TmModule *tm_module = TmModuleGetByName("ReceivePcapFile");
+ if (tm_module == NULL) {
+ return 0;
+ }
+ TmSlotSetFuncAppend(tv, tm_module, "/tmp/fuzz.pcap");
+ tm_module = TmModuleGetByName("DecodePcapFile");
+ if (tm_module == NULL) {
+ return 0;
+ }
+ TmSlotSetFuncAppend(tv, tm_module, NULL);
+ tmm_modules[TMM_DECODEPCAPFILE].ThreadInit(tv, NULL, (void **) &dtv);
+ (void)SC_ATOMIC_SET(tv->tm_slots->slot_next->slot_data, dtv);
+
+ PacketPoolInit();
+
+ initialized = 1;
+ }
+
+ //rewrite buffer to a file as libpcap does not have buffer inputs
+ if (UTHbufferToFile("/tmp/fuzz.pcap", data, size) < 0) {
+ return 0;
+ }
+
+ if (tmm_modules[TMM_RECEIVEPCAPFILE].ThreadInit(tv, "/tmp/fuzz.pcap", &ptv) == TM_ECODE_OK && ptv != NULL) {
+ suricata_ctl_flags = 0;
+ tmm_modules[TMM_RECEIVEPCAPFILE].PktAcqLoop(tv, ptv, tv->tm_slots);
+ tmm_modules[TMM_RECEIVEPCAPFILE].ThreadDeinit(tv, ptv);
+ }
+
+ return 0;
+}
--- /dev/null
+/**
+ * @file
+ * @author Philippe Antoine <contact@catenacyber.fr>
+ * fuzz target for ConfYamlLoadString
+ */
+
+
+#include "suricata-common.h"
+#include "util-decode-mime.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static int initialized = 0;
+static int dummy = 0;
+
+static int MimeParserDataFromFileCB(const uint8_t *chunk, uint32_t len,
+ MimeDecParseState *state)
+{
+ if (len > 0 && chunk[len-1] == 0) {
+ // do not get optimizd away
+ dummy++;
+ }
+ return MIME_DEC_OK;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (initialized == 0) {
+ //Redirects logs to /dev/null
+ setenv("SC_LOG_OP_IFACE", "file", 0);
+ setenv("SC_LOG_FILE", "/dev/null", 0);
+ //global init
+ InitGlobal();
+ run_mode = RUNMODE_UNITTEST;
+ initialized = 1;
+ }
+
+ uint32_t line_count = 0;
+
+ MimeDecParseState *state = MimeDecInitParser(&line_count, MimeParserDataFromFileCB);
+ MimeDecEntity *msg_head = state->msg;
+ const uint8_t * buffer = data;
+ while (1) {
+ uint8_t * next = memchr(buffer, '\n', size);
+ if (next == NULL) {
+ (void) MimeDecParseLine(buffer, size, 1, state);
+ break;
+ } else {
+ (void) MimeDecParseLine(buffer, next - buffer, 1, state);
+ if (buffer + size < next + 1) {
+ break;
+ }
+ size -= next - buffer + 1;
+ buffer = next + 1;
+ }
+ }
+ /* Completed */
+ (void)MimeDecParseComplete(state);
+ /* De Init parser */
+ MimeDecDeInitParser(state);
+ MimeDecFreeEntity(msg_head);
+
+ return 0;
+}
--- /dev/null
+/**
+ * @file
+ * @author Philippe Antoine <contact@catenacyber.fr>
+ * fuzz target for SigInit
+ */
+
+
+#include "suricata-common.h"
+#include "util-reference-config.h"
+#include "util-classification-config.h"
+#include "detect-engine.h"
+#include "detect-parse.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+DetectEngineCtx *de_ctx = NULL;
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (de_ctx == NULL) {
+ setenv("SC_LOG_OP_IFACE", "file", 0);
+ setenv("SC_LOG_FILE", "/dev/null", 0);
+ //global init
+ InitGlobal();
+ run_mode = RUNMODE_UNITTEST;
+ MpmTableSetup();
+ SpmTableSetup();
+ SigTableSetup();
+ SCReferenceConfInit();
+ SCClassConfInit();
+ de_ctx = DetectEngineCtxInit();
+ }
+
+ char * buffer = malloc(size+1);
+ if (buffer) {
+ memcpy(buffer, data, size);
+ //null terminate string
+ buffer[size] = 0;
+ Signature *s = SigInit(de_ctx, buffer);
+ free(buffer);
+ SigFree(s);
+ }
+
+ return 0;
+}
--- /dev/null
+/**
+ * @file
+ * @author Philippe Antoine <contact@catenacyber.fr>
+ * fuzz target for AppLayerProtoDetectGetProto
+ */
+
+
+#include <pcap/pcap.h>
+
+#include "suricata-common.h"
+#include "source-pcap-file.h"
+#include "detect-engine.h"
+#include "util-classification-config.h"
+#include "util-reference-config.h"
+#include "app-layer.h"
+#include "tm-queuehandlers.h"
+#include "util-cidr.h"
+#include "util-proto-name.h"
+#include "detect-engine-tag.h"
+#include "detect-engine-threshold.h"
+#include "host-bit.h"
+#include "ippair-bit.h"
+#include "app-layer-htp.h"
+#include "util-decode-asn1.h"
+#include "detect-fast-pattern.h"
+#include "util-unittest-helper.h"
+#include "conf-yaml-loader.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+
+static int initialized = 0;
+ThreadVars tv;
+DecodeThreadVars *dtv;
+//FlowWorkerThreadData
+void *fwd;
+SCInstance suricata;
+
+const char configNoChecksum[] = "\
+%YAML 1.1\n\
+---\n\
+pcap-file:\n\
+\n\
+ checksum-checks: no\n\
+\n\
+stream:\n\
+\n\
+ checksum-validation: no\n\
+";
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ pcap_t * pkts;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ const u_char *pkt;
+ struct pcap_pkthdr *header;
+ int r;
+ Packet *p;
+ size_t pos;
+
+ if (initialized == 0) {
+ //Redirects logs to /dev/null
+ setenv("SC_LOG_OP_IFACE", "file", 0);
+ setenv("SC_LOG_FILE", "/dev/null", 0);
+
+ InitGlobal();
+
+ run_mode = RUNMODE_PCAP_FILE;
+ //redirect logs to /tmp
+ ConfigSetLogDirectory("/tmp/");
+ //disables checksums validation for fuzzing
+ if (ConfYamlLoadString(configNoChecksum, strlen(configNoChecksum)) != 0) {
+ abort();
+ }
+ suricata.sig_file = strdup("/tmp/fuzz.rules");
+ suricata.sig_file_exclusive = 1;
+ //loads rules after init
+ suricata.delayed_detect = 1;
+
+ SupportFastPatternForSigMatchTypes();
+ PostConfLoadedSetup(&suricata);
+
+ //dummy init before DetectEngineReload
+ DetectEngineCtx * de_ctx = DetectEngineCtxInit();
+ de_ctx->flags |= DE_QUIET;
+ DetectEngineAddToMaster(de_ctx);
+
+ memset(&tv, 0, sizeof(tv));
+ dtv = DecodeThreadVarsAlloc(&tv);
+ DecodeRegisterPerfCounters(dtv, &tv);
+ tmm_modules[TMM_FLOWWORKER].ThreadInit(&tv, NULL, &fwd);
+ StatsSetupPrivate(&tv);
+
+ initialized = 1;
+ }
+
+ /* TODO add yaml config
+ for (pos = 0; pos < size; pos++) {
+ if (data[pos] == 0) {
+ break;
+ }
+ }
+ if (ConfYamlLoadString(data, pos) != 0) {
+ return 0;
+ }
+ if (pos < size) {
+ //skip zero
+ pos++;
+ }
+ data += pos;
+ size -= pos;*/
+
+ for (pos=0; pos < size; pos++) {
+ if (data[pos] == 0) {
+ break;
+ }
+ }
+ if (pos > 0 && pos < size) {
+ // dump signatures to a file so as to reuse SigLoadSignatures
+ if (UTHbufferToFile(suricata.sig_file, data, pos-1) < 0) {
+ return 0;
+ }
+ } else {
+ if (UTHbufferToFile(suricata.sig_file, data, pos) < 0) {
+ return 0;
+ }
+ }
+
+ if (DetectEngineReload(&suricata) < 0) {
+ return 0;
+ }
+ if (pos < size) {
+ //skip zero
+ pos++;
+ }
+ data += pos;
+ size -= pos;
+
+ //rewrite buffer to a file as libpcap does not have buffer inputs
+ if (UTHbufferToFile("/tmp/fuzz.pcap", data, size) < 0) {
+ return 0;
+ }
+
+ //initialize structure
+ pkts = pcap_open_offline("/tmp/fuzz.pcap", errbuf);
+ if (pkts == NULL) {
+ return 0;
+ }
+
+ //loop over packets
+ r = pcap_next_ex(pkts, &header, &pkt);
+ p = PacketGetFromAlloc();
+ p->datalink = pcap_datalink(pkts);
+ while (r > 0) {
+ PacketCopyData(p, pkt, header->caplen);
+ //DecodePcapFile
+ TmEcode ecode = tmm_modules[TMM_DECODEPCAPFILE].Func(&tv, p, dtv);
+ if (ecode == TM_ECODE_FAILED) {
+ break;
+ }
+ Packet *extra_p = PacketDequeueNoLock(&tv.decode_pq);
+ while (extra_p != NULL) {
+ PacketFree(extra_p);
+ extra_p = PacketDequeueNoLock(&tv.decode_pq);
+ }
+ tmm_modules[TMM_FLOWWORKER].Func(&tv, p, fwd);
+ extra_p = PacketDequeueNoLock(&tv.decode_pq);
+ while (extra_p != NULL) {
+ PacketFree(extra_p);
+ extra_p = PacketDequeueNoLock(&tv.decode_pq);
+ }
+ r = pcap_next_ex(pkts, &header, &pkt);
+ }
+ //close structure
+ pcap_close(pkts);
+ PacketFree(p);
+
+ return 0;
+}
--- /dev/null
+#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;
+}
PASS;
}
+/** \brief writes the contents of a buffer into a file */
+int UTHbufferToFile(const char * name, const uint8_t *data, size_t size) {
+ FILE * fd;
+ if (remove(name) != 0) {
+ if (errno != ENOENT) {
+ printf("failed remove, errno=%d\n", errno);
+ return -1;
+ }
+ }
+ fd = fopen(name, "wb");
+ if (fd == NULL) {
+ printf("failed open, errno=%d\n", errno);
+ return -2;
+ }
+ if (fwrite (data, 1, size, fd) != size) {
+ fclose(fd);
+ return -3;
+ }
+ fclose(fd);
+ return 0;
+}
/*
* unittests for the unittest helpers
void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len);
int UTHParseSignature(const char *str, bool expect);
+int UTHbufferToFile(const char * name, const uint8_t *data, size_t size);
#endif
void UTHRegisterTests(void);