about summary refs log tree commit diff
path: root/include/afl-persistent-replay.h
diff options
context:
space:
mode:
authorDavide Quarta <quarta@qti.qualcomm.com>2024-02-06 18:19:52 +0100
committerDavide Quarta <quarta@qti.qualcomm.com>2024-02-06 18:19:52 +0100
commite405e721fad46e594b633147a6940cfdd602e4c2 (patch)
treebe499292f16789860ec2a8c6cad64379c2819965 /include/afl-persistent-replay.h
parent49d4fa4346b919e1cef65490e9f0232da02cc822 (diff)
downloadafl++-e405e721fad46e594b633147a6940cfdd602e4c2.tar.gz
reuse first_pass aux var in persistent loop for record replay mode, keep area ptr and loc logic intact in record replay mode, move replay record example to own dir in utils, update docs, move record compat layer to separate header file
Diffstat (limited to 'include/afl-persistent-replay.h')
-rw-r--r--include/afl-persistent-replay.h131
1 files changed, 131 insertions, 0 deletions
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
+