|
|
|
/**
|
|
|
|
* @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;
|
|
|
|
}
|