aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--include/afl-fuzz.h4
-rw-r--r--include/afl-persistent-replay.h131
-rw-r--r--include/afl-record-compat.h67
-rw-r--r--include/config.h5
-rw-r--r--instrumentation/README.persistent_mode.md32
-rw-r--r--instrumentation/afl-compiler-rt.o.c55
-rw-r--r--src/afl-forkserver.c82
-rw-r--r--src/afl-fuzz-init.c6
-rw-r--r--src/afl-fuzz.c2
-rw-r--r--utils/persistent_mode/Makefile2
-rw-r--r--utils/replay_record/Makefile8
-rw-r--r--utils/replay_record/README.md10
-rw-r--r--utils/replay_record/persistent_demo_replay.c148
14 files changed, 526 insertions, 30 deletions
diff --git a/.gitignore b/.gitignore
index f76a86fc..67feb240 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,6 +103,10 @@ utils/optimin/build
utils/optimin/optimin
utils/persistent_mode/persistent_demo
utils/persistent_mode/persistent_demo_new
+utils/persistent_mode/persistent_demo_new_compat
utils/persistent_mode/test-instr
+utils/replay_record/persistent_demo_replay
+utils/replay_record/persistent_demo_replay_compat
+utils/replay_record/persistent_demo_replay_argparse
utils/plot_ui/afl-plot-ui
vuln_prog
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index c24f39e2..be86910e 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -124,6 +124,10 @@
#define CASE_PREFIX "id_"
#endif /* ^!SIMPLE_FILES */
+#ifdef AFL_PERSISTENT_RECORD
+ #define RECORD_PREFIX "RECORD:"
+#endif
+
#define STAGE_BUF_SIZE (64) /* usable size for stage name buf in afl_state */
// Little helper to access the ptr to afl->##name_buf - for use in afl_realloc.
diff --git a/include/afl-persistent-replay.h b/include/afl-persistent-replay.h
new file mode 100644
index 00000000..9e60ff9c
--- /dev/null
+++ b/include/afl-persistent-replay.h
@@ -0,0 +1,131 @@
+#ifndef _HAVE_PERSISTENT_REPLAY_H
+#define _HAVE_PERSISTENT_REPLAY_H
+
+#include <dirent.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef PATH_MAX
+ #define PATH_MAX 4096
+#endif
+
+static unsigned short int is_replay_record;
+static unsigned int replay_record;
+static unsigned int replay_record_cnt;
+static char replay_record_path[PATH_MAX];
+static char *replay_record_dir;
+static struct dirent **record_list;
+
+#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
+static char **record_arg = NULL;
+#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
+
+static int select_files(const struct dirent *dirbuf) {
+
+ char fn[PATH_MAX];
+
+ if (dirbuf->d_name[0] == '.') {
+
+ return 0;
+
+ } else {
+
+ snprintf(fn, sizeof(fn), "RECORD:%06u", replay_record);
+ return !!strstr(dirbuf->d_name, fn);
+
+ }
+
+}
+
+static int compare_files(const struct dirent **da, const struct dirent **db) {
+
+ unsigned int c1 = 0, c2 = 0;
+
+ sscanf((*da)->d_name, "RECORD:%*u,cnt:%06u", &c1);
+ sscanf((*db)->d_name, "RECORD:%*u,cnt:%06u", &c2);
+
+ return c1 - c2;
+
+}
+
+__attribute__((destructor)) static void __afl_record_replay_destroy(void) {
+
+ for (int i = 0; i < replay_record_cnt; i++) {
+
+ free(record_list[i]);
+
+ }
+
+ free(record_list);
+
+}
+
+__attribute__((constructor)) static void __afl_record_replay_init(
+#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
+ int argc, char **argv
+#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
+) {
+
+#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
+ char **argp;
+#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
+
+ struct stat sb;
+
+ /* caveat: if harness uses @@ and we don't pass it, it will regardless loop
+ * the number of iterations defined for AFL_LOOP (on the same file)*/
+ if (!(is_replay_record = !!getenv("AFL_PERSISTENT_REPLAY"))) {
+
+ // printf("[warning] AFL_PERSISTENT_REPLAY not set.\n");
+ return;
+
+ }
+
+ replay_record = atoi(getenv("AFL_PERSISTENT_REPLAY"));
+ replay_record_dir = getenv("AFL_PERSISTENT_DIR");
+
+ if (!(stat(replay_record_dir, &sb) == 0 && S_ISDIR(sb.st_mode))) {
+
+ fprintf(stderr, "[error] Can't find the requested record directory!\n");
+ is_replay_record = 0;
+ return;
+
+ }
+
+ replay_record_cnt = scandir(replay_record_dir ? replay_record_dir : "./",
+ &record_list, select_files, compare_files);
+
+ if (!replay_record_cnt) {
+
+ fprintf(stderr, "[error] Can't find the requested record!\n");
+ is_replay_record = 0;
+
+ }
+
+#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
+ argp = argv;
+ while (*argp) {
+
+ if (!strcmp(*argp, "@@")) {
+
+ record_arg = argp;
+ *record_arg = replay_record_path;
+ break;
+
+ }
+
+ ++argp;
+
+ }
+
+#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
+
+}
+
+#endif // _HAVE_PERSISTENT_REPLAY_H
+
diff --git a/include/afl-record-compat.h b/include/afl-record-compat.h
new file mode 100644
index 00000000..2c79595d
--- /dev/null
+++ b/include/afl-record-compat.h
@@ -0,0 +1,67 @@
+#ifndef _HAVE_AFL_COMPAT_H
+#define _HAVE_AFL_COMPAT_H
+
+#include <afl-persistent-replay.h>
+
+#define FUZZ_BUF_SIZE 1024000
+
+// extern ssize_t read(int fildes, void *buf, size_t nbyte);
+
+// extern int __afl_persistent_loop(unsigned int max_cnt);
+// extern unsigned char fuzz_buf[];
+
+#ifndef __AFL_HAVE_MANUAL_CONTROL
+ #define __AFL_HAVE_MANUAL_CONTROL
+#endif
+
+#define __AFL_FUZZ_TESTCASE_LEN (read(0, fuzz_buf, FUZZ_BUF_SIZE))
+#define __AFL_FUZZ_TESTCASE_BUF fuzz_buf
+#define __AFL_FUZZ_INIT() void sync(void);
+#define __AFL_INIT() sync()
+#define __AFL_LOOP(x) __afl_persistent_loop(x)
+
+unsigned char fuzz_buf[FUZZ_BUF_SIZE];
+
+int __afl_persistent_loop(unsigned int max_cnt) {
+
+ static unsigned int cycle_cnt = 1;
+ static unsigned short int inited = 0;
+ char tcase[PATH_MAX];
+
+ if (is_replay_record) {
+
+ if (!inited) {
+
+ cycle_cnt = replay_record_cnt;
+ inited = 1;
+
+ }
+
+ snprintf(tcase, PATH_MAX, "%s/%s",
+ replay_record_dir ? replay_record_dir : "./",
+ record_list[replay_record_cnt - cycle_cnt]->d_name);
+
+#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
+ if (record_arg) {
+
+ *record_arg = tcase;
+
+ } else
+
+#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
+ {
+
+ int fd = open(tcase, O_RDONLY);
+ dup2(fd, 0);
+ close(fd);
+
+ }
+
+ }
+
+ return --cycle_cnt;
+
+}
+
+#endif // _HAVE_AFL_COMPAT_H
+
diff --git a/include/config.h b/include/config.h
index 9349828f..70ce2ae3 100644
--- a/include/config.h
+++ b/include/config.h
@@ -97,6 +97,11 @@
// #define AFL_PERSISTENT_RECORD
+/* Adds support in compiler-rt to replay persistent records in @@-style
+ * harnesses */
+
+// #define AFL_PERSISTENT_REPLAY_ARGPARSE
+
/* console output colors: There are three ways to configure its behavior
* 1. default: colored outputs fixed on: defined USE_COLOR && defined
* ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect
diff --git a/instrumentation/README.persistent_mode.md b/instrumentation/README.persistent_mode.md
index 14e59f4a..8e4f6ae4 100644
--- a/instrumentation/README.persistent_mode.md
+++ b/instrumentation/README.persistent_mode.md
@@ -195,4 +195,34 @@ Then as first line after the `__AFL_LOOP` while loop:
int len = __AFL_FUZZ_TESTCASE_LEN;
```
-And that is all! \ No newline at end of file
+And that is all!
+
+## 6) Persistent record, and replay
+
+If your software under test requires keeping a state between persistent loop iterations (i.e., a stateful network stack), you can use the `AFL_PERSISTENT_RECORD` variable as described in the [environment variables documentation](../docs/env_variables.md).
+
+When `AFL_PERSISTENT_RECORD` is enabled, replay functionality is also included in the compiler-rt library. To replay a specific record, assign the record number to the AFL_PERSISTENT_REPLAY environment variable (i.e., `RECORD:XXXXX`` -> `AFL_PERSISTENT_REPLAY=XXXXX`), and run the test binary as you would normally do.
+The directory where the record files live can be specified via the `AFL_PERSISTENT_DIR` environment varilable, otherwise by default it will be considered the current directory (`./`).
+
+If your harness reads the input files from arguments using the special `@@` argument you will need to include support by enabling `AFL_PERSISTENT_ARGPARSE` in `config.h`.
+
+In order to offer transparent support to harnesses using the `@@` command line argument, arguments are parsed by the `__afl_record_replay_init` init function. Since not all systems support passing arguments to initializers, this functionality is disabled by default, it's recommendable to use the `__AFL_FUZZ_TESTCASE_BUF/__AFL_FUZZ_TESTCASE_LEN` shared memory mechanism instead.
+
+## 7) Drop-in persistent loop replay replacement
+
+To use the replay functionality without having to use `afl-cc`, include the [include/record_compat.h](../include/afl-record_compat.h) header file. Together with the [include/afl-persistent-replay.h](../include/afl-persistent-replay.h) header included in it, `afl-record-compat.h` provides a drop-in replacement for the persistent loop mechanism.
+
+```c
+#ifndef __AFL_FUZZ_TESTCASE_LEN
+ // #define AFL_PERSISTENT_REPLAY_ARGPARSE
+ #include "afl-record-compat.h"
+#endif
+
+__AFL_FUZZ_INIT();
+```
+
+A simple example is provided in [persistent_demo_replay.c](../utils/replay_record/persistent_demo_replay.c).
+
+Be aware that the [afl-record-compat.h](../include/afl-record-compat.h) header should only be included in a single compilation unit, or you will end up with clobbered functions and variables.
+
+If you need a cleaner solution, you'll have to move the functions and variables defined in [include/record_compat.h](../include/afl-record-compat.h) and [include/afl-persistent-replay.h](../include/afl-persistent-replay.h) in a C file, and add the relevant declarations to a header file. After including the new header file, the compilation unit resulting from compiling the C file can then be linked with your program. \ No newline at end of file
diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c
index caa3c3a8..a6982280 100644
--- a/instrumentation/afl-compiler-rt.o.c
+++ b/instrumentation/afl-compiler-rt.o.c
@@ -87,6 +87,10 @@ __attribute__((weak)) void __sanitizer_symbolize_pc(void *, const char *fmt,
#include <sys/mman.h>
#include <fcntl.h>
+#ifdef AFL_PERSISTENT_RECORD
+ #include "afl-persistent-replay.h"
+#endif
+
/* Globals needed by the injected instrumentation. The __afl_area_initial region
is used for instrumentation output before __afl_map_shm() has a chance to
run. It will end up as .comm, so it shouldn't be too wasteful. */
@@ -1354,6 +1358,10 @@ int __afl_persistent_loop(unsigned int max_cnt) {
static u8 first_pass = 1;
static u32 cycle_cnt;
+#ifdef AFL_PERSISTENT_RECORD
+ char tcase[PATH_MAX];
+#endif
+
if (first_pass) {
/* Make sure that every iteration of __AFL_LOOP() starts with a clean slate.
@@ -1365,14 +1373,59 @@ int __afl_persistent_loop(unsigned int max_cnt) {
__afl_area_ptr[0] = 1;
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
- cycle_cnt = max_cnt;
first_pass = 0;
__afl_selective_coverage_temp = 1;
+#ifdef AFL_PERSISTENT_RECORD
+ if (unlikely(is_replay_record)) {
+
+ cycle_cnt = replay_record_cnt;
+ goto persistent_record;
+
+ } else
+
+#endif
+ {
+
+ cycle_cnt = max_cnt;
+
+ }
+
return 1;
} else if (--cycle_cnt) {
+#ifdef AFL_PERSISTENT_RECORD
+ if (unlikely(is_replay_record)) {
+
+ persistent_record:
+
+ snprintf(tcase, PATH_MAX, "%s/%s",
+ replay_record_dir ? replay_record_dir : "./",
+ record_list[replay_record_cnt - cycle_cnt]->d_name);
+
+ #ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
+ if (unlikely(record_arg)) {
+
+ *record_arg = tcase;
+
+ } else
+
+ #endif // AFL_PERSISTENT_REPLAY_ARGPARSE
+ {
+
+ int fd = open(tcase, O_RDONLY);
+ dup2(fd, 0);
+ close(fd);
+
+ }
+
+ return 1;
+
+ }
+
+#endif
+
raise(SIGSTOP);
__afl_area_ptr[0] = 1;
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 0a77d61c..43b57b52 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -1599,6 +1599,11 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
u32 exec_ms;
u32 write_value = fsrv->last_run_timed_out;
+#ifdef AFL_PERSISTENT_RECORD
+ fsrv_run_result_t retval = FSRV_RUN_OK;
+ char *persistent_out_fmt;
+#endif
+
#ifdef __linux__
if (fsrv->nyx_mode) {
@@ -1798,6 +1803,18 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
if (unlikely(fsrv->last_run_timed_out)) {
fsrv->last_kill_signal = fsrv->child_kill_signal;
+
+#ifdef AFL_PERSISTENT_RECORD
+ if (unlikely(fsrv->persistent_record)) {
+
+ retval = FSRV_RUN_TMOUT;
+ persistent_out_fmt = "%s/hangs/RECORD:%06u,cnt:%06u";
+ goto store_persistent_record;
+
+ }
+
+#endif
+
return FSRV_RUN_TMOUT;
}
@@ -1819,48 +1836,61 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
(fsrv->uses_crash_exitcode &&
WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) {
+ /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
+ fsrv->last_kill_signal =
+ WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
+
#ifdef AFL_PERSISTENT_RECORD
if (unlikely(fsrv->persistent_record)) {
- char fn[PATH_MAX];
- u32 i, writecnt = 0;
- for (i = 0; i < fsrv->persistent_record; ++i) {
+ retval = FSRV_RUN_CRASH;
+ persistent_out_fmt = "%s/crashes/RECORD:%06u,cnt:%06u";
+ goto store_persistent_record;
- u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record;
- u8 *data = fsrv->persistent_record_data[entry];
- u32 len = fsrv->persistent_record_len[entry];
- if (likely(len && data)) {
+ }
- snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u",
- fsrv->persistent_record_dir, fsrv->persistent_record_cnt,
- writecnt++);
- int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
- if (fd >= 0) {
+#endif
- ck_write(fd, data, len, fn);
- close(fd);
+ return FSRV_RUN_CRASH;
- }
+ }
- }
+ /* success :) */
+ return FSRV_RUN_OK;
- }
+#ifdef AFL_PERSISTENT_RECORD
+store_persistent_record: {
- ++fsrv->persistent_record_cnt;
+ char fn[PATH_MAX];
+ u32 i, writecnt = 0;
+ for (i = 0; i < fsrv->persistent_record; ++i) {
- }
+ u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record;
+ u8 *data = fsrv->persistent_record_data[entry];
+ u32 len = fsrv->persistent_record_len[entry];
+ if (likely(len && data)) {
-#endif
+ snprintf(fn, sizeof(fn), persistent_out_fmt, fsrv->persistent_record_dir,
+ fsrv->persistent_record_cnt, writecnt++);
+ int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+ if (fd >= 0) {
- /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
- fsrv->last_kill_signal =
- WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
- return FSRV_RUN_CRASH;
+ ck_write(fd, data, len, fn);
+ close(fd);
+
+ }
+
+ }
}
- /* success :) */
- return FSRV_RUN_OK;
+ ++fsrv->persistent_record_cnt;
+
+ return retval;
+
+}
+
+#endif
}
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 76291cc4..54760744 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -1921,6 +1921,9 @@ static void handle_existing_out_dir(afl_state_t *afl) {
}
+#ifdef AFL_PERSISTENT_RECORD
+ delete_files(fn, RECORD_PREFIX);
+#endif
if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
ck_free(fn);
@@ -1953,6 +1956,9 @@ static void handle_existing_out_dir(afl_state_t *afl) {
}
+#ifdef AFL_PERSISTENT_RECORD
+ delete_files(fn, RECORD_PREFIX);
+#endif
if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
ck_free(fn);
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 12d67fe7..ea8f1423 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -2182,7 +2182,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
- afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir);
+ afl->fsrv.persistent_record_dir = alloc_printf("%s", afl->out_dir);
}
diff --git a/utils/persistent_mode/Makefile b/utils/persistent_mode/Makefile
index e348c46c..498aa3f8 100644
--- a/utils/persistent_mode/Makefile
+++ b/utils/persistent_mode/Makefile
@@ -7,4 +7,4 @@ document:
AFL_DONT_OPTIMIZE=1 ../../afl-clang-fast -D_AFL_DOCUMENT_MUTATIONS -o test-instr test-instr.c
clean:
- rm -f persistent_demo persistent_demo_new test-instr
+ rm -f persistent_demo persistent_demo_new persistent_demo_new_compat test-instr
diff --git a/utils/replay_record/Makefile b/utils/replay_record/Makefile
new file mode 100644
index 00000000..0d1cba92
--- /dev/null
+++ b/utils/replay_record/Makefile
@@ -0,0 +1,8 @@
+all:
+ test `grep '//[\s\t ]*#define[\s\t ]*AFL_PERSISTENT_RECORD' ../../include/config.h | wc -l` -eq 0 || (echo "AFL_PERSISTENT_RECORD must be enabled in config.h"; exit 1)
+ ../../afl-clang-fast -o persistent_demo_replay persistent_demo_replay.c
+ ${CC} -I ../../include -o persistent_demo_replay_compat persistent_demo_replay.c
+ ${CC} -g -I ../../include -DAFL_PERSISTENT_REPLAY_ARGPARSE -o persistent_demo_replay_argparse persistent_demo_replay.c
+
+clean:
+ rm -f persistent_demo_replay persistent_demo_replay_argparse persistent_demo_replay_compat
diff --git a/utils/replay_record/README.md b/utils/replay_record/README.md
new file mode 100644
index 00000000..6d72ca97
--- /dev/null
+++ b/utils/replay_record/README.md
@@ -0,0 +1,10 @@
+# AFL++ persistent record replay
+
+This persistent record replay demo showcases the `AFL_PERSISTENT_RECORD` replay functionality.
+
+The [Makefile](Makefile) will produce three binaries:
+ + persistent_demo_replay: uses afl-cc and makes use of the replay functionality included in the compiler runtime library
+ + persistent_demo_replay_compat: uses the [afl-record-compat.h](../../include/afl-record-compat.h) compatibility header to compile the same example without `afl-cc`
+ + persistent_demo_replay_argparse: makes use of `afl-record-compat.h`, and the Makefile defines `AFL_PERSISTENT_REPLAY_ARGPARSE` to test the replay functionality but parses the input file via a command-line argument (`@@`-style harness).
+
+For more information see [README.persistent_mode.md](../../instrumentation/README.persistent_mode.md). \ No newline at end of file
diff --git a/utils/replay_record/persistent_demo_replay.c b/utils/replay_record/persistent_demo_replay.c
new file mode 100644
index 00000000..6f6648f1
--- /dev/null
+++ b/utils/replay_record/persistent_demo_replay.c
@@ -0,0 +1,148 @@
+/*
+ american fuzzy lop++ - persistent mode example
+ --------------------------------------------
+
+ Originally written by Michal Zalewski
+
+ Copyright 2015 Google Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ This file demonstrates the high-performance "persistent mode" that may be
+ suitable for fuzzing certain fast and well-behaved libraries, provided that
+ they are stateless or that their internal state can be easily reset
+ across runs.
+
+ To make this work, the library and this shim need to be compiled in LLVM
+ mode using afl-clang-fast (other compiler wrappers will *not* work).
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <limits.h>
+
+#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
+ #include <sys/stat.h>
+ #include <fcntl.h>
+#endif
+
+/* this lets the source compile without afl-clang-fast/lto */
+#ifndef __AFL_FUZZ_TESTCASE_LEN
+ #include "afl-record-compat.h"
+#endif
+
+__AFL_FUZZ_INIT();
+
+/* Main entry point. */
+
+/* To ensure checks are not optimized out it is recommended to disable
+ code optimization for the fuzzer harness main() */
+#pragma clang optimize off
+#pragma GCC optimize("O0")
+
+int main(int argc, char **argv) {
+
+ ssize_t len; /* how much input did we read? */
+ unsigned char *buf; /* test case buffer pointer */
+
+#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
+ int fd;
+
+ if (argc < 2) { printf("Need an input file!"); }
+#endif
+
+ /* The number passed to __AFL_LOOP() controls the maximum number of
+ iterations before the loop exits and the program is allowed to
+ terminate normally. This limits the impact of accidental memory leaks
+ and similar hiccups. */
+
+ __AFL_INIT();
+
+#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
+ buf = malloc(1000);
+#else
+ buf = __AFL_FUZZ_TESTCASE_BUF; // this must be assigned before __AFL_LOOP!
+#endif
+
+ while (__AFL_LOOP(UINT_MAX)) { // increase if you have good stability
+
+#ifdef AFL_PERSISTENT_REPLAY_ARGPARSE
+ fd = open(argv[1], O_RDONLY);
+ len = read(fd, buf, 1000);
+ close(fd);
+#else
+ len = __AFL_FUZZ_TESTCASE_LEN; // do not use the macro directly in a call!
+#endif
+
+ // fprintf(stderr, "input: %zd \"%s\"\n", len, buf);
+
+ /* do we have enough data? */
+ if (len < 8) continue;
+
+ if (strcmp((char *)buf, "thisisateststring") == 0) printf("teststring\n");
+
+ if (buf[0] == 'f') {
+
+ printf("one\n");
+ if (buf[1] == 'o') {
+
+ printf("two\n");
+ if (buf[2] == 'o') {
+
+ printf("three\n");
+ if (buf[3] == '!') {
+
+ printf("four\n");
+ if (buf[4] == '!') {
+
+ printf("five\n");
+ if (buf[5] == '!') {
+
+ printf("six\n");
+ abort();
+
+ } else {
+
+ if (buf[5] == 'O') {
+
+ // hang
+ while (1) {
+
+ continue;
+
+ };
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /*** END PLACEHOLDER CODE ***/
+
+ }
+
+ /* Once the loop is exited, terminate normally - AFL will restart the process
+ when this happens, with a clean slate when it comes to allocated memory,
+ leftover file descriptors, etc. */
+
+ return 0;
+
+}
+