From: Philippe Antoine Date: Wed, 3 Feb 2021 13:26:24 +0000 (+0100) Subject: fuzz: adds structure aware target X-Git-Tag: suricata-7.0.0-beta1~1719 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e8415f249b12a25c3698148956de52484e2995dc;p=thirdparty%2Fsuricata.git fuzz: adds structure aware target so as not to fuzz libpcap and generate structure aware signatures --- diff --git a/configure.ac b/configure.ac index bee6c09786..8f298d30a9 100644 --- a/configure.ac +++ b/configure.ac @@ -2527,6 +2527,8 @@ fi ]) AC_SUBST(RUST_FEATURES) + AC_CHECK_LIB(fuzzpcap, FPC_IsFuzzPacketCapture, HAS_FUZZPCAP="yes") + AM_CONDITIONAL([HAS_FUZZPCAP], [test "x$HAS_FUZZPCAP" = "xyes"]) 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"]) diff --git a/src/Makefile.am b/src/Makefile.am index abc6699264..0251e152fe 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,6 +5,9 @@ if BUILD_FUZZTARGETS fuzz_confyamlloadstring fuzz_decodepcapfile \ fuzz_sigpcap fuzz_mimedecparseline endif +if HAS_FUZZPCAP + bin_PROGRAMS += fuzz_sigpcap_aware +endif noinst_HEADERS = \ action-globals.h \ @@ -1276,6 +1279,19 @@ endif # force usage of CXX for linker nodist_EXTRA_fuzz_sigpcap_SOURCES = force-cxx-linking.cxx +if HAS_FUZZPCAP +nodist_fuzz_sigpcap_aware_SOURCES = tests/fuzz/fuzz_sigpcap_aware.c +fuzz_sigpcap_aware_LDFLAGS = $(LDFLAGS_FUZZ) +fuzz_sigpcap_aware_LDADD = $(LDADD_FUZZ) -lfuzzpcap +if HAS_FUZZLDFLAGS + fuzz_sigpcap_aware_LDFLAGS += $(LIB_FUZZING_ENGINE) +else + nodist_fuzz_sigpcap_aware_SOURCES += tests/fuzz/onefile.c +endif +# force usage of CXX for linker +nodist_EXTRA_fuzz_sigpcap_aware_SOURCES = force-cxx-linking.cxx +endif + nodist_fuzz_mimedecparseline_SOURCES = tests/fuzz/fuzz_mimedecparseline.c fuzz_mimedecparseline_LDFLAGS = $(LDFLAGS_FUZZ) fuzz_mimedecparseline_LDADD = $(LDADD_FUZZ) diff --git a/src/tests/fuzz/fuzz_sigpcap_aware.c b/src/tests/fuzz/fuzz_sigpcap_aware.c new file mode 100644 index 0000000000..3d9dcdfc5c --- /dev/null +++ b/src/tests/fuzz/fuzz_sigpcap_aware.c @@ -0,0 +1,178 @@ +/** + * @file + * @author Philippe Antoine + * fuzz target for AppLayerProtoDetectGetProto + */ + +#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 "detect-fast-pattern.h" +#include "util-unittest-helper.h" +#include "conf-yaml-loader.h" +#include "pkt-var.h" + +#include + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +static int initialized = 0; +ThreadVars tv; +DecodeThreadVars *dtv; +// FlowWorkerThreadData +void *fwd; +SCInstance surifuzz; + +#include "confyaml.c" + +static void SigGenereateAware(const uint8_t *data, size_t size, char *r, size_t *len) +{ + *len = snprintf(r, 511, "alert ip any any -> any any ("); + for (size_t i = 0; i + 1 < size && *len < 511; i++) { + if (data[i] & 0x80) { + size_t off = (data[i] & 0x7F + ((data[i + 1] & 0xF) << 7)) % + (sizeof(sigmatch_table) / sizeof(SigTableElmt)); + if (sigmatch_table[off].flags & SIGMATCH_NOOPT || + ((data[i + 1] & 0x80) && sigmatch_table[off].flags & SIGMATCH_OPTIONAL_OPT)) { + *len += snprintf(r + *len, 511 - *len, "; %s;", sigmatch_table[off].name); + } else { + *len += snprintf(r + *len, 511 - *len, "; %s:", sigmatch_table[off].name); + } + i++; + } else { + r[*len] = data[i]; + *len = *len + 1; + } + } + if (*len < 511) { + *len += snprintf(r + *len, 511 - *len, ")"); + } else { + r[511] = 0; + *len = 511; + } +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + FPC_buffer_t pkts; + const u_char *pkt; + struct pcap_pkthdr header; + int r; + Packet *p; + size_t pos; + size_t pcap_cnt = 0; + + if (initialized == 0) { + // Redirects logs to /dev/null + setenv("SC_LOG_OP_IFACE", "file", 0); + setenv("SC_LOG_FILE", "/dev/null", 0); + + InitGlobal(); + + GlobalsInitPreConfig(); + run_mode = RUNMODE_PCAP_FILE; + // redirect logs to /tmp + ConfigSetLogDirectory("/tmp/"); + // disables checksums validation for fuzzing + if (ConfYamlLoadString(configNoChecksum, strlen(configNoChecksum)) != 0) { + abort(); + } + // do not load rules before reproducible DetectEngineReload + remove("/tmp/fuzz.rules"); + surifuzz.sig_file = strdup("/tmp/fuzz.rules"); + surifuzz.sig_file_exclusive = 1; + // loads rules after init + surifuzz.delayed_detect = 1; + + PostConfLoadedSetup(&surifuzz); + PreRunPostPrivsDropInit(run_mode); + PostConfLoadedDetectSetup(&surifuzz); + + memset(&tv, 0, sizeof(tv)); + tv.flow_queue = FlowQueueNew(); + if (tv.flow_queue == NULL) + abort(); + dtv = DecodeThreadVarsAlloc(&tv); + DecodeRegisterPerfCounters(dtv, &tv); + tmm_modules[TMM_FLOWWORKER].ThreadInit(&tv, NULL, &fwd); + StatsSetupPrivate(&tv); + + extern intmax_t max_pending_packets; + max_pending_packets = 128; + PacketPoolInit(); + initialized = 1; + } + + if (size < 1 + FPC0_HEADER_LEN) { + return 0; + } + for (pos = 0; pos < size - FPC0_HEADER_LEN; pos++) { + if (data[pos] == 0) { + break; + } + } + // initialize FPC with the buffer + if (FPC_init(&pkts, data + pos + 1, size - pos - 1) < 0) { + return 0; + } + + // dump signatures to a file so as to reuse SigLoadSignatures + char sigaware[512]; + size_t len; + SigGenereateAware(data, pos + 1, sigaware, &len); + if (TestHelperBufferToFile(surifuzz.sig_file, (uint8_t *)sigaware, len) < 0) { + return 0; + } + + if (DetectEngineReload(&surifuzz) < 0) { + return 0; + } + + // loop over packets + r = FPC_next(&pkts, &header, &pkt); + p = PacketGetFromAlloc(); + p->ts.tv_sec = header.ts.tv_sec; + p->ts.tv_usec = header.ts.tv_usec; + p->datalink = pkts.datalink; + while (r > 0) { + if (PacketCopyData(p, pkt, header.caplen) == 0) { + // 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) { + PacketFreeOrRelease(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) { + PacketFreeOrRelease(extra_p); + extra_p = PacketDequeueNoLock(&tv.decode_pq); + } + } + r = FPC_next(&pkts, &header, &pkt); + PACKET_RECYCLE(p); + p->ts.tv_sec = header.ts.tv_sec; + p->ts.tv_usec = header.ts.tv_usec; + p->datalink = pkts.datalink; + pcap_cnt++; + p->pcap_cnt = pcap_cnt; + } + PacketFree(p); + + return 0; +}