fuzz: adds eight fuzz targets

And ways to compile them with enable-fuzztargets at configure time
Adds utility function in util-unittest-helper
pull/4715/head
Philippe Antoine 7 years ago committed by Victor Julien
parent 1c8943dedd
commit 600b0d7c55

@ -3,7 +3,7 @@
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
@ -459,9 +459,49 @@
# 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])
])

@ -6,8 +6,14 @@ noinst_HEADERS = action-globals.h \
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 \
@ -324,7 +330,6 @@ log-stats.c log-stats.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 \
@ -542,11 +547,116 @@ EXTRA_DIST = tests
# 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)\" \

@ -0,0 +1,57 @@
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 @@

@ -0,0 +1,137 @@
/**
* @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;
}

@ -0,0 +1,57 @@
/**
* @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;
}

@ -0,0 +1,30 @@
/**
* @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;
}

@ -0,0 +1,32 @@
/**
* @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;
}

@ -0,0 +1,97 @@
/**
* @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;
}

@ -0,0 +1,64 @@
/**
* @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;
}

@ -0,0 +1,45 @@
/**
* @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;
}

@ -0,0 +1,179 @@
/**
* @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;
}

@ -0,0 +1,50 @@
#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;
}

@ -942,6 +942,27 @@ int UTHParseSignature(const char *str, bool expect)
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

@ -63,6 +63,7 @@ Packet *UTHBuildPacketIPV6Real(uint8_t *, uint16_t , uint8_t ipproto, const char
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);

Loading…
Cancel
Save