better replay mode error handling, added replay mode documentation, code formatting

This commit is contained in:
Davide Quarta
2024-02-05 18:26:46 +01:00
parent 8fedf49984
commit 023fc19ce0
7 changed files with 183 additions and 82 deletions

View File

@ -125,7 +125,7 @@
#endif /* ^!SIMPLE_FILES */
#ifdef AFL_PERSISTENT_RECORD
#define RECORD_PREFIX "RECORD:"
#define RECORD_PREFIX "RECORD:"
#endif
#define STAGE_BUF_SIZE (64) /* usable size for stage name buf in afl_state */

View File

@ -83,10 +83,14 @@
will be kept and written to the crash/ directory as RECORD:... files.
Note that every crash will be written, not only unique ones! */
// #define AFL_PERSISTENT_RECORD
#define AFL_PERSISTENT_RECORD
/* Builds compiler-rt with support to replay persistent records */
// #define AFL_PERSISTENT_REPLAY
/* Adds support in compiler-rt to replay persistent records */
#define AFL_PERSISTENT_REPLAY
/* 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

View File

@ -11,71 +11,116 @@
#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 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[4096];
if (dirbuf->d_name[0] == '.'){
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;
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;
return c1 - c2;
}
__attribute__((destructor)) static void __afl_record_replay_destroy(void){
for (int i=0; i < replay_record_cnt; i++) {
__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;
__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"))) {
/* 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");
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, "@@")){
while (*argp) {
if (!strcmp(*argp, "@@")) {
record_arg = argp;
*record_arg = replay_record_path;
break;
}
++argp;
}
#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
}
/* only used if explictly included for compatibility
@ -83,67 +128,80 @@ __attribute__((constructor)) static void __afl_record_replay_init(int argc, char
#ifdef AFL_COMPAT
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#define FUZZ_BUF_SIZE 1024000
#define FUZZ_BUF_SIZE 1024000
// extern ssize_t read(int fildes, void *buf, size_t nbyte);
// 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[];
// 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
#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)
#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 int cycle_cnt = 1;
static unsigned short int inited = 0;
char tcase[PATH_MAX];
char tcase[PATH_MAX];
if( is_replay_record ){
if (is_replay_record) {
if (!inited) {
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);
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 {
} else
#endif // AFL_PERSISTENT_REPLAY_ARGPARSE
{
int fd = open(tcase, O_RDONLY);
dup2(fd, 0);
close(fd);
}
} else {
if (!inited){
if (!inited) {
cycle_cnt = max_cnt;
inited = 1;
}
}
return cycle_cnt--;
}
#endif // AFL_COMPAT
#endif // _HAVE_PERSISTENT_REPLAY_H
#endif // _HAVE_PERSISTENT_REPLAY_H