diff options
author | van Hauser <vh@thc.org> | 2024-04-13 11:50:49 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-13 11:50:49 +0200 |
commit | 1d17210d9fb0eb37ba866a3697643a9e4f37acd5 (patch) | |
tree | 2471cccc76e4396de369f3bfe4b8f4bb00ef6403 /src | |
parent | 775861ea94d00672c9e868db329073afd699b994 (diff) | |
parent | 1582aa9da2d7593e5b577aa3fc963ea7eb2ccbb3 (diff) | |
download | afl++-1d17210d9fb0eb37ba866a3697643a9e4f37acd5.tar.gz |
Merge pull request #2052 from AFLplusplus/dev v4.20c
4.20 release pre-PR
Diffstat (limited to 'src')
-rw-r--r-- | src/afl-cc.c | 27 | ||||
-rw-r--r-- | src/afl-common.c | 46 | ||||
-rw-r--r-- | src/afl-forkserver.c | 500 | ||||
-rw-r--r-- | src/afl-fuzz-bitmap.c | 41 | ||||
-rw-r--r-- | src/afl-fuzz-extras.c | 7 | ||||
-rw-r--r-- | src/afl-fuzz-init.c | 43 | ||||
-rw-r--r-- | src/afl-fuzz-redqueen.c | 64 | ||||
-rw-r--r-- | src/afl-fuzz-run.c | 43 | ||||
-rw-r--r-- | src/afl-fuzz-state.c | 6 | ||||
-rw-r--r-- | src/afl-fuzz-stats.c | 180 | ||||
-rw-r--r-- | src/afl-fuzz.c | 83 | ||||
-rw-r--r-- | src/afl-performance.c | 14 | ||||
-rw-r--r-- | src/afl-tmin.c | 34 | ||||
-rw-r--r-- | src/hashmap.c | 149 |
14 files changed, 947 insertions, 290 deletions
diff --git a/src/afl-cc.c b/src/afl-cc.c index e9564277..45fd398b 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -828,7 +828,8 @@ static void instrument_mode_old_environ(aflcc_state_t *aflcc) { } if (getenv("AFL_LLVM_CTX")) aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX; - if (getenv("AFL_LLVM_CALLER")) + if (getenv("AFL_LLVM_CALLER") || getenv("AFL_LLVM_LTO_CALLER") || + getenv("AFL_LLVM_LTO_CTX")) aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER; if (getenv("AFL_LLVM_NGRAM_SIZE")) { @@ -1148,12 +1149,16 @@ static void instrument_opt_mode_exclude(aflcc_state_t *aflcc) { } - if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM) + if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM && + !((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) && + aflcc->compiler_mode == LTO)) FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode"); if (aflcc->instrument_opt_mode && aflcc->instrument_opt_mode != INSTRUMENT_OPT_CODECOV && - aflcc->instrument_mode != INSTRUMENT_CLASSIC) + aflcc->instrument_mode != INSTRUMENT_CLASSIC && + !(aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER && + aflcc->compiler_mode == LTO)) FATAL( "CALLER, CTX and NGRAM instrumentation options can only be used with " "the LLVM CLASSIC instrumentation mode."); @@ -1364,6 +1369,13 @@ void mode_final_checkout(aflcc_state_t *aflcc, int argc, char **argv) { } + if (getenv("AFL_LLVM_DICT2FILE") && + (getenv("AFL_LLVM_LAF_SPLIT_SWITCHES") || + getenv("AFL_LLVM_LAF_SPLIT_COMPARES") || + getenv("AFL_LLVM_LAF_SPLIT_FLOATS") || + getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES"))) + FATAL("AFL_LLVM_DICT2FILE is incompatible with AFL_LLVM_LAF_*"); + aflcc->cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG") || getenv("AFL_GCC_CMPLOG"); @@ -2375,7 +2387,11 @@ void add_runtime(aflcc_state_t *aflcc) { if (aflcc->plusplus_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) && strncmp(libdir, "/lib", 4)) { +#ifdef __APPLE__ + u8 *libdir_opt = strdup("-Wl,-rpath," LLVM_LIBDIR); +#else u8 *libdir_opt = strdup("-Wl,-rpath=" LLVM_LIBDIR); +#endif insert_param(aflcc, libdir_opt); } @@ -2917,11 +2933,12 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) { " AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding " "functions\n" " into this file (LTO mode)\n" + " AFL_LLVM_LTO_CALLER: activate CALLER/CTX instrumentation\n" + " AFL_LLVM_LTO_CALLER_DEPTH: skip how many empty functions\n" " AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a " "global var\n" " AFL_LLVM_LTO_STARTID: from which ID to start counting from for " - "a " - "bb\n" + "a bb\n" " AFL_REAL_LD: use this lld linker instead of the compiled in " "path\n" " AFL_LLVM_LTO_SKIPINIT: don't inject initialization code " diff --git a/src/afl-common.c b/src/afl-common.c index 87003b03..6d915b00 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -34,6 +34,7 @@ #endif #include <string.h> #include <strings.h> +#include <time.h> #include <math.h> #include <sys/mman.h> @@ -58,6 +59,27 @@ u8 last_intr = 0; #define AFL_PATH "/usr/local/lib/afl/" #endif +/* - Some BSD (i.e.: FreeBSD) offer the FAST clock source as + * equivalent to Linux COARSE clock source. Aliasing COARSE to + * FAST on such systems when COARSE is not already defined. + * - macOS has no support of CLOCK_MONOTONIC_COARSE clock type. + */ +#if defined(OS_DARWIN) || defined(OS_SUNOS) || defined(__APPLE__) || \ + defined(__sun) || defined(__NetBSD__) + #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC +#elif defined(OS_FREEBSD) + #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST +#endif + +/* Convert seconds to milliseconds. */ +#define SEC_TO_MS(sec) ((sec) * 1000) +/* Convert seconds to microseconds. */ +#define SEC_TO_US(sec) ((sec) * 1000000) +/* Convert nanoseconds to milliseconds. */ +#define NS_TO_MS(ns) ((ns) / 1000000) +/* Convert nanoseconds to microseconds. */ +#define NS_TO_US(ns) ((ns) / 1000) + void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { @@ -974,12 +996,16 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) { inline u64 get_cur_time(void) { - struct timeval tv; - struct timezone tz; + struct timespec ts; + int rc = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); + if (rc == -1) { - gettimeofday(&tv, &tz); + PFATAL("Failed to obtain timestamp (errno = %i: %s)\n", errno, + strerror(errno)); - return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000); + } + + return SEC_TO_MS((uint64_t)ts.tv_sec) + NS_TO_MS((uint64_t)ts.tv_nsec); } @@ -987,12 +1013,16 @@ inline u64 get_cur_time(void) { u64 get_cur_time_us(void) { - struct timeval tv; - struct timezone tz; + struct timespec ts; + int rc = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); + if (rc == -1) { - gettimeofday(&tv, &tz); + PFATAL("Failed to obtain timestamp (errno = %i: %s)\n", errno, + strerror(errno)); + + } - return (tv.tv_sec * 1000000ULL) + tv.tv_usec; + return SEC_TO_US((uint64_t)ts.tv_sec) + NS_TO_US((uint64_t)ts.tv_nsec); } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 0a77d61c..f28a2a64 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -389,7 +389,7 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { while (1) { uint32_t was_killed; - int status; + u32 status; /* Wait for parent by reading from the pipe. Exit if read fails. */ @@ -524,7 +524,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, u8 debug_child_output) { int st_pipe[2], ctl_pipe[2]; - s32 status; + u32 status; s32 rlen; char *ignore_autodict = getenv("AFL_NO_AUTODICT"); @@ -724,7 +724,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } /* autodict in Nyx mode */ - if (!ignore_autodict) { + if (!ignore_autodict && fsrv->add_extra_func) { char *x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path); @@ -1017,69 +1017,106 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (rlen == 4) { - if (status >= 0x41464c00 && status <= 0x41464cff) { + /* + * The new fork server model works like this: + * Client: sends "AFLx" in little endian, with x being the forkserver + * protocol version. + * Server: replies with XOR of the message or exits with an error if it + * is not a supported version. + * Client: sends 32 bit of options and then sends all parameters of + * the options, one after another, increasing by option number. + * Ends with "AFLx". + * After the initial protocol version confirmation the server does not + * send any data anymore - except a future option requires this. + */ - FATAL( - "Target uses the new forkserver model, you need to switch to a newer " - "afl-fuzz too!"); + if ((status & FS_NEW_ERROR) == FS_NEW_ERROR) { - } + report_error_and_exit(status & 0x0000ffff); - if (!be_quiet) { OKF("All right - fork server is up."); } + } - if (getenv("AFL_DEBUG")) { + if (status >= 0x41464c00 && status <= 0x41464cff) { - ACTF("Extended forkserver functions received (%08x).", status); + u32 version = status - 0x41464c00; - } + if (!version) { - if ((status & FS_OPT_ERROR) == FS_OPT_ERROR) - report_error_and_exit(FS_OPT_GET_ERROR(status)); + FATAL( + "Fork server version is not assigned, this should not happen. " + "Recompile target."); - if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { + } else if (version < FS_NEW_VERSION_MIN || version > FS_NEW_VERSION_MAX) { - // workaround for recent AFL++ versions - if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND) - status = (status & 0xf0ffffff); + FATAL( + "Fork server version is not not supported. Recompile the target."); - if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) { + } - if (fsrv->qemu_mode || fsrv->frida_mode) { + u32 keep = status; + status ^= 0xffffffff; + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { - report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU); + FATAL("Writing to forkserver failed."); - } else { + } - report_error_and_exit(FS_ERROR_OLD_CMPLOG); + if (!be_quiet) { - } + OKF("All right - new fork server model v%u is up.", version); } - if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) { + rlen = read(fsrv->fsrv_st_fd, &status, 4); - fsrv->snapshot = 1; - if (!be_quiet) { ACTF("Using SNAPSHOT feature."); } + if (getenv("AFL_DEBUG")) { + + ACTF("Forkserver options received: (0x%08x)", status); } - if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) { + if ((status & FS_NEW_OPT_MAPSIZE)) { - if (fsrv->support_shmem_fuzz) { + u32 tmp_map_size; + rlen = read(fsrv->fsrv_st_fd, &tmp_map_size, 4); - fsrv->use_shmem_fuzz = 1; - if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); } + if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; } - if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) { + fsrv->real_map_size = tmp_map_size; - u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); - if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) { + if (tmp_map_size % 64) { - FATAL("Writing to forkserver failed."); + tmp_map_size = (((tmp_map_size + 63) >> 6) << 6); - } + } - } + if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); } + if (tmp_map_size > fsrv->map_size) { + + FATAL( + "Target's coverage map size of %u is larger than the one this " + "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and " + "restart " + " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile " + "afl-fuzz", + tmp_map_size, fsrv->map_size, tmp_map_size); + + } + + fsrv->map_size = tmp_map_size; + + } else { + + fsrv->real_map_size = fsrv->map_size = MAP_SIZE; + + } + + if (status & FS_NEW_OPT_SHDMEM_FUZZ) { + + if (fsrv->support_shmem_fuzz) { + + fsrv->use_shmem_fuzz = 1; + if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); } } else { @@ -1091,134 +1128,303 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } - if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { + if (status & FS_NEW_OPT_AUTODICT) { - u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status); + // even if we do not need the dictionary we have to read it - if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; } + u32 dict_size; + if (read(fsrv->fsrv_st_fd, &dict_size, 4) != 4) { - fsrv->real_map_size = tmp_map_size; + FATAL("Reading from forkserver failed."); - if (tmp_map_size % 64) { + } - tmp_map_size = (((tmp_map_size + 63) >> 6) << 6); + if (dict_size < 2 || dict_size > 0xffffff) { + + FATAL("Dictionary has an illegal size: %d", dict_size); } - if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); } - if (tmp_map_size > fsrv->map_size) { + u32 offset = 0, count = 0; + u8 *dict = ck_alloc(dict_size); + if (dict == NULL) { - FATAL( - "Target's coverage map size of %u is larger than the one this " - "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart " - " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile " - "afl-fuzz", - tmp_map_size, fsrv->map_size, tmp_map_size); + FATAL("Could not allocate %u bytes of autodictionary memory", + dict_size); } - fsrv->map_size = tmp_map_size; + while (offset < dict_size) { + + rlen = read(fsrv->fsrv_st_fd, dict + offset, dict_size - offset); + if (rlen > 0) { + + offset += rlen; + + } else { + + FATAL( + "Reading autodictionary fail at position %u with %u bytes " + "left.", + offset, dict_size - offset); + + } + + } + + offset = 0; + while (offset < dict_size && (u8)dict[offset] + offset < dict_size) { + + if (!ignore_autodict && fsrv->add_extra_func) { + + fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, + (u8)dict[offset]); + count++; + + } + + offset += (1 + dict[offset]); + + } + + if (!be_quiet && count) { + + ACTF("Loaded %u autodictionary entries", count); + + } + + ck_free(dict); } - if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { + u32 status2; + rlen = read(fsrv->fsrv_st_fd, &status2, 4); - if (!ignore_autodict) { + if (status2 != keep) { - if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) { + FATAL("Error in forkserver communication (%08x=>%08x)", keep, status2); - // this is not afl-fuzz - or it is cmplog - we deny and return - if (fsrv->use_shmem_fuzz) { + } - status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); + } else { - } else { + if (!fsrv->qemu_mode && !fsrv->cs_mode +#ifdef __linux__ + && !fsrv->nyx_mode +#endif + ) { - status = (FS_OPT_ENABLED); + WARNF( + "Old fork server model is used by the target, this still works " + "though."); - } + } - if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { + if (!be_quiet) { OKF("All right - old fork server is up."); } - FATAL("Writing to forkserver failed."); + if (getenv("AFL_DEBUG")) { - } + ACTF("Extended forkserver functions received (%08x).", status); + + } - return; + if ((status & FS_OPT_ERROR) == FS_OPT_ERROR) + report_error_and_exit(FS_OPT_GET_ERROR(status)); - } + if (fsrv->cmplog_binary && !fsrv->qemu_mode) { + + FATAL("Target was compiled with outdated CMPLOG, recompile it!\n"); + + } - if (!be_quiet) { ACTF("Using AUTODICT feature."); } + if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { - if (fsrv->use_shmem_fuzz) { + // workaround for recent AFL++ versions + if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == + FS_OPT_OLD_AFLPP_WORKAROUND) + status = (status & 0xf0ffffff); - status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ); + if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) { + + if (fsrv->qemu_mode || fsrv->frida_mode) { + + report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU); } else { - status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); + report_error_and_exit(FS_ERROR_OLD_CMPLOG); } - if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { + } - FATAL("Writing to forkserver failed."); + if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) { - } + fsrv->snapshot = 1; + if (!be_quiet) { ACTF("Using SNAPSHOT feature."); } + + } + + if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) { - if (read(fsrv->fsrv_st_fd, &status, 4) != 4) { + if (fsrv->support_shmem_fuzz) { - FATAL("Reading from forkserver failed."); + fsrv->use_shmem_fuzz = 1; + if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); } + + if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) { + + u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); + if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) { + + FATAL("Writing to forkserver failed."); + + } + + } + + } else { + + FATAL( + "Target requested sharedmem fuzzing, but we failed to enable " + "it."); } - if (status < 2 || (u32)status > 0xffffff) { + } + + if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { + + u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status); + + if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; } + + fsrv->real_map_size = tmp_map_size; + + if (tmp_map_size % 64) { - FATAL("Dictionary has an illegal size: %d", status); + tmp_map_size = (((tmp_map_size + 63) >> 6) << 6); } - u32 offset = 0, count = 0; - u32 len = status; - u8 *dict = ck_alloc(len); - if (dict == NULL) { + if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); } + if (tmp_map_size > fsrv->map_size) { - FATAL("Could not allocate %u bytes of autodictionary memory", len); + FATAL( + "Target's coverage map size of %u is larger than the one this " + "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and " + "restart " + " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile " + "afl-fuzz", + tmp_map_size, fsrv->map_size, tmp_map_size); } - while (len != 0) { + fsrv->map_size = tmp_map_size; - rlen = read(fsrv->fsrv_st_fd, dict + offset, len); - if (rlen > 0) { + } - len -= rlen; - offset += rlen; + if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { + + if (!ignore_autodict) { + + if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) { + + // this is not afl-fuzz - or it is cmplog - we deny and return + if (fsrv->use_shmem_fuzz) { + + status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); + + } else { + + status = (FS_OPT_ENABLED); + + } + + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { + + FATAL("Writing to forkserver failed."); + + } + + return; + + } + + if (!be_quiet) { ACTF("Using AUTODICT feature."); } + + if (fsrv->use_shmem_fuzz) { + + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ); } else { - FATAL( - "Reading autodictionary fail at position %u with %u bytes " - "left.", - offset, len); + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); } - } + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { - offset = 0; - while (offset < (u32)status && - (u8)dict[offset] + offset < (u32)status) { + FATAL("Writing to forkserver failed."); - fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, - (u8)dict[offset]); - offset += (1 + dict[offset]); - count++; + } - } + if (read(fsrv->fsrv_st_fd, &status, 4) != 4) { - if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); } - ck_free(dict); + FATAL("Reading from forkserver failed."); + + } + + if (status < 2 || (u32)status > 0xffffff) { + + FATAL("Dictionary has an illegal size: %d", status); + + } + + u32 offset = 0, count = 0; + u32 len = status; + u8 *dict = ck_alloc(len); + if (dict == NULL) { + + FATAL("Could not allocate %u bytes of autodictionary memory", + len); + + } + + while (len != 0) { + + rlen = read(fsrv->fsrv_st_fd, dict + offset, len); + if (rlen > 0) { + + len -= rlen; + offset += rlen; + + } else { + + FATAL( + "Reading autodictionary fail at position %u with %u bytes " + "left.", + offset, len); + + } + + } + + offset = 0; + while (offset < (u32)status && + (u8)dict[offset] + offset < (u32)status) { + + fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, + (u8)dict[offset]); + offset += (1 + dict[offset]); + count++; + + } + + if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); } + ck_free(dict); + + } } @@ -1599,6 +1805,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) { @@ -1628,6 +1839,8 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, case Timeout: return FSRV_RUN_TMOUT; case InvalidWriteToPayload: + if (!!getenv("AFL_NYX_HANDLE_INVALID_WRITE")) { return FSRV_RUN_CRASH; } + /* ??? */ FATAL("FixMe: Nyx InvalidWriteToPayload handler is missing"); break; @@ -1661,7 +1874,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, territory. */ #ifdef __linux__ - if (!fsrv->nyx_mode) { + if (likely(!fsrv->nyx_mode)) { memset(fsrv->trace_bits, 0, fsrv->map_size); MEM_BARRIER(); @@ -1731,7 +1944,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, if (exec_ms > timeout) { - /* If there was no response from forkserver after timeout seconds, + /* If there was no response from forkserver after timeout milliseconds, we kill the child. The forkserver should inform us afterwards */ s32 tmp_pid = fsrv->child_pid; @@ -1798,6 +2011,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%s%s"; + goto store_persistent_record; + + } + +#endif + return FSRV_RUN_TMOUT; } @@ -1819,48 +2044,63 @@ 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%s%s"; + 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++, + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); + 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-bitmap.c b/src/afl-fuzz-bitmap.c index d056ac9f..d8561dde 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -527,15 +527,19 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES - queue_fn = - alloc_printf("%s/queue/id:%06u,%s", afl->out_dir, afl->queued_items, - describe_op(afl, new_bits + is_timeout, - NAME_MAX - strlen("id:000000,"))); + queue_fn = alloc_printf( + "%s/queue/id:%06u,%s%s%s", afl->out_dir, afl->queued_items, + describe_op(afl, new_bits + is_timeout, + NAME_MAX - strlen("id:000000,")), + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #else - queue_fn = - alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_items); + queue_fn = alloc_printf( + "%s/queue/id_%06u", afl->out_dir, afl->queued_items, + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #endif /* ^!SIMPLE_FILES */ fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); @@ -739,14 +743,17 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES - snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s", afl->out_dir, + snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s%s%s", afl->out_dir, afl->saved_hangs, - describe_op(afl, 0, NAME_MAX - strlen("id:000000,"))); + describe_op(afl, 0, NAME_MAX - strlen("id:000000,")), + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #else - snprintf(fn, PATH_MAX, "%s/hangs/id_%06llu", afl->out_dir, - afl->saved_hangs); + snprintf(fn, PATH_MAX, "%s/hangs/id_%06llu%s%s", afl->out_dir, + afl->saved_hangs, afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #endif /* ^!SIMPLE_FILES */ @@ -792,14 +799,18 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES - snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir, - afl->saved_crashes, afl->fsrv.last_kill_signal, - describe_op(afl, 0, NAME_MAX - strlen("id:000000,sig:00,"))); + snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s%s%s", + afl->out_dir, afl->saved_crashes, afl->fsrv.last_kill_signal, + describe_op(afl, 0, NAME_MAX - strlen("id:000000,sig:00,")), + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #else - snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u", afl->out_dir, - afl->saved_crashes, afl->fsrv.last_kill_signal); + snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u%s%s", afl->out_dir, + afl->saved_crashes, afl->fsrv.last_kill_signal, + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #endif /* ^!SIMPLE_FILES */ diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 3b1d13f1..c06896ef 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -742,8 +742,11 @@ void save_auto(afl_state_t *afl) { for (i = 0; i < MIN((u32)USE_AUTO_EXTRAS, afl->a_extras_cnt); ++i) { - u8 *fn = - alloc_printf("%s/queue/.state/auto_extras/auto_%06u", afl->out_dir, i); + u8 *fn = alloc_printf( + "%s/queue/.state/auto_extras/auto_%06u%s%s", afl->out_dir, i, + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); + s32 fd; fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 76291cc4..21a8ba7e 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1157,18 +1157,22 @@ void perform_dry_run(afl_state_t *afl) { #ifndef SIMPLE_FILES - snprintf(crash_fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s%s", - afl->out_dir, afl->saved_crashes, afl->fsrv.last_kill_signal, - describe_op(afl, 0, - NAME_MAX - strlen("id:000000,sig:00,") - - strlen(use_name)), - use_name); + snprintf( + crash_fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s%s%s%s", + afl->out_dir, afl->saved_crashes, afl->fsrv.last_kill_signal, + describe_op( + afl, 0, + NAME_MAX - strlen("id:000000,sig:00,") - strlen(use_name)), + use_name, afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #else - snprintf(crash_fn, PATH_MAX, "%s/crashes/id_%06llu_%02u", - afl->out_dir, afl->saved_crashes, - afl->fsrv.last_kill_signal); + snprintf( + crash_fn, PATH_MAX, "%s/crashes/id_%06llu_%02u%s%s", afl->out_dir, + afl->saved_crashes, afl->fsrv.last_kill_signal, + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #endif @@ -1439,7 +1443,9 @@ void pivot_inputs(afl_state_t *afl) { u32 src_id; afl->resuming_fuzz = 1; - nfn = alloc_printf("%s/queue/%s", afl->out_dir, rsl); + nfn = alloc_printf( + "%s/queue/%s%s%s", afl->out_dir, rsl, afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); /* Since we're at it, let's also get the parent and figure out the appropriate depth for this entry. */ @@ -1479,12 +1485,17 @@ void pivot_inputs(afl_state_t *afl) { } - nfn = alloc_printf("%s/queue/id:%06u,time:0,execs:%llu,orig:%s", - afl->out_dir, id, afl->fsrv.total_execs, use_name); + nfn = alloc_printf( + "%s/queue/id:%06u,time:0,execs:%llu,orig:%s%s%s", afl->out_dir, id, + afl->fsrv.total_execs, use_name, afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #else - nfn = alloc_printf("%s/queue/id_%06u", afl->out_dir, id); + nfn = alloc_printf( + "%s/queue/id_%06u%s%s", afl->out_dir, id, + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #endif /* ^!SIMPLE_FILES */ @@ -1921,6 +1932,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 +1967,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-redqueen.c b/src/afl-fuzz-redqueen.c index eead7a8b..be41d6c4 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -11,7 +11,7 @@ Andrea Fioraldi <andreafioraldi@gmail.com> Copyright 2016, 2017 Google Inc. All rights reserved. - Copyright 2019-2024 AFLplusplus Project. All rights reserved. + Copyright 2019-2023 AFLplusplus Project. 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. @@ -29,6 +29,7 @@ #include "cmplog.h" // #define _DEBUG +// #define USE_HASHMAP // #define CMPLOG_INTROSPECTION // CMP attribute enum @@ -87,6 +88,13 @@ static u32 hshape; static u64 screen_update; static u64 last_update; +#ifdef USE_HASHMAP +// hashmap functions +void hashmap_reset(); +bool hashmap_search_and_add(uint8_t type, uint64_t key); +bool hashmap_search_and_add_ptr(uint8_t type, u8 *key); +#endif + static struct range *add_range(struct range *ranges, u32 start, u32 end) { struct range *r = ck_alloc_nozero(sizeof(struct range)); @@ -795,7 +803,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 *o_buf_64 = (u64 *)&orig_buf[idx]; u32 *o_buf_32 = (u32 *)&orig_buf[idx]; u16 *o_buf_16 = (u16 *)&orig_buf[idx]; - u8 *o_buf_8 = &orig_buf[idx]; + // u8 *o_buf_8 = &orig_buf[idx]; u32 its_len = MIN(len - idx, taint_len); @@ -836,6 +844,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // necessary for preventing heap access overflow bytes = MIN(bytes, len - idx); + if (unlikely(bytes <= 1)) { return 0; } // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3 if (afl->cmplog_enable_transform && (lvl & LVL3)) { @@ -1266,6 +1275,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } + /* if (*status != 1) { // u8 // if (its_len >= 1) @@ -1290,6 +1300,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } + */ + } // If 'S' is set for cmplog mode then we try a scale encoding of the value. @@ -1881,6 +1893,8 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, hshape = SHAPE_BYTES(h->shape); + if (hshape < 2) { return 0; } + if (h->hits > CMP_MAP_H) { loggeds = CMP_MAP_H; @@ -1906,8 +1920,6 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, #endif - if (hshape < 2) { return 0; } - for (i = 0; i < loggeds; ++i) { struct cmp_operands *o = &afl->shm.cmp_map->log[key][i]; @@ -1945,6 +1957,19 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, } +#ifdef USE_HASHMAP + // TODO: add attribute? not sure + if (hshape <= 8 && hashmap_search_and_add(hshape - 1, o->v0) && + hashmap_search_and_add(hshape - 1, orig_o->v0) && + hashmap_search_and_add(hshape - 1, o->v1) && + hashmap_search_and_add(hshape - 1, orig_o->v1)) { + + continue; + + } + +#endif + #ifdef _DEBUG fprintf(stderr, "Handling: %llx->%llx vs %llx->%llx attr=%u shape=%u\n", orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, hshape); @@ -2219,15 +2244,15 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, } - if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 31 || l1 > 31 || - ol0 > 31 || ol1 > 31) { + if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 32 || l1 > 32 || + ol0 > 32 || ol1 > 32) { l0 = ol0 = hshape; } u8 lmax = MAX(l0, ol0); - u8 save[40]; + u8 save[80]; u32 saved_idx = idx, pre, from = 0, to = 0, i, j; u32 its_len = MIN(MIN(lmax, hshape), len - idx); its_len = MIN(its_len, taint_len); @@ -2330,7 +2355,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, u32 tob64 = 0, fromb64 = 0; u32 from_0 = 0, from_x = 0, from_X = 0, from_slash = 0, from_up = 0; u32 to_0 = 0, to_x = 0, to_slash = 0, to_up = 0; - u8 xor_val[32], arith_val[32], tmp[48]; + u8 xor_val[64], arith_val[64], tmp[64]; idx = saved_idx; its_len = saved_its_len; @@ -2615,12 +2640,13 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, } - memcpy(buf + idx, tmp, hlen + 1 + off); + u32 tmp_l = hlen + 1 + off; + memcpy(buf + idx, tmp, tmp_l); if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - tmp[hlen + 1 + off] = 0; + tmp[tmp_l] = 0; // fprintf(stderr, "RTN ATTEMPT idx=%u len=%u fromhex %u %s %s result // %u\n", idx, len, fromhex, tmp, repl, *status); - memcpy(buf + idx, save, hlen + 1 + off); + memcpy(buf + idx, save, tmp_l); } @@ -2755,6 +2781,18 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, fprintf(stderr, "\n"); #endif +#ifdef USE_HASHMAP + if (hshape <= 8 && hashmap_search_and_add_ptr(hshape - 1, o->v0) && + hashmap_search_and_add_ptr(hshape - 1, orig_o->v0) && + hashmap_search_and_add_ptr(hshape - 1, o->v1) && + hashmap_search_and_add_ptr(hshape - 1, orig_o->v1)) { + + continue; + + } + +#endif + t = taint; while (t->next) { @@ -3021,6 +3059,10 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) { // Start insertion loop +#ifdef USE_HASHMAP + hashmap_reset(); +#endif + u64 orig_hit_cnt, new_hit_cnt; u64 orig_execs = afl->fsrv.total_execs; orig_hit_cnt = afl->queued_items + afl->saved_crashes; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index d764952c..edcddc8e 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -409,6 +409,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, u32 use_tmout = afl->fsrv.exec_tmout; u8 *old_sn = afl->stage_name; + u64 calibration_start_us = get_cur_time_us(); if (unlikely(afl->shm.cmplog_mode)) { q->exec_cksum = 0; } /* Be a bit more generous about timeouts when resuming sessions, or when @@ -504,6 +505,10 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, fault = fuzz_run_target(afl, &afl->fsrv, use_tmout); + // update the time spend in calibration after each execution, as those may + // be slow + update_calibration_time(afl, &calibration_start_us); + /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed, we want to bail out quickly. */ @@ -650,6 +655,7 @@ abort_calibration: if (!first_run) { show_stats(afl); } + update_calibration_time(afl, &calibration_start_us); return fault; } @@ -669,11 +675,16 @@ void sync_fuzzers(afl_state_t *afl) { afl->stage_max = afl->stage_cur = 0; afl->cur_depth = 0; + u64 sync_start_us = get_cur_time_us(); /* Look at the entries created for every other fuzzer in the sync directory. */ while ((sd_ent = readdir(sd))) { + // since sync can take substantial amounts of time, update time spend every + // iteration + update_sync_time(afl, &sync_start_us); + u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX]; u32 min_accept = 0, next_min_accept = 0; @@ -811,7 +822,7 @@ void sync_fuzzers(afl_state_t *afl) { /* See what happens. We rely on save_if_interesting() to catch major errors and save the test case. */ - (void)write_to_testcase(afl, (void **)&mem, st.st_size, 1); + u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1); fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); @@ -819,7 +830,7 @@ void sync_fuzzers(afl_state_t *afl) { afl->syncing_party = sd_ent->d_name; afl->queued_imported += - save_if_interesting(afl, mem, st.st_size, fault); + save_if_interesting(afl, mem, new_len, fault); afl->syncing_party = 0; munmap(mem, st.st_size); @@ -861,6 +872,9 @@ void sync_fuzzers(afl_state_t *afl) { if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0); + // add time in sync one last time + update_sync_time(afl, &sync_start_us); + afl->last_sync_time = get_cur_time(); afl->last_sync_cycle = afl->queue_cycle; @@ -872,8 +886,9 @@ void sync_fuzzers(afl_state_t *afl) { u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { + u8 needs_write = 0, fault = 0; u32 orig_len = q->len; - + u64 trim_start_us = get_cur_time_us(); /* Custom mutator trimmer */ if (afl->custom_mutators_count) { @@ -897,11 +912,15 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } - if (custom_trimmed) return trimmed_case; + if (custom_trimmed) { + + fault = trimmed_case; + goto abort_trimming; + + } } - u8 needs_write = 0, fault = 0; u32 trim_exec = 0; u32 remove_len; u32 len_p2; @@ -912,7 +931,12 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { detected, it will still work to some extent, so we don't check for this. */ - if (unlikely(q->len < 5)) { return 0; } + if (unlikely(q->len < 5)) { + + fault = 0; + goto abort_trimming; + + } afl->stage_name = afl->stage_name_buf; afl->bytes_trim_in += q->len; @@ -946,6 +970,8 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); + update_trim_time(afl, &trim_start_us); + if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; } /* Note that we don't keep track of crashes or hangs here; maybe TODO? @@ -972,7 +998,6 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { /* Let's save a clean trace, which will be needed by update_bitmap_score once we're done with the trimming stuff. */ - if (!needs_write) { needs_write = 1; @@ -987,7 +1012,6 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } /* Since this can be slow, update the screen every now and then. */ - if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); } ++afl->stage_cur; @@ -1039,8 +1063,9 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } abort_trimming: - afl->bytes_trim_out += q->len; + update_trim_time(afl, &trim_start_us); + return fault; } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 4467cae8..c61f00bd 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -28,10 +28,6 @@ #include "afl-fuzz.h" #include "envs.h" -s8 interesting_8[] = {INTERESTING_8}; -s16 interesting_16[] = {INTERESTING_8, INTERESTING_16}; -s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32}; - char *power_names[POWER_SCHEDULES_NUM] = {"explore", "mmopt", "exploit", "fast", "coe", "lin", "quad", "rare", "seek"}; @@ -102,7 +98,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->stats_update_freq = 1; afl->stats_file_update_freq_msecs = STATS_UPDATE_SEC * 1000; afl->stats_avg_exec = 0; - afl->skip_deterministic = 1; + afl->skip_deterministic = 0; afl->sync_time = SYNC_TIME; afl->cmplog_lvl = 2; afl->min_length = 1; diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 76577081..7e1a3b92 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -133,6 +133,12 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { } +static bool starts_with(char *key, char *line) { + + return strncmp(key, line, strlen(key)) == 0; + +} + /* load some of the existing stats file when resuming.*/ void load_stats_file(afl_state_t *afl) { @@ -175,58 +181,84 @@ void load_stats_file(afl_state_t *afl) { strcpy(keystring, lstartptr); lptr++; char *nptr; - switch (lineno) { - - case 3: - if (!strcmp(keystring, "run_time ")) - afl->prev_run_time = 1000 * strtoull(lptr, &nptr, 10); - break; - case 5: - if (!strcmp(keystring, "cycles_done ")) - afl->queue_cycle = - strtoull(lptr, &nptr, 10) ? strtoull(lptr, &nptr, 10) + 1 : 0; - break; - case 7: - if (!strcmp(keystring, "execs_done ")) - afl->fsrv.total_execs = strtoull(lptr, &nptr, 10); - break; - case 10: - if (!strcmp(keystring, "corpus_count ")) { - - u32 corpus_count = strtoul(lptr, &nptr, 10); - if (corpus_count != afl->queued_items) { - - WARNF( - "queue/ has been modified -- things might not work, you're " - "on your own!"); - - } - - } - - break; - case 12: - if (!strcmp(keystring, "corpus_found ")) - afl->queued_discovered = strtoul(lptr, &nptr, 10); - break; - case 13: - if (!strcmp(keystring, "corpus_imported ")) - afl->queued_imported = strtoul(lptr, &nptr, 10); - break; - case 14: - if (!strcmp(keystring, "max_depth ")) - afl->max_depth = strtoul(lptr, &nptr, 10); - break; - case 21: - if (!strcmp(keystring, "saved_crashes ")) - afl->saved_crashes = strtoull(lptr, &nptr, 10); - break; - case 22: - if (!strcmp(keystring, "saved_hangs ")) - afl->saved_hangs = strtoull(lptr, &nptr, 10); - break; - default: - break; + if (starts_with("run_time", keystring)) { + + afl->prev_run_time = 1000 * strtoull(lptr, &nptr, 10); + + } + + if (starts_with("cycles_done", keystring)) { + + afl->queue_cycle = + strtoull(lptr, &nptr, 10) ? strtoull(lptr, &nptr, 10) + 1 : 0; + + } + + if (starts_with("calibration_time", keystring)) { + + afl->calibration_time_us = strtoull(lptr, &nptr, 10) * 1000000; + + } + + if (starts_with("sync_time", keystring)) { + + afl->sync_time_us = strtoull(lptr, &nptr, 10) * 1000000; + + } + + if (starts_with("trim_time", keystring)) { + + afl->trim_time_us = strtoull(lptr, &nptr, 10) * 1000000; + + } + + if (starts_with("execs_done", keystring)) { + + afl->fsrv.total_execs = strtoull(lptr, &nptr, 10); + + } + + if (starts_with("corpus_count", keystring)) { + + u32 corpus_count = strtoul(lptr, &nptr, 10); + if (corpus_count != afl->queued_items) { + + WARNF( + "queue/ has been modified -- things might not work, you're " + "on your own!"); + sleep(3); + + } + + } + + if (starts_with("corpus_found", keystring)) { + + afl->queued_discovered = strtoul(lptr, &nptr, 10); + + } + + if (starts_with("corpus_imported", keystring)) { + + afl->queued_imported = strtoul(lptr, &nptr, 10); + + } + + if (starts_with("max_depth", keystring)) { + + afl->max_depth = strtoul(lptr, &nptr, 10); + + } + + if (starts_with("saved_crashes", keystring)) { + + afl->saved_crashes = strtoull(lptr, &nptr, 10); + + } + + if (starts_with("saved_hangs", keystring)) { + + afl->saved_hangs = strtoull(lptr, &nptr, 10); } @@ -300,6 +332,10 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, "cycles_done : %llu\n" "cycles_wo_finds : %llu\n" "time_wo_finds : %llu\n" + "fuzz_time : %llu\n" + "calibration_time : %llu\n" + "sync_time : %llu\n" + "trim_time : %llu\n" "execs_done : %llu\n" "execs_per_sec : %0.02f\n" "execs_ps_last_min : %0.02f\n" @@ -337,7 +373,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, "\n" "target_mode : %s%s%s%s%s%s%s%s%s%s\n" "command_line : %s\n", - (afl->start_time - afl->prev_run_time) / 1000, cur_time / 1000, + (afl->start_time /*- afl->prev_run_time*/) / 1000, cur_time / 1000, runtime / 1000, (u32)getpid(), afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds, afl->longest_find_time > cur_time - afl->last_find_time @@ -345,7 +381,13 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, : ((afl->start_time == 0 || afl->last_find_time == 0) ? 0 : (cur_time - afl->last_find_time) / 1000), - afl->fsrv.total_execs, afl->fsrv.total_execs / ((double)(runtime) / 1000), + (runtime - + (afl->calibration_time_us + afl->sync_time_us + afl->trim_time_us) / + 1000) / + 1000, + afl->calibration_time_us / 1000000, afl->sync_time_us / 1000000, + afl->trim_time_us / 1000000, afl->fsrv.total_execs, + afl->fsrv.total_execs / ((double)(runtime) / 1000), afl->last_avg_execs_saved, afl->queued_items, afl->queued_favored, afl->queued_discovered, afl->queued_imported, afl->queued_variable, afl->max_depth, afl->current_entry, afl->pending_favored, @@ -876,6 +918,10 @@ void show_stats_normal(afl_state_t *afl) { #endif + if (banner_pad) + for (u32 i = 0; i < banner_pad; ++i) + strcat(banner, " "); + } SAYF("\n%s\n", banner); @@ -1112,7 +1158,7 @@ void show_stats_normal(afl_state_t *afl) { } else if (likely(afl->skip_deterministic)) { - strcpy(tmp, "disabled (default, enable with -D)"); + strcpy(tmp, "disabled (-z switch used)"); } else { @@ -2435,3 +2481,27 @@ void show_init_stats(afl_state_t *afl) { } +void update_calibration_time(afl_state_t *afl, u64 *time) { + + u64 cur = get_cur_time_us(); + afl->calibration_time_us += cur - *time; + *time = cur; + +} + +void update_trim_time(afl_state_t *afl, u64 *time) { + + u64 cur = get_cur_time_us(); + afl->trim_time_us += cur - *time; + *time = cur; + +} + +void update_sync_time(afl_state_t *afl, u64 *time) { + + u64 cur = get_cur_time_us(); + afl->sync_time_us += cur - *time; + *time = cur; + +} + diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 12d67fe7..00d24ab1 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -5,8 +5,9 @@ Originally written by Michal Zalewski Now maintained by Marc Heuse <mh@mh-sec.de>, - Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and - Andrea Fioraldi <andreafioraldi@gmail.com> + Dominik Meier <mail@dmnk.co>, + Andrea Fioraldi <andreafioraldi@gmail.com>, and + Heiko Eissfeldt <heiko.eissfeldt@hexco.de> Copyright 2016, 2017 Google Inc. All rights reserved. Copyright 2019-2024 AFLplusplus Project. All rights reserved. @@ -170,7 +171,6 @@ static void usage(u8 *argv0, int more_help) { " -g minlength - set min length of generated fuzz input (default: 1)\n" " -G maxlength - set max length of generated fuzz input (default: " "%lu)\n" - " -D - enable (a new) effective deterministic fuzzing\n" " -L minutes - use MOpt(imize) mode and set the time limit for " "entering the\n" " pacemaker mode (minutes of no new finds). 0 = " @@ -200,7 +200,8 @@ static void usage(u8 *argv0, int more_help) { "Test settings:\n" " -s seed - use a fixed seed for the RNG\n" - " -V seconds - fuzz for a specified time then terminate\n" + " -V seconds - fuzz for a specified time then terminate (fuzz time " + "only!)\n" " -E execs - fuzz for an approx. no. of total executions then " "terminate\n" " Note: not precise and can have several more " @@ -213,7 +214,8 @@ static void usage(u8 *argv0, int more_help) { " -F path - sync to a foreign fuzzer queue directory (requires " "-M, can\n" " be specified up to %u times)\n" - // " -d - skip deterministic fuzzing in -M mode\n" + " -z - skip the enhanced deterministic fuzzing\n" + " (note that the old -d and -D flags are ignored.)\n" " -T text - text banner to show on the screen\n" " -I command - execute this command/script when a new crash is " "found\n" @@ -401,6 +403,12 @@ static void usage(u8 *argv0, int more_help) { SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n"); #endif +#ifdef _AFL_SPECIAL_PERFORMANCE + SAYF( + "Compiled with special performance options for this specific system, it " + "might not work on other platforms!\n"); +#endif + SAYF("For additional help please consult %s/README.md :)\n\n", doc_path); exit(1); @@ -539,7 +547,7 @@ int main(int argc, char **argv_orig, char **envp) { // still available: HjJkKqruvwz while ((opt = getopt(argc, argv, "+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:" - "T:UV:WXx:YZ")) > 0) { + "T:UV:WXx:YzZ")) > 0) { switch (opt) { @@ -955,20 +963,17 @@ int main(int argc, char **argv_orig, char **envp) { break; - case 'D': /* partial deterministic */ + case 'd': + case 'D': /* old deterministic */ - afl->skip_deterministic = 0; + WARNF( + "Parameters -d and -D are deprecated, a new enhanced deterministic " + "fuzzing is active by default, to disable it use -z"); break; - case 'd': /* no deterministic */ + case 'z': /* no deterministic */ - // this is the default and currently a lot of infrastructure enforces - // it (e.g. clusterfuzz, fuzzbench) based on that this feature - // originally was bad performance wise. We now have a better - // implementation, hence if it is activated, we do not want to - // deactivate it by such setups. - - // afl->skip_deterministic = 1; + afl->skip_deterministic = 1; break; case 'B': /* load bitmap */ @@ -1232,6 +1237,7 @@ int main(int argc, char **argv_orig, char **envp) { } + afl->old_seed_selection = 1; u64 limit_time_puppet2 = afl->limit_time_puppet * 60 * 1000; if ((s32)limit_time_puppet2 < afl->limit_time_puppet) { @@ -2069,6 +2075,17 @@ int main(int argc, char **argv_orig, char **envp) { } + /* Simply code if AFL_TMPDIR is used or not */ + if (!afl->afl_env.afl_tmpdir) { + + afl->tmp_dir = afl->out_dir; + + } else { + + afl->tmp_dir = afl->afl_env.afl_tmpdir; + + } + write_setup_file(afl, argc, argv); setup_cmdline_file(afl, argv + optind); @@ -2081,8 +2098,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!afl->timeout_given) { find_timeout(afl); } // only for resumes! - if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL && - !afl->in_place_resume) { + if (afl->afl_env.afl_tmpdir && !afl->in_place_resume) { char tmpfile[PATH_MAX]; @@ -2107,10 +2123,6 @@ int main(int argc, char **argv_orig, char **envp) { } - } else { - - afl->tmp_dir = afl->out_dir; - } /* If we don't have a file name chosen yet, use a safe default. */ @@ -2182,7 +2194,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); } @@ -2489,8 +2501,15 @@ int main(int argc, char **argv_orig, char **envp) { for (entry = 0; entry < afl->queued_items; ++entry) if (!afl->queue_buf[entry]->disabled) - if (afl->queue_buf[entry]->exec_us > max_ms) - max_ms = afl->queue_buf[entry]->exec_us; + if ((afl->queue_buf[entry]->exec_us / 1000) > max_ms) + max_ms = afl->queue_buf[entry]->exec_us / 1000; + + // Add 20% as a safety margin, capped to exec_tmout given in -t option + max_ms *= 1.2; + if (max_ms > afl->fsrv.exec_tmout) max_ms = afl->fsrv.exec_tmout; + + // Ensure that there is a sensible timeout even for very fast binaries + if (max_ms < 5) max_ms = 5; afl->fsrv.exec_tmout = max_ms; afl->timeout_given = 1; @@ -2526,8 +2545,6 @@ int main(int argc, char **argv_orig, char **envp) { } // (void)nice(-20); // does not improve the speed - // real start time, we reset, so this works correctly with -V - afl->start_time = get_cur_time(); #ifdef INTROSPECTION u32 prev_saved_crashes = 0, prev_saved_tmouts = 0; @@ -2548,6 +2565,9 @@ int main(int argc, char **argv_orig, char **envp) { OKF("Writing mutation introspection to '%s'", ifn); #endif + // real start time, we reset, so this works correctly with -V + afl->start_time = get_cur_time(); + while (likely(!afl->stop_soon)) { cull_queue(afl); @@ -2568,6 +2588,13 @@ int main(int argc, char **argv_orig, char **envp) { sync_fuzzers(afl); + if (!afl->queue_cycle && afl->afl_env.afl_import_first) { + + // real start time, we reset, so this works correctly with -V + afl->start_time = get_cur_time(); + + } + } ++afl->queue_cycle; @@ -3057,7 +3084,7 @@ stop_fuzzing: afl_fsrv_deinit(&afl->fsrv); /* remove tmpfile */ - if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) { + if (!afl->in_place_resume && afl->fsrv.out_file) { (void)unlink(afl->fsrv.out_file); diff --git a/src/afl-performance.c b/src/afl-performance.c index 07c1b527..f730ca53 100644 --- a/src/afl-performance.c +++ b/src/afl-performance.c @@ -2,9 +2,17 @@ #include "afl-fuzz.h" #include "types.h" -#define XXH_INLINE_ALL -#include "xxhash.h" -#undef XXH_INLINE_ALL +#ifdef _HAVE_AVX2 + #define T1HA0_AESNI_AVAILABLE 1 + #define T1HA_USE_FAST_ONESHOT_READ 1 + #define T1HA_USE_INDIRECT_FUNCTIONS 1 + #define T1HA_IA32AES_NAME XXH3_64bits + #include "t1ha0_ia32aes_b.h" +#else + #define XXH_INLINE_ALL + #include "xxhash.h" + #undef XXH_INLINE_ALL +#endif void rand_set_seed(afl_state_t *afl, s64 init_seed) { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 4e5dab41..994174ed 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -82,6 +82,8 @@ static u8 crash_mode, /* Crash-centric mode? */ remove_shm = 1, /* remove shmem on exit? */ debug; /* debug mode */ +static u32 del_len_limit = 1; /* Minimum block deletion length */ + static volatile u8 stop_soon; /* Ctrl-C pressed? */ static afl_forkserver_t *fsrv; @@ -480,7 +482,7 @@ next_del_blksize: } - if (del_len > 1 && in_len >= 1) { + if (del_len > del_len_limit && in_len >= 1) { del_len /= 2; goto next_del_blksize; @@ -796,8 +798,9 @@ static void usage(u8 *argv0) { "Minimization settings:\n" " -e - solve for edge coverage only, ignore hit counts\n" - " -x - treat non-zero exit codes as crashes\n\n" - " -H - minimize a hang (hang mode)\n" + " -l bytes - set minimum block deletion length to speed up minimization\n" + " -x - treat non-zero exit codes as crashes\n" + " -H - minimize a hang (hang mode)\n\n" "For additional tips, please consult %s/README.md.\n\n" @@ -829,8 +832,9 @@ static void usage(u8 *argv0) { int main(int argc, char **argv_orig, char **envp) { - s32 opt; - u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; + s32 opt; + u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0, + del_limit_given = 0; char **use_argv; char **argv = argv_cpy_dup(argc, argv_orig); @@ -846,7 +850,7 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n"); - while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWXYHh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:l:B:xeAOQUWXYHh")) > 0) { switch (opt) { @@ -1055,6 +1059,24 @@ int main(int argc, char **argv_orig, char **envp) { read_bitmap(optarg, mask_bitmap, map_size); break; + case 'l': + if (del_limit_given) { FATAL("Multiple -l options not supported"); } + del_limit_given = 1; + + if (!optarg) { FATAL("Wrong usage of -l"); } + + if (optarg[0] == '-') { FATAL("Dangerously low value of -l"); } + + del_len_limit = atoi(optarg); + + if (del_len_limit < 1 || del_len_limit > TMIN_MAX_FILE) { + + FATAL("Value of -l out of range between 1 and TMIN_MAX_FILE"); + + } + + break; + case 'h': usage(argv[0]); return -1; diff --git a/src/hashmap.c b/src/hashmap.c new file mode 100644 index 00000000..a0a9283c --- /dev/null +++ b/src/hashmap.c @@ -0,0 +1,149 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include "types.h" +#define TABLE_SIZE 10007 // Use a prime number for better distribution + +typedef struct HashNode { + + uint64_t key; + struct HashNode *next; + +} HashNode; + +typedef struct HashMap { + + HashNode **table; + +} HashMap; + +static HashMap *_hashmap; + +void hashmap_reset() { + + if (unlikely(!_hashmap)) { + + _hashmap = (HashMap *)malloc(sizeof(HashMap)); + _hashmap->table = (HashNode **)malloc(sizeof(HashNode *) * TABLE_SIZE); + memset((char *)_hashmap->table, 0, sizeof(HashNode *) * TABLE_SIZE); + + } else { + + for (int i = 0; i < TABLE_SIZE; i++) { + + HashNode *node = _hashmap->table[i]; + while (node) { + + HashNode *temp = node; + node = node->next; + free(temp); + + } + + } + + memset((char *)_hashmap->table, 0, sizeof(HashNode *) * TABLE_SIZE); + + } + +} + +static inline unsigned int hash(uint64_t key) { + + return key % TABLE_SIZE; + +} + +// type must be below 8 +bool hashmap_search_and_add(uint8_t type, uint64_t key) { + + if (unlikely(type >= 8)) return false; + uint64_t val = (key & 0xf8ffffffffffffff) + (type << 56); + unsigned int index = hash(val); + HashNode *node = _hashmap->table[index]; + while (node) { + + if (node->key == val) return true; + node = node->next; + + } + + // not found so add it + node = (HashNode *)malloc(sizeof(HashNode)); + node->key = val; + node->next = _hashmap->table[index]; + _hashmap->table[index] = node; + + return false; + +} + +// type must be below 8 +bool hashmap_search_and_add_ptr(uint8_t type, u8 *key) { + + if (unlikely(type >= 8)) return false; + uint64_t key_t = 0; + memcpy(((char *)key_t) + (7 - type), key, type + 1); + return hashmap_search_and_add(type, key_t); + +} + +/* below is not used */ + +void hashmap_insert(uint64_t key) { + + unsigned int index = hash(key); + HashNode *node = (HashNode *)malloc(sizeof(HashNode)); + node->key = key; + node->next = _hashmap->table[index]; + _hashmap->table[index] = node; + +} + +bool hashmap_search(uint64_t key) { + + unsigned int index = hash(key); + HashNode *node = _hashmap->table[index]; + while (node) { + + if (node->key == key) return true; + node = node->next; + + } + + return false; + +} + +void delete(uint64_t key) { + + unsigned int index = hash(key); + HashNode *prev = NULL, *node = _hashmap->table[index]; + while (node) { + + if (node->key == key) { + + if (prev) + prev->next = node->next; + else + _hashmap->table[index] = node->next; + free(node); + return; + + } + + prev = node; + node = node->next; + + } + +} + +void freeHashMap(HashMap *map) { + + free(_hashmap->table); + free(map); + +} + |