You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/tests/fuzz/fuzz_sigpcap.c

265 lines
6.4 KiB
C

/**
* @file
* @author Philippe Antoine <contact@catenacyber.fr>
* 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 "util-decode-asn1.h"
#include "detect-fast-pattern.h"
#include "util-unittest-helper.h"
#include "conf-yaml-loader.h"
#include "pkt-var.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\
outputs:\n\
- fast:\n\
enabled: yes\n\
filename: /dev/null\n\
- eve-log:\n\
enabled: yes\n\
filetype: regular\n\
filename: /dev/null\n\
xff:\n\
enabled: yes\n\
mode: extra-data\n\
deployment: reverse\n\
header: X-Forwarded-For\n\
types:\n\
- alert:\n\
payload: yes\n\
payload-printable: yes\n\
packet: yes\n\
metadata: yes\n\
http-body: yes\n\
http-body-printable: yes\n\
tagged-packets: yes\n\
- anomaly:\n\
enabled: yes\n\
types:\n\
decode: yes\n\
stream: yes\n\
applayer: yes\n\
packethdr: yes\n\
- http:\n\
extended: yes\n\
dump-all-headers: both\n\
- dns\n\
- tls:\n\
extended: yes\n\
session-resumption: yes\n\
- files\n\
- smtp:\n\
extended: yes\n\
- dnp3\n\
- ftp\n\
- rdp\n\
- nfs\n\
- smb\n\
- tftp\n\
- ikev2\n\
- krb5\n\
- snmp\n\
- rfb\n\
- sip\n\
- dhcp:\n\
enabled: yes\n\
extended: yes\n\
- ssh\n\
- flow\n\
- netflow\n\
- metadata\n\
- http-log:\n\
enabled: yes\n\
filename: /dev/null\n\
extended: yes\n\
- tls-log:\n\
enabled: yes\n\
filename: /dev/null\n\
extended: yes\n\
app-layer:\n\
protocols:\n\
rdp:\n\
enabled: yes\n\
modbus:\n\
enabled: yes\n\
detection-ports:\n\
dp: 502\n\
dnp3:\n\
enabled: yes\n\
detection-ports:\n\
dp: 20000\n\
enip:\n\
enabled: yes\n\
detection-ports:\n\
dp: 44818\n\
sp: 44818\n\
sip:\n\
enabled: yes\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);
PreRunPostPrivsDropInit(run_mode);
//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);
fuzz/sigpcap: initialize empty packet pool Fixes runs with --enable-debug-validation. The target did not init a packet pool, so for a tunnel packet would try to get a packet from an uninitialized pool. In non-debug mode, this silently works by falling back to a packet from alloc. (gdb) bt #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51 #1 0x00007ffff35a6801 in __GI_abort () at abort.c:79 #2 0x00007ffff359639a in __assert_fail_base (fmt=0x7ffff371d7d8 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x555557fe7260 "!(pool->initialized == 0)", file=file@entry=0x555557fe7220 "tmqh-packetpool.c", line=line@entry=253, function=function@entry=0x555557fe7500 <__PRETTY_FUNCTION__.21181> "PacketPoolGetPacket") at assert.c:92 #3 0x00007ffff3596412 in __GI___assert_fail (assertion=0x555557fe7260 "!(pool->initialized == 0)", file=0x555557fe7220 "tmqh-packetpool.c", line=253, function=0x555557fe7500 <__PRETTY_FUNCTION__.21181> "PacketPoolGetPacket") at assert.c:101 #4 0x00005555577e24be in PacketPoolGetPacket () at tmqh-packetpool.c:253 #5 0x0000555556914ecd in PacketGetFromQueueOrAlloc () at decode.c:183 #6 0x00005555569161e1 in PacketTunnelPktSetup (tv=0x555559863980 <tv>, dtv=0x614000068e40, parent=0x61e0000fc080, pkt=0x61e0000fc470 "LL", len=72, proto=DECODE_TUNNEL_IPV4) at decode.c:286 #7 0x00005555569de694 in DecodeIPv4inIPv6 (tv=0x555559863980 <tv>, dtv=0x614000068e40, p=0x61e0000fc080, pkt=0x61e0000fc470 "LL", plen=72) at decode-ipv6.c:59 #8 0x00005555569e60b5 in DecodeIPV6ExtHdrs (tv=0x555559863980 <tv>, dtv=0x614000068e40, p=0x61e0000fc080, pkt=0x61e0000fc470 "LL", len=112) at decode-ipv6.c:522 #9 0x00005555569e846f in DecodeIPV6 (tv=0x555559863980 <tv>, dtv=0x614000068e40, p=0x61e0000fc080, pkt=0x61e0000fc420 "cLL", len=255) at decode-ipv6.c:641 #10 0x0000555556a032f9 in DecodeRaw (tv=0x555559863980 <tv>, dtv=0x614000068e40, p=0x61e0000fc080, pkt=0x61e0000fc420 "cLL", len=255) at decode-raw.c:70 #11 0x0000555557659ba8 in DecodePcapFile (tv=0x555559863980 <tv>, p=0x61e0000fc080, data=0x614000068e40) at source-pcap-file.c:412 #12 0x0000555556573401 in LLVMFuzzerTestOneInput (data=0x613000000047 "\241\262\315\064", size=339) at tests/fuzz/fuzz_sigpcap.c:158 #13 0x0000555557a4dc66 in main (argc=2, argv=0x7fffffffdfa8) at tests/fuzz/onefile.c:51 That line: BUG_ON(pool->initialized == 0);
5 years ago
PacketPoolInitEmpty();
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 (TestHelperBufferToFile(suricata.sig_file, data, pos-1) < 0) {
return 0;
}
} else {
if (TestHelperBufferToFile(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 (TestHelperBufferToFile("/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);
PACKET_RECYCLE(p);
}
//close structure
pcap_close(pkts);
PacketFree(p);
return 0;
}