mirror of https://github.com/OISF/suricata
afl: improve packet fuzz testing
Due to the use of AFL_LOOP and initialization/deinit outside of it, part of the fuzzing relied on the global 'state' in flow and defrag. Because of this crashes that were found could not be reproduced. The saved crash input was only the last in the series. This patch addresses that. It requires a new output directory 'dump' where the packet fuzzers will store all their input. If the AFL_LOOP fails the files will not be removed and this 'serie' can be read again for reproducing the issue. e.g.: AFL would work with: --afl-decoder-ppp=@@ and after a crash is found the produced serie can be read with: --afl-decoder-ppp-serie=1486656919-514163 The series have a timestamp as name and a suffix that controls the order in which the files will be 'replayed' in Suricata.pull/2552/head
parent
923d93f314
commit
fbd69729aa
@ -0,0 +1,149 @@
|
||||
/* Copyright (C) 2007-2017 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "suricata-common.h"
|
||||
#include "suricata.h"
|
||||
#include "conf.h"
|
||||
#include "decode.h"
|
||||
#include "util-debug.h"
|
||||
#include "util-mem.h"
|
||||
#include "app-layer-detect-proto.h"
|
||||
#include "app-layer.h"
|
||||
#include "tm-threads.h"
|
||||
#include "util-error.h"
|
||||
#include "util-print.h"
|
||||
#include "tmqh-packetpool.h"
|
||||
#include "util-profiling.h"
|
||||
#include "pkt-var.h"
|
||||
#include "util-mpm-ac.h"
|
||||
|
||||
#include "output.h"
|
||||
#include "output-flow.h"
|
||||
|
||||
#include "defrag.h"
|
||||
#include "flow.h"
|
||||
|
||||
#ifdef AFLFUZZ_DECODER
|
||||
|
||||
/* stateful processing of data as packets. Because AFL in case of a
|
||||
* crash will only safe the last input, we dump all the inputs to a
|
||||
* directory 'dump' with a unique timestamp for the serie and an
|
||||
* incrementing 'id' so that we can 'replay' it in
|
||||
* DecoderParseDataFromFileSerie().
|
||||
*/
|
||||
int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder) {
|
||||
uint8_t buffer[65536];
|
||||
|
||||
struct timeval ts;
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
gettimeofday(&ts, NULL);
|
||||
|
||||
uint32_t cnt = 0;
|
||||
|
||||
DefragInit();
|
||||
FlowInitConfig(FLOW_QUIET);
|
||||
|
||||
ThreadVars tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv);
|
||||
DecodeRegisterPerfCounters(dtv, &tv);
|
||||
StatsSetupPrivate(&tv);
|
||||
|
||||
#ifdef AFLFUZZ_PERSISTANT_MODE
|
||||
while (__AFL_LOOP(1000)) {
|
||||
/* reset state */
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
#endif /* AFLFUZZ_PERSISTANT_MODE */
|
||||
|
||||
|
||||
FILE *fp = fopen(filename, "r");
|
||||
BUG_ON(fp == NULL);
|
||||
|
||||
size_t size = fread(&buffer, 1, sizeof(buffer), fp);
|
||||
char outfilename[256];
|
||||
snprintf(outfilename, sizeof(outfilename), "dump/%u-%u.%u", (uint)ts.tv_sec, (uint)ts.tv_usec, cnt);
|
||||
FILE *out_fp = fopen(outfilename, "w");
|
||||
BUG_ON(out_fp == NULL);
|
||||
(void)fwrite(buffer, size, 1, out_fp);
|
||||
fclose(out_fp);
|
||||
|
||||
Packet *p = PacketGetFromAlloc();
|
||||
if (p != NULL) {
|
||||
(void) Decoder (&tv, dtv, p, buffer, size, NULL);
|
||||
PacketFree(p);
|
||||
}
|
||||
fclose(fp);
|
||||
cnt++;
|
||||
|
||||
#ifdef AFLFUZZ_PERSISTANT_MODE
|
||||
}
|
||||
#endif /* AFLFUZZ_PERSISTANT_MODE */
|
||||
|
||||
/* if we get here there was no crash, so we can remove our files */
|
||||
uint32_t x = 0;
|
||||
for (x = 0; x < cnt; x++) {
|
||||
char rmfilename[256];
|
||||
snprintf(rmfilename, sizeof(rmfilename), "dump/%u-%u.%u", (uint)ts.tv_sec, (uint)ts.tv_usec, x);
|
||||
unlink(rmfilename);
|
||||
}
|
||||
|
||||
DecodeThreadVarsFree(&tv, dtv);
|
||||
FlowShutdown();
|
||||
DefragDestroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* load a serie of files generated by DecoderParseDataFromFile() in
|
||||
* the same order as it was produced. */
|
||||
int DecoderParseDataFromFileSerie(char *fileprefix, DecoderFunc Decoder)
|
||||
{
|
||||
uint8_t buffer[65536];
|
||||
uint32_t cnt = 0;
|
||||
|
||||
DefragInit();
|
||||
FlowInitConfig(FLOW_QUIET);
|
||||
ThreadVars tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
DecodeThreadVars *dtv = DecodeThreadVarsAlloc(&tv);
|
||||
DecodeRegisterPerfCounters(dtv, &tv);
|
||||
StatsSetupPrivate(&tv);
|
||||
|
||||
char filename[256];
|
||||
snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt);
|
||||
FILE *fp;
|
||||
while ((fp = fopen(filename, "r")) != NULL)
|
||||
{
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
size_t size = fread(&buffer, 1, sizeof(buffer), fp);
|
||||
|
||||
Packet *p = PacketGetFromAlloc();
|
||||
if (p != NULL) {
|
||||
(void) Decoder (&tv, dtv, p, buffer, size, NULL);
|
||||
PacketFree(p);
|
||||
}
|
||||
fclose(fp);
|
||||
cnt++;
|
||||
snprintf(filename, sizeof(filename), "dump/%s.%u", fileprefix, cnt);
|
||||
}
|
||||
DecodeThreadVarsFree(&tv, dtv);
|
||||
FlowShutdown();
|
||||
DefragDestroy();
|
||||
return 0;
|
||||
}
|
||||
#endif /* AFLFUZZ_DECODER */
|
||||
|
Loading…
Reference in New Issue