about summary refs log tree commit diff
path: root/include/persistent_replay.h
diff options
context:
space:
mode:
authorDavide Quarta <quarta@qti.qualcomm.com>2024-01-23 19:36:49 +0100
committerDavide Quarta <quarta@qti.qualcomm.com>2024-01-23 19:36:49 +0100
commit8fedf4998449d5b6b909a1118fc2e152e4d2e6e7 (patch)
tree71c8d03f94c006f952be8522f8403fe0fca273c7 /include/persistent_replay.h
parentb99bbf671b7469a5aad29898fe28489004c4cbe7 (diff)
downloadafl++-8fedf4998449d5b6b909a1118fc2e152e4d2e6e7.tar.gz
replay mode support
Diffstat (limited to 'include/persistent_replay.h')
-rw-r--r--include/persistent_replay.h149
1 files changed, 149 insertions, 0 deletions
diff --git a/include/persistent_replay.h b/include/persistent_replay.h
new file mode 100644
index 00000000..b1a55e9f
--- /dev/null
+++ b/include/persistent_replay.h
@@ -0,0 +1,149 @@
+#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>
+
+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 **record_arg;
+static char *replay_record_dir;
+static struct dirent **record_list;
+
+static int select_files(const struct dirent *dirbuf) {
+
+  char fn[4096];
+
+  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(int argc, char **argv) {
+  
+  char **argp;
+
+  /* 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");
+  replay_record_cnt = scandir(replay_record_dir ? replay_record_dir : "./", &record_list, select_files, compare_files);  
+
+  if (!replay_record_cnt){
+    printf("[error] Can't find the requested record!\n");
+    is_replay_record = 0;
+  }
+
+  argp = argv;
+  while (*argp){
+    if (!strcmp(*argp, "@@")){
+      record_arg = argp;
+      *record_arg = replay_record_path;
+      break;
+    }
+    ++argp;
+  }
+
+}
+
+/* only used if explictly included for compatibility
+   compiling without afl-cc */
+
+#ifdef AFL_COMPAT
+
+#ifndef PATH_MAX
+  #define PATH_MAX 4096
+#endif
+
+#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);
+
+
+    if (record_arg) {
+      *record_arg = tcase;
+    } else {
+      int fd = open(tcase, O_RDONLY);
+      dup2(fd, 0);
+      close(fd);
+    }
+
+  } else {
+
+    if (!inited){
+      cycle_cnt = max_cnt;
+      inited = 1;
+    }
+
+  }
+
+  return cycle_cnt--;
+}
+
+#endif  // AFL_COMPAT
+
+#endif  // _HAVE_PERSISTENT_REPLAY_H
\ No newline at end of file