diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/README.md | 24 | ||||
-rw-r--r-- | src/README.src | 22 | ||||
-rw-r--r-- | src/afl-analyze.c | 27 | ||||
-rw-r--r-- | src/afl-common.c | 435 | ||||
-rw-r--r-- | src/afl-forkserver.c | 292 | ||||
-rw-r--r-- | src/afl-fuzz-bitmap.c | 169 | ||||
-rw-r--r-- | src/afl-fuzz-cmplog.c | 597 | ||||
-rw-r--r-- | src/afl-fuzz-extras.c | 35 | ||||
-rw-r--r-- | src/afl-fuzz-init.c | 88 | ||||
-rw-r--r-- | src/afl-fuzz-misc.c | 186 | ||||
-rw-r--r-- | src/afl-fuzz-mutators.c | 147 | ||||
-rw-r--r-- | src/afl-fuzz-one.c | 490 | ||||
-rw-r--r-- | src/afl-fuzz-python.c | 318 | ||||
-rw-r--r-- | src/afl-fuzz-queue.c | 119 | ||||
-rw-r--r-- | src/afl-fuzz-redqueen.c | 21 | ||||
-rw-r--r-- | src/afl-fuzz-run.c | 202 | ||||
-rw-r--r-- | src/afl-fuzz-state.c (renamed from src/afl-fuzz-globals.c) | 54 | ||||
-rw-r--r-- | src/afl-fuzz-stats.c | 368 | ||||
-rw-r--r-- | src/afl-fuzz.c | 153 | ||||
-rw-r--r-- | src/afl-gcc.c | 10 | ||||
-rw-r--r-- | src/afl-gotcpu.c | 2 | ||||
-rw-r--r-- | src/afl-sharedmem.c | 2 | ||||
-rw-r--r-- | src/afl-showmap.c | 59 | ||||
-rw-r--r-- | src/afl-tmin.c | 197 | ||||
-rw-r--r-- | src/third_party/libradamsa/GNUmakefile (renamed from src/third_party/libradamsa/Makefile) | 0 | ||||
-rw-r--r-- | src/third_party/libradamsa/libradamsa.c | 8 | ||||
-rw-r--r-- | src/third_party/libradamsa/radamsa.h | 14 |
27 files changed, 1918 insertions, 2121 deletions
diff --git a/src/README.md b/src/README.md new file mode 100644 index 00000000..6da534c3 --- /dev/null +++ b/src/README.md @@ -0,0 +1,24 @@ +# Source Folder + +Quick explanation about the files here: + +- `afl-analyze.c` - afl-analyze binary tool +- `afl-as.c` - afl-as binary tool +- `afl-gotcpu.c` - afl-gotcpu binary tool +- `afl-showmap.c` - afl-showmap binary tool +- `afl-tmin.c` - afl-tmin binary tool +- `afl-fuzz.c` - afl-fuzz binary tool (just main() and usage()) +- `afl-fuzz-bitmap.c` - afl-fuzz bitmap handling +- `afl-fuzz-extras.c` - afl-fuzz the *extra* function calls +- `afl-fuzz-state.c` - afl-fuzz state and globals +- `afl-fuzz-init.c` - afl-fuzz initialization +- `afl-fuzz-misc.c` - afl-fuzz misc functions +- `afl-fuzz-one.c` - afl-fuzz fuzzer_one big loop, this is where the mutation is happening +- `afl-fuzz-python.c` - afl-fuzz the python mutator extension +- `afl-fuzz-queue.c` - afl-fuzz handling the queue +- `afl-fuzz-run.c` - afl-fuzz running the target +- `afl-fuzz-stats.c` - afl-fuzz writing the statistics file +- `afl-gcc.c` - afl-gcc binary tool (deprecated) +- `afl-common.c` - common functions, used by afl-analyze, afl-fuzz, afl-showmap and afl-tmin +- `afl-forkserver.c` - forkserver implementation, used by afl-fuzz and afl-tmin +afl-sharedmem.c - sharedmem implementation, used by afl-fuzz and afl-tmin diff --git a/src/README.src b/src/README.src deleted file mode 100644 index 244f5ddd..00000000 --- a/src/README.src +++ /dev/null @@ -1,22 +0,0 @@ -Quick explanation about the files here: - -afl-analyze.c - afl-analyze binary tool -afl-as.c - afl-as binary tool -afl-gotcpu.c - afl-gotcpu binary tool -afl-showmap.c - afl-showmap binary tool -afl-tmin.c - afl-tmin binary tool -afl-fuzz.c - afl-fuzz binary tool (just main() and usage()) -afl-fuzz-bitmap.c - afl-fuzz bitmap handling -afl-fuzz-extras.c - afl-fuzz the *extra* function calls -afl-fuzz-globals.c - afl-fuzz global variables -afl-fuzz-init.c - afl-fuzz initialization -afl-fuzz-misc.c - afl-fuzz misc functions -afl-fuzz-one.c - afl-fuzz fuzzer_one big loop, this is where the mutation is happening -afl-fuzz-python.c - afl-fuzz the python mutator extension -afl-fuzz-queue.c - afl-fuzz handling the queue -afl-fuzz-run.c - afl-fuzz running the target -afl-fuzz-stats.c - afl-fuzz writing the statistics file -afl-gcc.c - afl-gcc binary tool (deprecated) -afl-common.c - common functions, used by afl-analyze, afl-fuzz, afl-showmap and afl-tmin -afl-forkserver.c - forkserver implementation, used by afl-fuzz and afl-tmin -afl-sharedmem.c - sharedmem implementation, used by afl-fuzz and afl-tmin diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 2148cdf0..510ec94a 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -36,6 +36,7 @@ #include "hash.h" #include "sharedmem.h" #include "common.h" +#include "forkserver.h" #include <stdio.h> #include <unistd.h> @@ -57,11 +58,10 @@ static s32 child_pid; /* PID of the tested program */ -u8 *trace_bits; /* SHM with instrumentation bitmap */ +static u8 *trace_bits; /* SHM with instrumentation bitmap */ static u8 *in_file, /* Analyzer input test case */ - *prog_in, /* Targeted program input file */ - *doc_path; /* Path to docs */ + *prog_in; /* Targeted program input file */ static u8 *in_data; /* Input data for analysis */ @@ -75,16 +75,15 @@ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ static s32 dev_null_fd = -1; /* FD to /dev/null */ -u8 edges_only, /* Ignore hit counts? */ +static u8 edges_only, /* Ignore hit counts? */ use_hex_offsets, /* Show hex offsets? */ - be_quiet, use_stdin = 1; /* Use stdin for program input? */ + use_stdin = 1; /* Use stdin for program input? */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_timed_out; /* Child timed out? */ -static u8 qemu_mode; - static u8 *target_path; +static u8 qemu_mode; /* Constants used for describing byte behavior. */ @@ -207,15 +206,6 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) { } -/* Handle timeout signal. */ - -static void handle_timeout(int sig) { - - child_timed_out = 1; - if (child_pid > 0) kill(child_pid, SIGKILL); - -} - /* Execute target application. Returns exec checksum, or 0 if program times out. */ @@ -770,11 +760,6 @@ static void setup_signal_handlers(void) { sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); - /* Exec timeout notifications. */ - - sa.sa_handler = handle_timeout; - sigaction(SIGALRM, &sa, NULL); - } /* Display usage hints. */ diff --git a/src/afl-common.c b/src/afl-common.c index 1aa15442..7eba6ae4 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -30,6 +30,7 @@ #include "debug.h" #include "alloc-inl.h" #include "envs.h" +#include "common.h" /* Detect @@ in args. */ #ifndef __glibc__ @@ -37,8 +38,11 @@ #endif #include <limits.h> -extern u8 be_quiet; -char * afl_environment_variables[] = { +u8 be_quiet = 0; +u8 *doc_path = ""; +u8 last_intr = 0; + +char *afl_environment_variables[] = { "AFL_ALIGNED_ALLOC", "AFL_ALLOW_TMP", "AFL_ANALYZE_HEX", "AFL_AS", "AFL_AUTORESUME", "AFL_AS_FORCE_INSTRUMENT", "AFL_BENCH_JUST_ONE", @@ -54,10 +58,12 @@ char * afl_environment_variables[] = { "AFL_INST_LIBS", "AFL_INST_RATIO", "AFL_KEEP_TRACES", "AFL_KEEP_ASSEMBLY", "AFL_LD_HARD_FAIL", "AFL_LD_LIMIT_MB", "AFL_LD_NO_CALLOC_OVER", "AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", - "AFL_LLVM_INSTRIM_LOOPHEAD", "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", - "AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", - "AFL_LLVM_LAF_SPLIT_FLOATS", "AFL_LLVM_LAF_SPLIT_SWITCHES", - "AFL_LLVM_LAF_TRANSFORM_COMPARES", "AFL_LLVM_NOT_ZERO", + "AFL_LLVM_CTX", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD", + "AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY", + "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_LAF_SPLIT_COMPARES", + "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_FLOATS", + "AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES", + "AFL_LLVM_NGRAM_SIZE", "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST", "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", "AFL_NO_BUILTIN", "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI", @@ -73,7 +79,8 @@ char * afl_environment_variables[] = { "AFL_SHUFFLE_QUEUE", "AFL_SKIP_BIN_CHECK", "AFL_SKIP_CPUFREQ", "AFL_SKIP_CRASHES", "AFL_TMIN_EXACT", "AFL_TMPDIR", "AFL_TOKEN_FILE", "AFL_TRACE_PC", "AFL_USE_ASAN", "AFL_USE_MSAN", "AFL_USE_TRACE_PC", - "AFL_USE_UBSAN", "AFL_WINE_PATH", NULL}; + "AFL_USE_UBSAN", "AFL_USE_CFISAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", + NULL}; void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) { @@ -134,7 +141,7 @@ void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) { char **argv_cpy_dup(int argc, char **argv) { - u32 i = 0; + int i = 0; char **ret = ck_alloc((argc + 1) * sizeof(char *)); @@ -228,7 +235,7 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { "Oops, unable to find the 'afl-qemu-trace' binary. The binary must be " "built\n" " separately by following the instructions in " - "afl->qemu_mode/README.md. " + "qemu_mode/README.md. " "If you\n" " already have the binary installed, you may need to specify " "AFL_PATH in the\n" @@ -325,7 +332,7 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) { "Oops, unable to find the '%s' binary. The binary must be " "built\n" " separately by following the instructions in " - "afl->qemu_mode/README.md. " + "qemu_mode/README.md. " "If you\n" " already have the binary installed, you may need to specify " "AFL_PATH in the\n" @@ -348,7 +355,7 @@ void check_environment_vars(char **envp) { if (be_quiet) return; int index = 0, found = 0; - char *env; + char *env, *val; while ((env = envp[index++]) != NULL) { if (strncmp(env, "ALF_", 4) == 0) { @@ -362,10 +369,21 @@ void check_environment_vars(char **envp) { while (match == 0 && afl_environment_variables[i] != NULL) if (strncmp(env, afl_environment_variables[i], strlen(afl_environment_variables[i])) == 0 && - env[strlen(afl_environment_variables[i])] == '=') + env[strlen(afl_environment_variables[i])] == '=') { + match = 1; - else + if ((val = getenv(afl_environment_variables[i])) && !*val) + WARNF( + "AFL environment variable %s defined but is empty, this can " + "lead to unexpected consequences", + afl_environment_variables[i]); + + } else { + i++; + + } + if (match == 0) { WARNF("Mistyped AFL environment variable: %s", env); @@ -393,3 +411,394 @@ char *get_afl_env(char *env) { } +u64 get_cur_time(void) { + + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + + return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000); + +} + +/* Get unix time in microseconds */ + +u64 get_cur_time_us(void) { + + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + + return (tv.tv_sec * 1000000ULL) + tv.tv_usec; + +} + +/* Describe integer. The buf should be + at least 6 bytes to fit all ints we randomly see. + Will return buf for convenience. */ + +u8 *stringify_int(u8 *buf, size_t len, u64 val) { +\ +#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \ + do { \ + \ + if (val < (_divisor) * (_limit_mult)) { \ + \ + snprintf(buf, len, _fmt, ((_cast)val) / (_divisor)); \ + return buf; \ + \ + } \ + \ + } while (0) + + /* 0-9999 */ + CHK_FORMAT(1, 10000, "%llu", u64); + + /* 10.0k - 99.9k */ + CHK_FORMAT(1000, 99.95, "%0.01fk", double); + + /* 100k - 999k */ + CHK_FORMAT(1000, 1000, "%lluk", u64); + + /* 1.00M - 9.99M */ + CHK_FORMAT(1000 * 1000, 9.995, "%0.02fM", double); + + /* 10.0M - 99.9M */ + CHK_FORMAT(1000 * 1000, 99.95, "%0.01fM", double); + + /* 100M - 999M */ + CHK_FORMAT(1000 * 1000, 1000, "%lluM", u64); + + /* 1.00G - 9.99G */ + CHK_FORMAT(1000LL * 1000 * 1000, 9.995, "%0.02fG", double); + + /* 10.0G - 99.9G */ + CHK_FORMAT(1000LL * 1000 * 1000, 99.95, "%0.01fG", double); + + /* 100G - 999G */ + CHK_FORMAT(1000LL * 1000 * 1000, 1000, "%lluG", u64); + + /* 1.00T - 9.99G */ + CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 9.995, "%0.02fT", double); + + /* 10.0T - 99.9T */ + CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 99.95, "%0.01fT", double); + + /* 100T+ */ + strncpy(buf, "infty", len); + buf[len - 1] = '\0'; + + return buf; + +} + +/* Describe float. Similar as int. */ + +u8 *stringify_float(u8 *buf, size_t len, double val) { + + if (val < 99.995) { + + snprintf(buf, len, "%0.02f", val); + + } else if (val < 999.95) { + + snprintf(buf, len, "%0.01f", val); + + } else { + + stringify_int(buf, len, (u64)val); + + } + + return buf; + +} + +/* Describe integer as memory size. */ + +u8 *stringify_mem_size(u8 *buf, size_t len, u64 val) { + + /* 0-9999 */ + CHK_FORMAT(1, 10000, "%llu B", u64); + + /* 10.0k - 99.9k */ + CHK_FORMAT(1024, 99.95, "%0.01f kB", double); + + /* 100k - 999k */ + CHK_FORMAT(1024, 1000, "%llu kB", u64); + + /* 1.00M - 9.99M */ + CHK_FORMAT(1024 * 1024, 9.995, "%0.02f MB", double); + + /* 10.0M - 99.9M */ + CHK_FORMAT(1024 * 1024, 99.95, "%0.01f MB", double); + + /* 100M - 999M */ + CHK_FORMAT(1024 * 1024, 1000, "%llu MB", u64); + + /* 1.00G - 9.99G */ + CHK_FORMAT(1024LL * 1024 * 1024, 9.995, "%0.02f GB", double); + + /* 10.0G - 99.9G */ + CHK_FORMAT(1024LL * 1024 * 1024, 99.95, "%0.01f GB", double); + + /* 100G - 999G */ + CHK_FORMAT(1024LL * 1024 * 1024, 1000, "%llu GB", u64); + + /* 1.00T - 9.99G */ + CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 9.995, "%0.02f TB", double); + + /* 10.0T - 99.9T */ + CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 99.95, "%0.01f TB", double); + +#undef CHK_FORMAT + + /* 100T+ */ + strncpy(buf, "infty", len - 1); + buf[len - 1] = '\0'; + + return buf; + +} + +/* Describe time delta as string. + Returns a pointer to buf for convenience. */ + +u8 *stringify_time_diff(u8 *buf, size_t len, u64 cur_ms, u64 event_ms) { + + u64 delta; + s32 t_d, t_h, t_m, t_s; + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + + if (!event_ms) { + + snprintf(buf, len, "none seen yet"); + + } else { + + delta = cur_ms - event_ms; + + t_d = delta / 1000 / 60 / 60 / 24; + t_h = (delta / 1000 / 60 / 60) % 24; + t_m = (delta / 1000 / 60) % 60; + t_s = (delta / 1000) % 60; + + stringify_int(val_buf, sizeof(val_buf), t_d); + snprintf(buf, len, "%s days, %d hrs, %d min, %d sec", val_buf, t_h, t_m, + t_s); + + } + + return buf; + +} + +/* Unsafe Describe integer. The buf sizes are not checked. + This is unsafe but fast. + Will return buf for convenience. */ + +u8 *u_stringify_int(u8 *buf, u64 val) { +\ +#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \ + do { \ + \ + if (val < (_divisor) * (_limit_mult)) { \ + \ + sprintf(buf, _fmt, ((_cast)val) / (_divisor)); \ + return buf; \ + \ + } \ + \ + } while (0) + + /* 0-9999 */ + CHK_FORMAT(1, 10000, "%llu", u64); + + /* 10.0k - 99.9k */ + CHK_FORMAT(1000, 99.95, "%0.01fk", double); + + /* 100k - 999k */ + CHK_FORMAT(1000, 1000, "%lluk", u64); + + /* 1.00M - 9.99M */ + CHK_FORMAT(1000 * 1000, 9.995, "%0.02fM", double); + + /* 10.0M - 99.9M */ + CHK_FORMAT(1000 * 1000, 99.95, "%0.01fM", double); + + /* 100M - 999M */ + CHK_FORMAT(1000 * 1000, 1000, "%lluM", u64); + + /* 1.00G - 9.99G */ + CHK_FORMAT(1000LL * 1000 * 1000, 9.995, "%0.02fG", double); + + /* 10.0G - 99.9G */ + CHK_FORMAT(1000LL * 1000 * 1000, 99.95, "%0.01fG", double); + + /* 100G - 999G */ + CHK_FORMAT(1000LL * 1000 * 1000, 1000, "%lluG", u64); + + /* 1.00T - 9.99G */ + CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 9.995, "%0.02fT", double); + + /* 10.0T - 99.9T */ + CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 99.95, "%0.01fT", double); + + /* 100T+ */ + strcpy(buf, "infty"); + + return buf; + +} + +/* Unsafe describe float. Similar as unsafe int. */ + +u8 *u_stringify_float(u8 *buf, double val) { + + if (val < 99.995) { + + sprintf(buf, "%0.02f", val); + + } else if (val < 999.95) { + + sprintf(buf, "%0.01f", val); + + } else { + + return u_stringify_int(buf, (u64)val); + + } + + return buf; + +} + +/* Unsafe describe integer as memory size. */ + +u8 *u_stringify_mem_size(u8 *buf, u64 val) { + + /* 0-9999 */ + CHK_FORMAT(1, 10000, "%llu B", u64); + + /* 10.0k - 99.9k */ + CHK_FORMAT(1024, 99.95, "%0.01f kB", double); + + /* 100k - 999k */ + CHK_FORMAT(1024, 1000, "%llu kB", u64); + + /* 1.00M - 9.99M */ + CHK_FORMAT(1024 * 1024, 9.995, "%0.02f MB", double); + + /* 10.0M - 99.9M */ + CHK_FORMAT(1024 * 1024, 99.95, "%0.01f MB", double); + + /* 100M - 999M */ + CHK_FORMAT(1024 * 1024, 1000, "%llu MB", u64); + + /* 1.00G - 9.99G */ + CHK_FORMAT(1024LL * 1024 * 1024, 9.995, "%0.02f GB", double); + + /* 10.0G - 99.9G */ + CHK_FORMAT(1024LL * 1024 * 1024, 99.95, "%0.01f GB", double); + + /* 100G - 999G */ + CHK_FORMAT(1024LL * 1024 * 1024, 1000, "%llu GB", u64); + + /* 1.00T - 9.99G */ + CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 9.995, "%0.02f TB", double); + + /* 10.0T - 99.9T */ + CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 99.95, "%0.01f TB", double); + +#undef CHK_FORMAT + + /* 100T+ */ + strcpy(buf, "infty"); + + return buf; + +} + +/* Unsafe describe time delta as string. + Returns a pointer to buf for convenience. */ + +u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) { + + u64 delta; + s32 t_d, t_h, t_m, t_s; + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + + if (!event_ms) { + + sprintf(buf, "none seen yet"); + + } else { + + delta = cur_ms - event_ms; + + t_d = delta / 1000 / 60 / 60 / 24; + t_h = (delta / 1000 / 60 / 60) % 24; + t_m = (delta / 1000 / 60) % 60; + t_s = (delta / 1000) % 60; + + u_stringify_int(val_buf, t_d); + sprintf(buf, "%s days, %d hrs, %d min, %d sec", val_buf, t_h, t_m, t_s); + + } + + return buf; + +} + +/* Wrapper for select() and read(), reading exactly len bytes. + Returns the time passed to read. + If the wait times out, returns timeout_ms + 1; + Returns 0 if an error occurred (fd closed, signal, ...); */ +u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms, + volatile u8 *stop_soon_p) { + + struct timeval timeout; + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + timeout.tv_sec = (timeout_ms / 1000); + timeout.tv_usec = (timeout_ms % 1000) * 1000; + + size_t read_total = 0; + size_t len_read = 0; + + while (len_read < len) { + + /* set exceptfds as well to return when a child exited/closed the pipe. */ + int sret = select(fd + 1, &readfds, NULL, NULL, &timeout); + + if (!sret) { + + // printf("Timeout in sret."); + return timeout_ms + 1; + + } else if (sret < 0) { + + /* Retry select for all signals other than than ctrl+c */ + if (errno == EINTR && !*stop_soon_p) { continue; } + return 0; + + } + + len_read = read(fd, ((u8 *)buf) + len_read, len - len_read); + if (!len_read) { return 0; } + read_total += len_read; + + } + + s32 exec_ms = + MIN(timeout_ms, + ((u64)timeout_ms - (timeout.tv_sec * 1000 + timeout.tv_usec / 1000))); + return exec_ms > 0 ? exec_ms + : 1; // at least 1 milli must have passed (0 is an error) + +} + diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index c7a3475f..28f664fa 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -49,90 +49,11 @@ /* Describe integer as memory size. */ -extern u8 *doc_path; - -u8 *forkserver_DMS(u64 val) { - - static u8 tmp[12][16]; - static u8 cur; - -#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \ - do { \ - \ - if (val < (_divisor) * (_limit_mult)) { \ - \ - sprintf(tmp[cur], _fmt, ((_cast)val) / (_divisor)); \ - return tmp[cur]; \ - \ - } \ - \ - } while (0) - - cur = (cur + 1) % 12; - - /* 0-9999 */ - CHK_FORMAT(1, 10000, "%llu B", u64); - - /* 10.0k - 99.9k */ - CHK_FORMAT(1024, 99.95, "%0.01f kB", double); - - /* 100k - 999k */ - CHK_FORMAT(1024, 1000, "%llu kB", u64); - - /* 1.00M - 9.99M */ - CHK_FORMAT(1024 * 1024, 9.995, "%0.02f MB", double); - - /* 10.0M - 99.9M */ - CHK_FORMAT(1024 * 1024, 99.95, "%0.01f MB", double); - - /* 100M - 999M */ - CHK_FORMAT(1024 * 1024, 1000, "%llu MB", u64); - - /* 1.00G - 9.99G */ - CHK_FORMAT(1024LL * 1024 * 1024, 9.995, "%0.02f GB", double); - - /* 10.0G - 99.9G */ - CHK_FORMAT(1024LL * 1024 * 1024, 99.95, "%0.01f GB", double); - - /* 100G - 999G */ - CHK_FORMAT(1024LL * 1024 * 1024, 1000, "%llu GB", u64); - - /* 1.00T - 9.99G */ - CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 9.995, "%0.02f TB", double); - - /* 10.0T - 99.9T */ - CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 99.95, "%0.01f TB", double); - -#undef CHK_FORMAT - - /* 100T+ */ - strcpy(tmp[cur], "infty"); - return tmp[cur]; - -} - list_t fsrv_list = {.element_prealloc_count = 0}; -/* the timeout handler */ - -void handle_timeout(int sig) { - - LIST_FOREACH(&fsrv_list, afl_forkserver_t, { - - // TODO: We need a proper timer to handle multiple timeouts - if (el->child_pid > 0) { +static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) { - el->child_timed_out = 1; - kill(el->child_pid, SIGKILL); - - } else if (el->child_pid == -1 && el->fsrv_pid > 0) { - - el->child_timed_out = 1; - kill(el->fsrv_pid, SIGKILL); - - } - - }); + execv(fsrv->target_path, argv); } @@ -153,21 +74,51 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->exec_tmout = EXEC_TIMEOUT; fsrv->mem_limit = MEM_LIMIT; fsrv->child_pid = -1; - fsrv->out_dir_fd = -1; - + fsrv->map_size = MAP_SIZE; fsrv->use_fauxsrv = 0; + fsrv->prev_timed_out = 0; + + fsrv->init_child_func = fsrv_exec_child; list_append(&fsrv_list, fsrv); } +/* Initialize a new forkserver instance, duplicating "global" settings */ +void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { + + fsrv_to->use_stdin = from->use_stdin; + fsrv_to->dev_null_fd = from->dev_null_fd; + fsrv_to->exec_tmout = from->exec_tmout; + fsrv_to->mem_limit = from->mem_limit; + fsrv_to->map_size = from->map_size; + +#ifndef HAVE_ARC4RANDOM + fsrv_to->dev_urandom_fd = from->dev_urandom_fd; +#endif + + // These are forkserver specific. + fsrv_to->out_fd = -1; + fsrv_to->out_dir_fd = -1; + fsrv_to->child_pid = -1; + fsrv_to->use_fauxsrv = 0; + fsrv_to->prev_timed_out = 0; + + fsrv_to->init_child_func = fsrv_exec_child; + + list_append(&fsrv_list, fsrv_to); + +} + /* Internal forkserver for dumb_mode=1 and non-forkserver mode runs. It execvs for each fork, forwarding exit codes and child pids to afl. */ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { - static unsigned char tmp[4] = {0}; - pid_t child_pid = -1; + unsigned char tmp[4] = {0, 0, 0, 0}; + pid_t child_pid = -1; + + if (!be_quiet) ACTF("Using Fauxserver:"); /* Phone home and tell the parent that we're OK. If parent isn't there, assume we're not running in forkserver mode and just execute program. */ @@ -244,16 +195,25 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { cloning a stopped child. So, we just execute once, and then send commands through a pipe. The other part of this logic is in afl-as.h / llvm_mode */ -void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { +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]; + int status; + s32 rlen; + + if (!be_quiet) ACTF("Spinning up the fork server..."); + + if (fsrv->use_fauxsrv) { - struct timeval timeout; - int st_pipe[2], ctl_pipe[2]; - int status; - s32 rlen; + /* TODO: Come up with sone nice way to initalize this all */ - if (fsrv->use_fauxsrv) ACTF("Using Fauxserver:"); + if (fsrv->init_child_func != fsrv_exec_child) + FATAL("Different forkserver not compatible with fauxserver"); - if (!getenv("AFL_QUIET")) ACTF("Spinning up the fork server..."); + fsrv->init_child_func = afl_fauxsrv_execv; + + } if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); @@ -305,7 +265,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { setsid(); - if (!get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) { + if (!(debug_child_output)) { dup2(fsrv->dev_null_fd, 1); dup2(fsrv->dev_null_fd, 2); @@ -338,7 +298,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { #ifndef HAVE_ARC4RANDOM close(fsrv->dev_urandom_fd); #endif - close(fsrv->plot_file == NULL ? -1 : fileno(fsrv->plot_file)); + if (fsrv->plot_file != NULL) fclose(fsrv->plot_file); /* This should improve performance a bit, since it stops the linker from doing extra work post-fork(). */ @@ -367,15 +327,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { "msan_track_origins=0", 0); - if (fsrv->use_fauxsrv) { - - afl_fauxsrv_execv(fsrv, argv); - - } else { - - execv(fsrv->target_path, argv); - - } + fsrv->init_child_func(fsrv, argv); /* Use a distinctive bitmap signature to tell the parent about execv() falling through. */ @@ -400,24 +352,22 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { rlen = 0; if (fsrv->exec_tmout) { - fd_set readfds; + u32 time = read_timed(fsrv->fsrv_st_fd, &status, 4, + fsrv->exec_tmout * FORK_WAIT_MULT, stop_soon_p); - FD_ZERO(&readfds); - FD_SET(fsrv->fsrv_st_fd, &readfds); - timeout.tv_sec = ((fsrv->exec_tmout * FORK_WAIT_MULT) / 1000); - timeout.tv_usec = ((fsrv->exec_tmout * FORK_WAIT_MULT) % 1000) * 1000; + if (!time) { - int sret = select(fsrv->fsrv_st_fd + 1, &readfds, NULL, NULL, &timeout); + kill(fsrv->fsrv_pid, SIGKILL); - if (sret == 0) { + } else if (time > fsrv->exec_tmout * FORK_WAIT_MULT) { fsrv->child_timed_out = 1; - kill(fsrv->child_pid, SIGKILL); + kill(fsrv->fsrv_pid, SIGKILL); } else { - - rlen = read(fsrv->fsrv_st_fd, &status, 4); - + + rlen = 4; + } } else { @@ -431,7 +381,98 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { if (rlen == 4) { - if (!getenv("AFL_QUIET")) OKF("All right - fork server is up."); + if (!be_quiet) OKF("All right - fork server is up."); + + if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { + + if (!be_quiet) + ACTF("Extended forkserver functions received (%08x).", status); + + if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) { + + fsrv->snapshot = 1; + if (!be_quiet) ACTF("Using SNAPSHOT feature."); + + } + + if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { + + fsrv->map_size = FS_OPT_GET_MAPSIZE(status); + if (fsrv->map_size % 8) // should not happen + fsrv->map_size = (((fsrv->map_size + 8) >> 3) << 3); + if (!be_quiet) ACTF("Target map size: %u", fsrv->map_size); + if (fsrv->map_size > MAP_SIZE) + FATAL( + "Target's coverage map size of %u is larger than the one this " + "afl++ is compiled with (%u)\n", + fsrv->map_size, MAP_SIZE); + + } + + if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { + + if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) { + + // this is not afl-fuzz - we deny and return + status = (0xffffffff ^ (FS_OPT_ENABLED | FS_OPT_AUTODICT)); + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) + FATAL("Writing to forkserver failed."); + return; + + } + + if (!be_quiet) ACTF("Using AUTODICT feature."); + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) + FATAL("Writing to forkserver failed."); + if (read(fsrv->fsrv_st_fd, &status, 4) != 4) + FATAL("Reading from forkserver failed."); + + if (status < 2 || (u32)status > 0xffffff) + FATAL("Dictionary has an illegal size: %d", status); + + u32 len = status, offset = 0, count = 0; + u8 *dict = ck_alloc(len); + if (dict == NULL) + FATAL("Could not allocate %u bytes of autodictionary memmory", 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); + + } + + } + + len = status; + offset = 0; + while (offset < status && (u8)dict[offset] + offset < status) { + + fsrv->function_ptr(fsrv->function_opt, dict + offset + 1, + (u8)dict[offset]); + offset += (1 + dict[offset]); + count++; + + } + + if (!be_quiet) ACTF("Loaded %u autodictionary entries", count); + ck_free(dict); + + } + + } + return; } @@ -476,6 +517,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { } else { + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + SAYF("\n" cLRD "[-] " cRST "Whoops, the target binary crashed suddenly, " "before receiving any input\n" @@ -508,7 +551,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { "options\n" " fail, poke <afl-users@googlegroups.com> for troubleshooting " "tips.\n", - forkserver_DMS(fsrv->mem_limit << 20), fsrv->mem_limit - 1); + stringify_mem_size(val_buf, sizeof(val_buf), fsrv->mem_limit << 20), + fsrv->mem_limit - 1); } @@ -543,6 +587,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { } else { + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + SAYF( "\n" cLRD "[-] " cRST "Hmm, looks like the target binary terminated " @@ -574,7 +620,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { "never\n" " reached before the program terminates.\n\n" : "", - forkserver_DMS(fsrv->mem_limit << 20), fsrv->mem_limit - 1); + stringify_int(val_buf, sizeof(val_buf), fsrv->mem_limit << 20), + fsrv->mem_limit - 1); } @@ -582,11 +629,19 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) { } +static void afl_fsrv_kill(afl_forkserver_t *fsrv) { + + if (fsrv->child_pid > 0) kill(fsrv->child_pid, SIGKILL); + if (fsrv->fsrv_pid > 0) kill(fsrv->fsrv_pid, SIGKILL); + if (waitpid(fsrv->fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); } + +} + void afl_fsrv_killall() { LIST_FOREACH(&fsrv_list, afl_forkserver_t, { - if (el->child_pid > 0) kill(el->child_pid, SIGKILL); + afl_fsrv_kill(el); }); @@ -594,6 +649,7 @@ void afl_fsrv_killall() { void afl_fsrv_deinit(afl_forkserver_t *fsrv) { + afl_fsrv_kill(fsrv); list_remove(&fsrv_list, fsrv); } diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 7e2d3212..b6a494db 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -24,6 +24,7 @@ */ #include "afl-fuzz.h" +#include <limits.h> /* Write bitmap to file. The bitmap is useful mostly for the secret -B option, to focus a separate fuzzing session on a particular @@ -31,13 +32,13 @@ void write_bitmap(afl_state_t *afl) { - u8 *fname; + u8 fname[PATH_MAX]; s32 fd; if (!afl->bitmap_changed) return; afl->bitmap_changed = 0; - fname = alloc_printf("%s/fuzz_bitmap", afl->out_dir); + snprintf(fname, PATH_MAX, "%s/fuzz_bitmap", afl->out_dir); fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) PFATAL("Unable to open '%s'", fname); @@ -45,7 +46,6 @@ void write_bitmap(afl_state_t *afl) { ck_write(fd, afl->virgin_bits, MAP_SIZE, fname); close(fd); - ck_free(fname); } @@ -78,16 +78,17 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { u64 *current = (u64 *)afl->fsrv.trace_bits; u64 *virgin = (u64 *)virgin_map; - u32 i = (MAP_SIZE >> 3); + u32 i = (afl->fsrv.map_size >> 3); #else u32 *current = (u32 *)afl->fsrv.trace_bits; u32 *virgin = (u32 *)virgin_map; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); #endif /* ^WORD_SIZE_64 */ + if (i == 0) i = 1; u8 ret = 0; @@ -138,7 +139,8 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { } - if (ret && virgin_map == afl->virgin_bits) afl->bitmap_changed = 1; + if (unlikely(ret) && unlikely(virgin_map == afl->virgin_bits)) + afl->bitmap_changed = 1; return ret; @@ -147,12 +149,14 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { /* Count the number of bits set in the provided bitmap. Used for the status screen several times every second, does not have to be fast. */ -u32 count_bits(u8 *mem) { +u32 count_bits(afl_state_t *afl, u8 *mem) { u32 *ptr = (u32 *)mem; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; + if (i == 0) i = 1; + while (i--) { u32 v = *(ptr++); @@ -177,27 +181,27 @@ u32 count_bits(u8 *mem) { } -#define FF(_b) (0xff << ((_b) << 3)) - /* Count the number of bytes set in the bitmap. Called fairly sporadically, mostly to update the status screen or calibrate and examine confirmed new paths. */ -u32 count_bytes(u8 *mem) { +u32 count_bytes(afl_state_t *afl, u8 *mem) { u32 *ptr = (u32 *)mem; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; + if (i == 0) i = 1; + while (i--) { u32 v = *(ptr++); if (!v) continue; - if (v & FF(0)) ++ret; - if (v & FF(1)) ++ret; - if (v & FF(2)) ++ret; - if (v & FF(3)) ++ret; + if (v & 0x000000ff) ++ret; + if (v & 0x0000ff00) ++ret; + if (v & 0x00ff0000) ++ret; + if (v & 0xff000000) ++ret; } @@ -208,12 +212,14 @@ u32 count_bytes(u8 *mem) { /* Count the number of non-255 bytes set in the bitmap. Used strictly for the status screen, several calls per second or so. */ -u32 count_non_255_bytes(u8 *mem) { +u32 count_non_255_bytes(afl_state_t *afl, u8 *mem) { u32 *ptr = (u32 *)mem; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; + if (i == 0) i = 1; + while (i--) { u32 v = *(ptr++); @@ -222,10 +228,10 @@ u32 count_non_255_bytes(u8 *mem) { case. */ if (v == 0xffffffff) continue; - if ((v & FF(0)) != FF(0)) ++ret; - if ((v & FF(1)) != FF(1)) ++ret; - if ((v & FF(2)) != FF(2)) ++ret; - if ((v & FF(3)) != FF(3)) ++ret; + if ((v & 0x000000ff) != 0x000000ff) ++ret; + if ((v & 0x0000ff00) != 0x0000ff00) ++ret; + if ((v & 0x00ff0000) != 0x00ff0000) ++ret; + if ((v & 0xff000000) != 0xff000000) ++ret; } @@ -246,9 +252,11 @@ const u8 simplify_lookup[256] = { #ifdef WORD_SIZE_64 -void simplify_trace(u64 *mem) { +void simplify_trace(afl_state_t *afl, u64 *mem) { - u32 i = MAP_SIZE >> 3; + u32 i = (afl->fsrv.map_size >> 3); + + if (i == 0) i = 1; while (i--) { @@ -279,9 +287,11 @@ void simplify_trace(u64 *mem) { #else -void simplify_trace(u32 *mem) { +void simplify_trace(afl_state_t *afl, u32 *mem) { + + u32 i = (afl->fsrv.map_size >> 2); - u32 i = MAP_SIZE >> 2; + if (i == 0) i = 1; while (i--) { @@ -341,9 +351,11 @@ void init_count_class16(void) { #ifdef WORD_SIZE_64 -void classify_counts(u64 *mem) { +void classify_counts(afl_state_t *afl, u64 *mem) { + + u32 i = (afl->fsrv.map_size >> 3); - u32 i = MAP_SIZE >> 3; + if (i == 0) i = 1; while (i--) { @@ -368,9 +380,11 @@ void classify_counts(u64 *mem) { #else -void classify_counts(u32 *mem) { +void classify_counts(afl_state_t *afl, u32 *mem) { - u32 i = MAP_SIZE >> 2; + u32 i = (afl->fsrv.map_size >> 2); + + if (i == 0) i = 1; while (i--) { @@ -397,11 +411,11 @@ void classify_counts(u32 *mem) { count information here. This is called only sporadically, for some new paths. */ -void minimize_bits(u8 *dst, u8 *src) { +void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) { u32 i = 0; - while (i < MAP_SIZE) { + while (i < afl->fsrv.map_size) { if (*(src++)) dst[i >> 3] |= 1 << (i & 7); ++i; @@ -413,13 +427,13 @@ void minimize_bits(u8 *dst, u8 *src) { #ifndef SIMPLE_FILES /* Construct a file name for a new test case, capturing the operation - that led to its discovery. Uses a static buffer. */ + that led to its discovery. Returns a ptr to afl->describe_op_buf_256. */ u8 *describe_op(afl_state_t *afl, u8 hnb) { u8 *ret = afl->describe_op_buf_256; - if (afl->syncing_party) { + if (unlikely(afl->syncing_party)) { sprintf(ret, "sync:%s,src:%06u", afl->syncing_party, afl->syncing_case); @@ -461,20 +475,23 @@ u8 *describe_op(afl_state_t *afl, u8 hnb) { static void write_crash_readme(afl_state_t *afl) { - u8 * fn = alloc_printf("%s/crashes/README.txt", afl->out_dir); + u8 fn[PATH_MAX]; s32 fd; FILE *f; + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + + sprintf(fn, "%s/crashes/README.txt", afl->out_dir); + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); - ck_free(fn); /* Do not die on errors here - that would be impolite. */ - if (fd < 0) return; + if (unlikely(fd < 0)) return; f = fdopen(fd, "w"); - if (!f) { + if (unlikely(!f)) { close(fd); return; @@ -501,7 +518,9 @@ static void write_crash_readme(afl_state_t *afl) { " https://github.com/AFLplusplus/AFLplusplus\n\n", - afl->orig_cmdline, DMS(afl->fsrv.mem_limit << 20)); /* ignore errors */ + afl->orig_cmdline, + stringify_mem_size(val_buf, sizeof(val_buf), + afl->fsrv.mem_limit << 20)); /* ignore errors */ fclose(f); @@ -513,15 +532,17 @@ static void write_crash_readme(afl_state_t *afl) { u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { - if (len == 0) return 0; + if (unlikely(len == 0)) return 0; - u8 *fn = ""; + u8 *queue_fn = ""; u8 hnb; s32 fd; u8 keeping = 0, res; + u8 fn[PATH_MAX]; + /* Update path frequency. */ - u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); struct queue_entry *q = afl->queue; while (q) { @@ -537,30 +558,31 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { } - if (fault == afl->crash_mode) { + if (unlikely(fault == afl->crash_mode)) { /* Keep only if there are new bits in the map, add to queue for future fuzzing, etc. */ if (!(hnb = has_new_bits(afl, afl->virgin_bits))) { - if (afl->crash_mode) ++afl->total_crashes; + if (unlikely(afl->crash_mode)) ++afl->total_crashes; return 0; } #ifndef SIMPLE_FILES - fn = alloc_printf("%s/queue/id:%06u,%s", afl->out_dir, afl->queued_paths, - describe_op(afl, hnb)); + queue_fn = alloc_printf("%s/queue/id:%06u,%s", afl->out_dir, + afl->queued_paths, describe_op(afl, hnb)); #else - fn = alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_paths); + queue_fn = + alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_paths); #endif /* ^!SIMPLE_FILES */ - add_to_queue(afl, fn, len, 0); + add_to_queue(afl, queue_fn, len, 0); if (hnb == 2) { @@ -576,11 +598,12 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { res = calibrate_case(afl, afl->queue_top, mem, afl->queue_cycle - 1, 0); - if (res == FAULT_ERROR) FATAL("Unable to execute target application"); + if (unlikely(res == FAULT_ERROR)) + FATAL("Unable to execute target application"); - fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) PFATAL("Unable to create '%s'", fn); - ck_write(fd, mem, len, fn); + fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (unlikely(fd < 0)) PFATAL("Unable to create '%s'", queue_fn); + ck_write(fd, mem, len, queue_fn); close(fd); keeping = 1; @@ -600,12 +623,12 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (afl->unique_hangs >= KEEP_UNIQUE_HANG) return keeping; - if (!afl->dumb_mode) { + if (likely(!afl->dumb_mode)) { #ifdef WORD_SIZE_64 - simplify_trace((u64 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u64 *)afl->fsrv.trace_bits); #else - simplify_trace((u32 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u32 *)afl->fsrv.trace_bits); #endif /* ^WORD_SIZE_64 */ if (!has_new_bits(afl, afl->virgin_tmout)) return keeping; @@ -622,7 +645,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { u8 new_fault; write_to_testcase(afl, mem, len); - new_fault = run_target(afl, afl->hang_tmout); + new_fault = run_target(afl, &afl->fsrv, afl->hang_tmout); /* A corner case that one user reported bumping into: increasing the timeout actually uncovers a crash. Make sure we don't discard it if @@ -636,12 +659,13 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { #ifndef SIMPLE_FILES - fn = alloc_printf("%s/hangs/id:%06llu,%s", afl->out_dir, - afl->unique_hangs, describe_op(afl, 0)); + snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s", afl->out_dir, + afl->unique_hangs, describe_op(afl, 0)); #else - fn = alloc_printf("%s/hangs/id_%06llu", afl->out_dir, afl->unique_hangs); + snprintf(fn, PATH_MAX, "%s/hangs/id_%06llu", afl->out_dir, + afl->unique_hangs); #endif /* ^!SIMPLE_FILES */ @@ -663,38 +687,37 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (afl->unique_crashes >= KEEP_UNIQUE_CRASH) return keeping; - if (!afl->dumb_mode) { + if (likely(!afl->dumb_mode)) { #ifdef WORD_SIZE_64 - simplify_trace((u64 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u64 *)afl->fsrv.trace_bits); #else - simplify_trace((u32 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u32 *)afl->fsrv.trace_bits); #endif /* ^WORD_SIZE_64 */ if (!has_new_bits(afl, afl->virgin_crash)) return keeping; } - if (!afl->unique_crashes) write_crash_readme(afl); + if (unlikely(!afl->unique_crashes)) write_crash_readme(afl); #ifndef SIMPLE_FILES - fn = alloc_printf("%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir, - afl->unique_crashes, afl->kill_signal, - describe_op(afl, 0)); + snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir, + afl->unique_crashes, afl->kill_signal, describe_op(afl, 0)); #else - fn = alloc_printf("%s/crashes/id_%06llu_%02u", afl->out_dir, - afl->unique_crashes, afl->kill_signal); + snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u", afl->out_dir, + afl->unique_crashes, afl->kill_signal); #endif /* ^!SIMPLE_FILES */ ++afl->unique_crashes; - if (afl->infoexec) { // if the user wants to be informed on new crashes - - // do + if (unlikely(afl->infoexec)) { + + // if the user wants to be informed on new crashes - do that #if !TARGET_OS_IPHONE - // that if (system(afl->infoexec) == -1) hnb += 0; // we dont care if system errors, but we dont want a // compiler warning either @@ -719,12 +742,10 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { test case, too. */ fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) PFATAL("Unable to create '%s'", fn); + if (unlikely(fd < 0)) PFATAL("Unable to create '%s'", fn); ck_write(fd, mem, len, fn); close(fd); - ck_free(fn); - return keeping; } diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 1600af53..e2747097 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -29,590 +29,18 @@ #include "afl-fuzz.h" #include "cmplog.h" -void init_cmplog_forkserver(afl_state_t *afl) { +typedef struct cmplog_data { - static struct timeval timeout; - int st_pipe[2], ctl_pipe[2]; - int status; - s32 rlen; +} cmplog_data_t; - ACTF("Spinning up the cmplog fork server..."); +void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { - if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); + setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); - afl->fsrv.child_timed_out = 0; - afl->cmplog_fsrv_pid = fork(); + if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) + argv[0] = fsrv->cmplog_binary; - if (afl->cmplog_fsrv_pid < 0) PFATAL("fork() failed"); - - if (!afl->cmplog_fsrv_pid) { - - /* CHILD PROCESS */ - - struct rlimit r; - - /* Umpf. On OpenBSD, the default fd limit for root users is set to - soft 128. Let's try to fix that... */ - - if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) { - - r.rlim_cur = FORKSRV_FD + 2; - setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */ - - } - - if (afl->fsrv.mem_limit) { - - r.rlim_max = r.rlim_cur = ((rlim_t)afl->fsrv.mem_limit) << 20; - -#ifdef RLIMIT_AS - setrlimit(RLIMIT_AS, &r); /* Ignore errors */ -#else - /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but - according to reliable sources, RLIMIT_DATA covers anonymous - maps - so we should be getting good protection against OOM bugs. */ - - setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ -#endif /* ^RLIMIT_AS */ - - } - - /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered - before the dump is complete. */ - - // r.rlim_max = r.rlim_cur = 0; - // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ - - /* Isolate the process and configure standard descriptors. If - afl->fsrv.out_file is specified, stdin is /dev/null; otherwise, - afl->fsrv.out_fd is cloned instead. */ - - setsid(); - - if (!(afl->afl_env.afl_debug_child_output)) { - - dup2(afl->fsrv.dev_null_fd, 1); - dup2(afl->fsrv.dev_null_fd, 2); - - } - - if (!afl->fsrv.use_stdin) { - - dup2(afl->fsrv.dev_null_fd, 0); - - } else { - - dup2(afl->fsrv.out_fd, 0); - close(afl->fsrv.out_fd); - - } - - /* Set up control and status pipes, close the unneeded original fds. */ - - if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed"); - if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed"); - - close(ctl_pipe[0]); - close(ctl_pipe[1]); - close(st_pipe[0]); - close(st_pipe[1]); - - close(afl->fsrv.out_dir_fd); - close(afl->fsrv.dev_null_fd); -#ifndef HAVE_ARC4RANDOM - close(afl->fsrv.dev_urandom_fd); -#endif - close(afl->fsrv.plot_file == NULL ? -1 : fileno(afl->fsrv.plot_file)); - - /* This should improve performance a bit, since it stops the linker from - doing extra work post-fork(). */ - - if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); - - /* Set sane defaults for ASAN if nothing else specified. */ - - setenv("ASAN_OPTIONS", - "abort_on_error=1:" - "detect_leaks=0:" - "malloc_context_size=0:" - "symbolize=0:" - "allocator_may_return_null=1", - 0); - - /* MSAN is tricky, because it doesn't support abort_on_error=1 at this - point. So, we do this in a very hacky way. */ - - setenv("MSAN_OPTIONS", - "exit_code=" STRINGIFY(MSAN_ERROR) ":" - "symbolize=0:" - "abort_on_error=1:" - "malloc_context_size=0:" - "allocator_may_return_null=1:" - "msan_track_origins=0", - 0); - - setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); - - if (!afl->qemu_mode && afl->argv[0] != afl->cmplog_binary) { - - ck_free(afl->argv[0]); - afl->argv[0] = afl->cmplog_binary; - - } - - execv(afl->argv[0], afl->argv); - - /* Use a distinctive bitmap signature to tell the parent about execv() - falling through. */ - - *(u32 *)afl->fsrv.trace_bits = EXEC_FAIL_SIG; - exit(0); - - } - - /* PARENT PROCESS */ - - /* Close the unneeded endpoints. */ - - close(ctl_pipe[0]); - close(st_pipe[1]); - - afl->cmplog_fsrv_ctl_fd = ctl_pipe[1]; - afl->cmplog_fsrv_st_fd = st_pipe[0]; - - /* Wait for the fork server to come up, but don't wait too long. */ - - rlen = 0; - if (afl->fsrv.exec_tmout) { - - fd_set readfds; - FD_ZERO(&readfds); - FD_SET(afl->cmplog_fsrv_st_fd, &readfds); - timeout.tv_sec = ((afl->fsrv.exec_tmout * FORK_WAIT_MULT) / 1000); - timeout.tv_usec = ((afl->fsrv.exec_tmout * FORK_WAIT_MULT) % 1000) * 1000; - - int sret = - select(afl->cmplog_fsrv_st_fd + 1, &readfds, NULL, NULL, &timeout); - - if (sret == 0) { - - kill(afl->cmplog_fsrv_pid, SIGKILL); - - } else { - - rlen = read(afl->cmplog_fsrv_st_fd, &status, 4); - - } - - } else { - - rlen = read(afl->cmplog_fsrv_st_fd, &status, 4); - - } - - /* If we have a four-byte "hello" message from the server, we're all set. - Otherwise, try to figure out what went wrong. */ - - if (rlen == 4) { - - OKF("All right - fork server is up."); - return; - - } - - if (afl->fsrv.child_timed_out) - FATAL( - "Timeout while initializing cmplog fork server (adjusting -t may " - "help)"); - - if (waitpid(afl->cmplog_fsrv_pid, &status, 0) <= 0) - PFATAL("waitpid() failed"); - - if (WIFSIGNALED(status)) { - - if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && - afl->fsrv.uses_asan) { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! Since it seems to be built with ASAN and you " - "have a\n" - " restrictive memory limit configured, this is expected; please " - "read\n" - " %s/notes_for_asan.md for help.\n", - doc_path); - - } else if (!afl->fsrv.mem_limit) { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! There are several probable explanations:\n\n" - - " - The binary is just buggy and explodes entirely on its own. " - "If so, you\n" - " need to fix the underlying problem or find a better " - "replacement.\n\n" - - MSG_FORK_ON_APPLE - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke <afl-users@googlegroups.com> for troubleshooting " - "tips.\n"); - - } else { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! There are several probable explanations:\n\n" - - " - The current memory limit (%s) is too restrictive, causing " - "the\n" - " target to hit an OOM condition in the dynamic linker. Try " - "bumping up\n" - " the limit with the -m setting in the command line. A simple " - "way confirm\n" - " this diagnosis would be:\n\n" - - MSG_ULIMIT_USAGE - " /path/to/fuzzed_app )\n\n" - - " Tip: you can use http://jwilk.net/software/recidivm to " - "quickly\n" - " estimate the required amount of virtual memory for the " - "binary.\n\n" - - " - The binary is just buggy and explodes entirely on its own. " - "If so, you\n" - " need to fix the underlying problem or find a better " - "replacement.\n\n" - - MSG_FORK_ON_APPLE - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke <afl-users@googlegroups.com> for troubleshooting " - "tips.\n", - DMS(afl->fsrv.mem_limit << 20), afl->fsrv.mem_limit - 1); - - } - - FATAL("Cmplog fork server crashed with signal %d", WTERMSIG(status)); - - } - - if (*(u32 *)afl->fsrv.trace_bits == EXEC_FAIL_SIG) - FATAL("Unable to execute target application ('%s')", afl->argv[0]); - - if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && afl->fsrv.uses_asan) { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. Since it seems to be built " - "with ASAN and\n" - " you have a restrictive memory limit configured, this is " - "expected; please\n" - " read %s/notes_for_asan.md for help.\n", - doc_path); - - } else if (!afl->fsrv.mem_limit) { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. Perhaps there is a horrible " - "bug in the\n" - " fuzzer. Poke <afl-users@googlegroups.com> for troubleshooting " - "tips.\n"); - - } else { - - SAYF( - "\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. There are %s probable " - "explanations:\n\n" - - "%s" - " - The current memory limit (%s) is too restrictive, causing an " - "OOM\n" - " fault in the dynamic linker. This can be fixed with the -m " - "option. A\n" - " simple way to confirm the diagnosis may be:\n\n" - - MSG_ULIMIT_USAGE - " /path/to/fuzzed_app )\n\n" - - " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" - " estimate the required amount of virtual memory for the " - "binary.\n\n" - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke <afl-users@googlegroups.com> for troubleshooting " - "tips.\n", - getenv(DEFER_ENV_VAR) ? "three" : "two", - getenv(DEFER_ENV_VAR) - ? " - You are using deferred forkserver, but __AFL_INIT() is " - "never\n" - " reached before the program terminates.\n\n" - : "", - DMS(afl->fsrv.mem_limit << 20), afl->fsrv.mem_limit - 1); - - } - - FATAL("Cmplog fork server handshake failed"); - -} - -u8 run_cmplog_target(afl_state_t *afl, u32 timeout) { - - static struct itimerval it; - static u32 prev_timed_out = 0; - static u64 exec_ms = 0; - - int status = 0; - u32 tb4; - - afl->fsrv.child_timed_out = 0; - - /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we - must prevent any earlier operations from venturing into that - territory. */ - - memset(afl->fsrv.trace_bits, 0, MAP_SIZE); - MEM_BARRIER(); - - /* If we're running in "dumb" mode, we can't rely on the fork server - logic compiled into the target program, so we will just keep calling - execve(). There is a bit of code duplication between here and - init_forkserver(), but c'est la vie. */ - - if (afl->dumb_mode == 1 || afl->no_forkserver) { - - afl->cmplog_child_pid = fork(); - - if (afl->cmplog_child_pid < 0) PFATAL("fork() failed"); - - if (!afl->cmplog_child_pid) { - - struct rlimit r; - - if (afl->fsrv.mem_limit) { - - r.rlim_max = r.rlim_cur = ((rlim_t)afl->fsrv.mem_limit) << 20; - -#ifdef RLIMIT_AS - - setrlimit(RLIMIT_AS, &r); /* Ignore errors */ - -#else - - setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ - -#endif /* ^RLIMIT_AS */ - - } - - r.rlim_max = r.rlim_cur = 0; - - setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ - - /* Isolate the process and configure standard descriptors. If - afl->fsrv.out_file is specified, stdin is /dev/null; otherwise, - afl->fsrv.out_fd is cloned instead. */ - - setsid(); - - dup2(afl->fsrv.dev_null_fd, 1); - dup2(afl->fsrv.dev_null_fd, 2); - - if (afl->fsrv.out_file) { - - dup2(afl->fsrv.dev_null_fd, 0); - - } else { - - dup2(afl->fsrv.out_fd, 0); - close(afl->fsrv.out_fd); - - } - - /* On Linux, would be faster to use O_CLOEXEC. Maybe TODO. */ - - close(afl->fsrv.dev_null_fd); - close(afl->fsrv.out_dir_fd); -#ifndef HAVE_ARC4RANDOM - close(afl->fsrv.dev_urandom_fd); -#endif - close(fileno(afl->fsrv.plot_file)); - - /* Set sane defaults for ASAN if nothing else specified. */ - - setenv("ASAN_OPTIONS", - "abort_on_error=1:" - "detect_leaks=0:" - "symbolize=0:" - "allocator_may_return_null=1", - 0); - - setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" - "symbolize=0:" - "msan_track_origins=0", 0); - - setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); - - if (!afl->qemu_mode && afl->argv[0] != afl->cmplog_binary) { - - ck_free(afl->argv[0]); - afl->argv[0] = afl->cmplog_binary; - - } - - execv(afl->argv[0], afl->argv); - - /* Use a distinctive bitmap value to tell the parent about execv() - falling through. */ - - *(u32 *)afl->fsrv.trace_bits = EXEC_FAIL_SIG; - exit(0); - - } - - } else { - - s32 res; - - /* In non-dumb mode, we have the fork server up and running, so simply - tell it to have at it, and then read back PID. */ - - if ((res = write(afl->cmplog_fsrv_ctl_fd, &prev_timed_out, 4)) != 4) { - - if (afl->stop_soon) return 0; - RPFATAL(res, - "Unable to request new process from cmplog fork server (OOM?)"); - - } - - if ((res = read(afl->cmplog_fsrv_st_fd, &afl->cmplog_child_pid, 4)) != 4) { - - if (afl->stop_soon) return 0; - RPFATAL(res, - "Unable to request new process from cmplog fork server (OOM?)"); - - } - - if (afl->cmplog_child_pid <= 0) - FATAL("Cmplog fork server is misbehaving (OOM?)"); - - } - - /* Configure timeout, as requested by user, then wait for child to terminate. - */ - - it.it_value.tv_sec = (timeout / 1000); - it.it_value.tv_usec = (timeout % 1000) * 1000; - - setitimer(ITIMER_REAL, &it, NULL); - - /* The SIGALRM handler simply kills the afl->cmplog_child_pid and sets - * afl->fsrv.child_timed_out. */ - - if (afl->dumb_mode == 1 || afl->no_forkserver) { - - if (waitpid(afl->cmplog_child_pid, &status, 0) <= 0) - PFATAL("waitpid() failed"); - - } else { - - s32 res; - - if ((res = read(afl->cmplog_fsrv_st_fd, &status, 4)) != 4) { - - if (afl->stop_soon) return 0; - SAYF( - "\n" cLRD "[-] " cRST - "Unable to communicate with fork server. Some possible reasons:\n\n" - " - You've run out of memory. Use -m to increase the the memory " - "limit\n" - " to something higher than %lld.\n" - " - The binary or one of the libraries it uses manages to create\n" - " threads before the forkserver initializes.\n" - " - The binary, at least in some circumstances, exits in a way " - "that\n" - " also kills the parent process - raise() could be the " - "culprit.\n\n" - "If all else fails you can disable the fork server via " - "AFL_NO_FORKSRV=1.\n", - afl->fsrv.mem_limit); - RPFATAL(res, "Unable to communicate with fork server"); - - } - - } - - if (!WIFSTOPPED(status)) afl->cmplog_child_pid = 0; - - getitimer(ITIMER_REAL, &it); - exec_ms = - (u64)timeout - (it.it_value.tv_sec * 1000 + it.it_value.tv_usec / 1000); - if (afl->slowest_exec_ms < exec_ms) afl->slowest_exec_ms = exec_ms; - - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 0; - - setitimer(ITIMER_REAL, &it, NULL); - - ++afl->total_execs; - - /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the - compiler below this point. Past this location, afl->fsrv.trace_bits[] - behave very normally and do not have to be treated as volatile. */ - - MEM_BARRIER(); - - tb4 = *(u32 *)afl->fsrv.trace_bits; - -#ifdef WORD_SIZE_64 - classify_counts((u64 *)afl->fsrv.trace_bits); -#else - classify_counts((u32 *)afl->fsrv.trace_bits); -#endif /* ^WORD_SIZE_64 */ - - prev_timed_out = afl->fsrv.child_timed_out; - - /* Report outcome to caller. */ - - if (WIFSIGNALED(status) && !afl->stop_soon) { - - afl->kill_signal = WTERMSIG(status); - - if (afl->fsrv.child_timed_out && afl->kill_signal == SIGKILL) - return FAULT_TMOUT; - - return FAULT_CRASH; - - } - - /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and - must use a special exit code. */ - - if (afl->fsrv.uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { - - afl->kill_signal = 0; - return FAULT_CRASH; - - } - - if ((afl->dumb_mode == 1 || afl->no_forkserver) && tb4 == EXEC_FAIL_SIG) - return FAULT_ERROR; - - return FAULT_NONE; + execv(argv[0], argv); } @@ -622,14 +50,19 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { if (afl->post_handler) { - out_buf = afl->post_handler(out_buf, &len); - if (!out_buf || !len) return 0; + u8 *post_buf = NULL; + + size_t post_len = + afl->post_handler(afl->post_data, out_buf, len, &post_buf); + if (!post_buf || !post_len) return 0; + out_buf = post_buf; + len = post_len; } write_to_testcase(afl, out_buf, len); - fault = run_cmplog_target(afl, afl->fsrv.exec_tmout); + fault = run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout); if (afl->stop_soon) return 1; diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index ff4c0ae2..55146dd9 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -55,6 +55,8 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, u8 * lptr; u32 cur_line = 0; + u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; + f = fopen(fname, "r"); if (!f) PFATAL("Unable to open '%s'", fname); @@ -170,8 +172,10 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len, afl->extras[afl->extras_cnt].len = klen; if (afl->extras[afl->extras_cnt].len > MAX_DICT_FILE) - FATAL("Keyword too big in line %u (%s, limit is %s)", cur_line, DMS(klen), - DMS(MAX_DICT_FILE)); + FATAL( + "Keyword too big in line %u (%s, limit is %s)", cur_line, + stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), klen), + stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE)); if (*min_len > klen) *min_len = klen; if (*max_len < klen) *max_len = klen; @@ -193,6 +197,8 @@ void load_extras(afl_state_t *afl, u8 *dir) { u32 min_len = MAX_DICT_FILE, max_len = 0, dict_level = 0; u8 * x; + u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; + /* If the name ends with @, extract level and continue. */ if ((x = strchr(dir, '@'))) { @@ -238,8 +244,10 @@ void load_extras(afl_state_t *afl, u8 *dir) { } if (st.st_size > MAX_DICT_FILE) - FATAL("Extra '%s' is too big (%s, limit is %s)", fn, DMS(st.st_size), - DMS(MAX_DICT_FILE)); + FATAL( + "Extra '%s' is too big (%s, limit is %s)", fn, + stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), st.st_size), + stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), MAX_DICT_FILE)); if (min_len > st.st_size) min_len = st.st_size; if (max_len < st.st_size) max_len = st.st_size; @@ -273,11 +281,12 @@ check_and_sort: compare_extras_len); OKF("Loaded %u extra tokens, size range %s to %s.", afl->extras_cnt, - DMS(min_len), DMS(max_len)); + stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), min_len), + stringify_mem_size(val_bufs[1], sizeof(val_bufs[1]), max_len)); if (max_len > 32) WARNF("Some tokens are relatively large (%s) - consider trimming.", - DMS(max_len)); + stringify_mem_size(val_bufs[0], sizeof(val_bufs[0]), max_len)); if (afl->extras_cnt > MAX_DET_EXTRAS) WARNF("More than %d tokens - will use them probabilistically.", @@ -296,10 +305,14 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) { } /* Maybe add automatic extra. */ +/* Ugly hack: afl state is transfered as u8* because we import data via + afl-forkserver.c - which is shared with other afl tools that do not + have the afl state struct */ -void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) { +void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) { - u32 i; + afl_state_t *afl = (afl_state_t *)afl_tmp; + u32 i; /* Allow users to specify that they don't want auto dictionaries. */ @@ -378,7 +391,7 @@ void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) { } else { - i = MAX_AUTO_EXTRAS / 2 + UR(afl, (MAX_AUTO_EXTRAS + 1) / 2); + i = MAX_AUTO_EXTRAS / 2 + rand_below(afl, (MAX_AUTO_EXTRAS + 1) / 2); ck_free(afl->a_extras[i].data); @@ -442,7 +455,7 @@ void load_auto(afl_state_t *afl) { u8 *fn = alloc_printf("%s/.state/auto_extras/auto_%06u", afl->in_dir, i); s32 fd, len; - fd = open(fn, O_RDONLY, 0600); + fd = open(fn, O_RDONLY); if (fd < 0) { @@ -460,7 +473,7 @@ void load_auto(afl_state_t *afl) { if (len < 0) PFATAL("Unable to read from '%s'", fn); if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, tmp, len); + maybe_add_auto((u8 *)afl, tmp, len); close(fd); ck_free(fn); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 6b5fa24f..54cc81ef 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -24,6 +24,7 @@ */ #include "afl-fuzz.h" +#include <limits.h> #ifdef HAVE_AFFINITY @@ -76,21 +77,16 @@ void bind_to_free_cpu(afl_state_t *afl) { while ((de = readdir(d))) { - u8 * fn; + u8 fn[PATH_MAX]; FILE *f; u8 tmp[MAX_LINE]; u8 has_vmsize = 0; if (!isdigit(de->d_name[0])) continue; - fn = alloc_printf("/proc/%s/status", de->d_name); + snprintf(fn, PATH_MAX, "/proc/%s/status", de->d_name); - if (!(f = fopen(fn, "r"))) { - - ck_free(fn); - continue; - - } + if (!(f = fopen(fn, "r"))) { continue; } while (fgets(tmp, MAX_LINE, f)) { @@ -111,7 +107,6 @@ void bind_to_free_cpu(afl_state_t *afl) { } - ck_free(fn); fclose(f); } @@ -139,8 +134,15 @@ void bind_to_free_cpu(afl_state_t *afl) { for (i = 0; i < proccount; i++) { #if defined(__FreeBSD__) - if (procs[i].ki_oncpu < sizeof(cpu_used) && procs[i].ki_pctcpu > 60) - cpu_used[procs[i].ki_oncpu] = 1; + if (!strcmp(procs[i].ki_comm, "idle")) continue; + + // fix when ki_oncpu = -1 + int oncpu; + oncpu = procs[i].ki_oncpu; + if (oncpu == -1) oncpu = procs[i].ki_lastcpu; + + if (oncpu != -1 && oncpu < sizeof(cpu_used) && procs[i].ki_pctcpu > 60) + cpu_used[oncpu] = 1; #elif defined(__DragonFly__) if (procs[i].kp_lwp.kl_cpuid < sizeof(cpu_used) && procs[i].kp_lwp.kl_pctcpu > 10) @@ -276,7 +278,9 @@ void setup_post(afl_state_t *afl) { void *dh; u8 * fn = afl->afl_env.afl_post_library; + u8 tbuf[6]; u32 tlen = 6; + strncpy(tbuf, "hello", tlen); if (!fn) return; @@ -287,10 +291,20 @@ void setup_post(afl_state_t *afl) { afl->post_handler = dlsym(dh, "afl_postprocess"); if (!afl->post_handler) FATAL("Symbol 'afl_postprocess' not found."); + afl->post_init = dlsym(dh, "afl_postprocess_init"); + if (!afl->post_init) FATAL("Symbol 'afl_postprocess_init' not found."); + afl->post_deinit = dlsym(dh, "afl_postprocess_deinit"); + if (!afl->post_deinit) FATAL("Symbol 'afl_postprocess_deinit' not found."); /* Do a quick test. It's better to segfault now than later =) */ - afl->post_handler("hello", &tlen); + u8 *post_buf = NULL; + afl->post_data = afl->post_init(afl); + if (!afl->post_data) FATAL("Could not initialize post handler."); + + size_t post_len = afl->post_handler(afl->post_data, tbuf, tlen, &post_buf); + if (!post_len || !post_buf) + SAYF("Empty return in test post handler for buf=\"hello\\0\"."); OKF("Postprocessor installed successfully."); @@ -304,7 +318,7 @@ static void shuffle_ptrs(afl_state_t *afl, void **ptrs, u32 cnt) { for (i = 0; i < cnt - 2; ++i) { - u32 j = i + UR(afl, cnt - i); + u32 j = i + rand_below(afl, cnt - i); void *s = ptrs[i]; ptrs[i] = ptrs[j]; ptrs[j] = s; @@ -323,6 +337,8 @@ void read_testcases(afl_state_t *afl) { u32 i; u8 * fn1; + u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX]; + /* Auto-detect non-in-place resumption attempts. */ fn1 = alloc_printf("%s/queue", afl->in_dir); @@ -367,9 +383,10 @@ void read_testcases(afl_state_t *afl) { struct stat st; + u8 dfn[PATH_MAX]; + snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir, + nl[i]->d_name); u8 *fn2 = alloc_printf("%s/%s", afl->in_dir, nl[i]->d_name); - u8 *dfn = alloc_printf("%s/.state/deterministic_done/%s", afl->in_dir, - nl[i]->d_name); u8 passed_det = 0; @@ -383,14 +400,14 @@ void read_testcases(afl_state_t *afl) { if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { ck_free(fn2); - ck_free(dfn); continue; } if (st.st_size > MAX_FILE) - FATAL("Test case '%s' is too big (%s, limit is %s)", fn2, DMS(st.st_size), - DMS(MAX_FILE)); + FATAL("Test case '%s' is too big (%s, limit is %s)", fn2, + stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), + stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); /* Check for metadata that indicates that deterministic fuzzing is complete for this entry. We don't want to repeat deterministic @@ -398,7 +415,6 @@ void read_testcases(afl_state_t *afl) { and probably very time-consuming. */ if (!access(dfn, F_OK)) passed_det = 1; - ck_free(dfn); add_to_queue(afl, fn2, st.st_size, passed_det); @@ -432,11 +448,13 @@ static void check_map_coverage(afl_state_t *afl) { u32 i; - if (count_bytes(afl->fsrv.trace_bits) < 100) return; + if (count_bytes(afl, afl->fsrv.trace_bits) < 100) return; for (i = (1 << (MAP_SIZE_POW2 - 1)); i < MAP_SIZE; ++i) if (afl->fsrv.trace_bits[i]) return; + if (afl->fsrv.map_size != MAP_SIZE) return; + WARNF("Recompile binary with newer version of afl to improve coverage!"); } @@ -553,6 +571,8 @@ void perform_dry_run(afl_state_t *afl) { if (afl->fsrv.mem_limit) { + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + SAYF("\n" cLRD "[-] " cRST "Oops, the program crashed with one of the test cases provided. " "There are\n" @@ -593,8 +613,9 @@ void perform_dry_run(afl_state_t *afl) { "other options\n" " fail, poke <afl-users@googlegroups.com> for " "troubleshooting tips.\n", - DMS(afl->fsrv.mem_limit << 20), afl->fsrv.mem_limit - 1, - doc_path); + stringify_mem_size(val_buf, sizeof(val_buf), + afl->fsrv.mem_limit << 20), + afl->fsrv.mem_limit - 1, doc_path); } else { @@ -797,7 +818,7 @@ void pivot_inputs(afl_state_t *afl) { u32 find_start_position(afl_state_t *afl) { - static u8 tmp[4096]; /* Ought to be enough for anybody. */ + u8 tmp[4096] = {0}; /* Ought to be enough for anybody. */ u8 *fn, *off; s32 fd, i; @@ -834,7 +855,7 @@ u32 find_start_position(afl_state_t *afl) { void find_timeout(afl_state_t *afl) { - static u8 tmp[4096]; /* Ought to be enough for anybody. */ + u8 tmp[4096] = {0}; /* Ought to be enough for anybody. */ u8 *fn, *off; s32 fd, i; @@ -902,7 +923,7 @@ static u8 delete_files(u8 *path, u8 *prefix) { double get_runnable_processes(void) { - static double res; + double res = 0; #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ defined(__NetBSD__) || defined(__DragonFly__) @@ -1049,7 +1070,7 @@ static void handle_existing_out_dir(afl_state_t *afl) { /* Let's see how much work is at stake. */ - if (!afl->in_place_resume && + if (!afl->in_place_resume && last_update > start_time2 && last_update - start_time2 > OUTPUT_GRACE * 60) { SAYF("\n" cLRD "[-] " cRST @@ -1787,7 +1808,7 @@ void fix_up_sync(afl_state_t *afl) { static void handle_resize(int sig) { - LIST_FOREACH(&afl_states, afl_state_t, { el->clear_screen; }); + LIST_FOREACH(&afl_states, afl_state_t, { el->clear_screen = 1; }); } @@ -1832,8 +1853,6 @@ static void handle_stop_sig(int sig) { if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, SIGKILL); if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, SIGKILL); - if (el->cmplog_child_pid > 0) kill(el->cmplog_child_pid, SIGKILL); - if (el->cmplog_fsrv_pid > 0) kill(el->cmplog_fsrv_pid, SIGKILL); }); @@ -1967,7 +1986,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { #endif /* ^!__APPLE__ */ - if (!afl->qemu_mode && !afl->unicorn_mode && !afl->dumb_mode && + if (!afl->fsrv.qemu_mode && !afl->unicorn_mode && !afl->dumb_mode && !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { SAYF("\n" cLRD "[-] " cRST @@ -1994,7 +2013,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { } - if ((afl->qemu_mode) && + if ((afl->fsrv.qemu_mode) && memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) { SAYF("\n" cLRD "[-] " cRST @@ -2008,7 +2027,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { } - if (memmem(f_data, f_len, "libasan.so", 10) || + if (memmem(f_data, f_len, "__asan_init", 11) || memmem(f_data, f_len, "__msan_init", 11)) afl->fsrv.uses_asan = 1; @@ -2125,11 +2144,6 @@ void setup_signal_handlers(void) { sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); - /* Exec timeout notifications. */ - - sa.sa_handler = handle_timeout; - sigaction(SIGALRM, &sa, NULL); - /* Window resize */ sa.sa_handler = handle_resize; diff --git a/src/afl-fuzz-misc.c b/src/afl-fuzz-misc.c deleted file mode 100644 index 29e8bd82..00000000 --- a/src/afl-fuzz-misc.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - american fuzzy lop++ - misc stuffs from Mordor - ---------------------------------------------- - - 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> - - Copyright 2016, 2017 Google Inc. All rights reserved. - Copyright 2019-2020 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. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - This is the real deal: the program takes an instrumented binary and - attempts a variety of basic fuzzing tricks, paying close attention to - how they affect the execution path. - - */ - -#include "afl-fuzz.h" - -/* Describe integer. Uses 12 cyclic static buffers for return values. The value - returned should be five characters or less for all the integers we reasonably - expect to see. */ - -u8 *DI(u64 val) { - - static u8 tmp[12][16]; - static u8 cur; - - cur = (cur + 1) % 12; - -#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \ - do { \ - \ - if (val < (_divisor) * (_limit_mult)) { \ - \ - sprintf(tmp[cur], _fmt, ((_cast)val) / (_divisor)); \ - return tmp[cur]; \ - \ - } \ - \ - } while (0) - - /* 0-9999 */ - CHK_FORMAT(1, 10000, "%llu", u64); - - /* 10.0k - 99.9k */ - CHK_FORMAT(1000, 99.95, "%0.01fk", double); - - /* 100k - 999k */ - CHK_FORMAT(1000, 1000, "%lluk", u64); - - /* 1.00M - 9.99M */ - CHK_FORMAT(1000 * 1000, 9.995, "%0.02fM", double); - - /* 10.0M - 99.9M */ - CHK_FORMAT(1000 * 1000, 99.95, "%0.01fM", double); - - /* 100M - 999M */ - CHK_FORMAT(1000 * 1000, 1000, "%lluM", u64); - - /* 1.00G - 9.99G */ - CHK_FORMAT(1000LL * 1000 * 1000, 9.995, "%0.02fG", double); - - /* 10.0G - 99.9G */ - CHK_FORMAT(1000LL * 1000 * 1000, 99.95, "%0.01fG", double); - - /* 100G - 999G */ - CHK_FORMAT(1000LL * 1000 * 1000, 1000, "%lluG", u64); - - /* 1.00T - 9.99G */ - CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 9.995, "%0.02fT", double); - - /* 10.0T - 99.9T */ - CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 99.95, "%0.01fT", double); - - /* 100T+ */ - strcpy(tmp[cur], "infty"); - return tmp[cur]; - -} - -/* Describe float. Similar to the above, except with a single - static buffer. */ - -u8 *DF(double val) { - - static u8 tmp[16]; - - if (val < 99.995) { - - sprintf(tmp, "%0.02f", val); - return tmp; - - } - - if (val < 999.95) { - - sprintf(tmp, "%0.01f", val); - return tmp; - - } - - return DI((u64)val); - -} - -/* Describe integer as memory size. */ - -u8 *DMS(u64 val) { - - static u8 tmp[12][16]; - static u8 cur; - - cur = (cur + 1) % 12; - - /* 0-9999 */ - CHK_FORMAT(1, 10000, "%llu B", u64); - - /* 10.0k - 99.9k */ - CHK_FORMAT(1024, 99.95, "%0.01f kB", double); - - /* 100k - 999k */ - CHK_FORMAT(1024, 1000, "%llu kB", u64); - - /* 1.00M - 9.99M */ - CHK_FORMAT(1024 * 1024, 9.995, "%0.02f MB", double); - - /* 10.0M - 99.9M */ - CHK_FORMAT(1024 * 1024, 99.95, "%0.01f MB", double); - - /* 100M - 999M */ - CHK_FORMAT(1024 * 1024, 1000, "%llu MB", u64); - - /* 1.00G - 9.99G */ - CHK_FORMAT(1024LL * 1024 * 1024, 9.995, "%0.02f GB", double); - - /* 10.0G - 99.9G */ - CHK_FORMAT(1024LL * 1024 * 1024, 99.95, "%0.01f GB", double); - - /* 100G - 999G */ - CHK_FORMAT(1024LL * 1024 * 1024, 1000, "%llu GB", u64); - - /* 1.00T - 9.99G */ - CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 9.995, "%0.02f TB", double); - - /* 10.0T - 99.9T */ - CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 99.95, "%0.01f TB", double); - -#undef CHK_FORMAT - - /* 100T+ */ - strcpy(tmp[cur], "infty"); - return tmp[cur]; - -} - -/* Describe time delta. Returns one static buffer, 34 chars of less. */ - -u8 *DTD(u64 cur_ms, u64 event_ms) { - - static u8 tmp[64]; - u64 delta; - s32 t_d, t_h, t_m, t_s; - - if (!event_ms) return "none seen yet"; - - delta = cur_ms - event_ms; - - t_d = delta / 1000 / 60 / 60 / 24; - t_h = (delta / 1000 / 60 / 60) % 24; - t_m = (delta / 1000 / 60) % 60; - t_s = (delta / 1000) % 60; - - sprintf(tmp, "%s days, %d hrs, %d min, %d sec", DI(t_d), t_h, t_m, t_s); - return tmp; - -} - diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 9071404d..efb1c117 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -7,6 +7,7 @@ Now maintained by Marc Heuse <mh@mh-sec.de>, Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and Andrea Fioraldi <andreafioraldi@gmail.com> + Dominik Maier <mail@dmnk.co> Copyright 2016, 2017 Google Inc. All rights reserved. Copyright 2019-2020 AFLplusplus Project. All rights reserved. @@ -27,13 +28,13 @@ void load_custom_mutator(afl_state_t *, const char *); #ifdef USE_PYTHON -void load_custom_mutator_py(afl_state_t *, const char *); +void load_custom_mutator_py(afl_state_t *, char *); #endif void setup_custom_mutator(afl_state_t *afl) { /* Try mutator library first */ - u8 *fn = getenv("AFL_CUSTOM_MUTATOR_LIBRARY"); + u8 *fn = afl->afl_env.afl_custom_mutator_library; if (fn) { @@ -51,7 +52,7 @@ void setup_custom_mutator(afl_state_t *afl) { /* Try Python module */ #ifdef USE_PYTHON - u8 *module_name = getenv("AFL_PYTHON_MODULE"); + u8 *module_name = afl->afl_env.afl_python_module; if (module_name) { @@ -59,17 +60,14 @@ void setup_custom_mutator(afl_state_t *afl) { FATAL( "MOpt and Python mutator are mutually exclusive. We accept pull " "requests that integrates MOpt with the optional mutators " - "(custom/radamsa/redquenn/...)."); - - if (init_py_module(afl, module_name)) - FATAL("Failed to initialize Python module"); + "(custom/radamsa/redqueen/...)."); load_custom_mutator_py(afl, module_name); } #else - if (getenv("AFL_PYTHON_MODULE")) + if (afl->afl_env.afl_python_module) FATAL("Your AFL binary was built without Python support"); #endif @@ -79,18 +77,20 @@ void destroy_custom_mutator(afl_state_t *afl) { if (afl->mutator) { - if (afl->mutator->dh) - dlclose(afl->mutator->dh); - else { + afl->mutator->afl_custom_deinit(afl->mutator->data); - /* Python mutator */ -#ifdef USE_PYTHON - finalize_py_module(afl); -#endif + if (afl->mutator->dh) dlclose(afl->mutator->dh); + + if (afl->mutator->pre_save_buf) { + + ck_free(afl->mutator->pre_save_buf); + afl->mutator->pre_save_buf = NULL; + afl->mutator->pre_save_size = 0; } ck_free(afl->mutator); + afl->mutator = NULL; } @@ -100,6 +100,8 @@ void load_custom_mutator(afl_state_t *afl, const char *fn) { void *dh; afl->mutator = ck_alloc(sizeof(struct custom_mutator)); + afl->mutator->pre_save_buf = NULL; + afl->mutator->pre_save_size = 0; afl->mutator->name = fn; ACTF("Loading custom mutator library from '%s'...", fn); @@ -109,10 +111,15 @@ void load_custom_mutator(afl_state_t *afl, const char *fn) { afl->mutator->dh = dh; /* Mutator */ - /* "afl_custom_init", optional for backward compatibility */ + /* "afl_custom_init", required */ afl->mutator->afl_custom_init = dlsym(dh, "afl_custom_init"); if (!afl->mutator->afl_custom_init) - WARNF("Symbol 'afl_custom_init' not found."); + FATAL("Symbol 'afl_custom_init' not found."); + + /* "afl_custom_deinit", required */ + afl->mutator->afl_custom_deinit = dlsym(dh, "afl_custom_deinit"); + if (!afl->mutator->afl_custom_deinit) + FATAL("Symbol 'afl_custom_deinit' not found."); /* "afl_custom_fuzz" or "afl_custom_mutator", required */ afl->mutator->afl_custom_fuzz = dlsym(dh, "afl_custom_fuzz"); @@ -186,59 +193,58 @@ void load_custom_mutator(afl_state_t *afl, const char *fn) { /* Initialize the custom mutator */ if (afl->mutator->afl_custom_init) - afl->mutator->afl_custom_init(afl, UR(afl, 0xFFFFFFFF)); + afl->mutator->data = + afl->mutator->afl_custom_init(afl, rand_below(afl, 0xFFFFFFFF)); } u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { - static u8 tmp[64]; - static u8 clean_trace[MAP_SIZE]; - u8 needs_write = 0, fault = 0; u32 trim_exec = 0; u32 orig_len = q->len; - afl->stage_name = tmp; + u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; + + afl->stage_name = afl->stage_name_buf; afl->bytes_trim_in += q->len; /* Initialize trimming in the custom mutator */ afl->stage_cur = 0; - afl->stage_max = afl->mutator->afl_custom_init_trim(afl, in_buf, q->len); - + afl->stage_max = + afl->mutator->afl_custom_init_trim(afl->mutator->data, in_buf, q->len); + if (unlikely(afl->stage_max) < 0) + FATAL("custom_init_trim error ret: %d", afl->stage_max); if (afl->not_on_tty && afl->debug) SAYF("[Custom Trimming] START: Max %d iterations, %u bytes", afl->stage_max, q->len); while (afl->stage_cur < afl->stage_max) { - sprintf(tmp, "ptrim %s", DI(trim_exec)); + u8 *retbuf = NULL; - u32 cksum; + sprintf(afl->stage_name_buf, "ptrim %s", + u_stringify_int(val_buf, trim_exec)); - u8 * retbuf = NULL; - size_t retlen = 0; + u32 cksum; - afl->mutator->afl_custom_trim(afl, &retbuf, &retlen); + size_t retlen = afl->mutator->afl_custom_trim(afl->mutator->data, &retbuf); - if (retlen > orig_len) + if (unlikely(!retbuf)) + FATAL("custom_trim failed (ret %zd)", retlen); + else if (unlikely(retlen > orig_len)) FATAL( "Trimmed data returned by custom mutator is larger than original " "data"); write_to_testcase(afl, retbuf, retlen); - fault = run_target(afl, afl->fsrv.exec_tmout); + fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); ++afl->trim_execs; - if (afl->stop_soon || fault == FAULT_ERROR) { - - ck_free(retbuf); - goto abort_trimming; - - } + if (afl->stop_soon || fault == FAULT_ERROR) { goto abort_trimming; } - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (cksum == q->exec_cksum) { @@ -251,12 +257,14 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (!needs_write) { needs_write = 1; - memcpy(clean_trace, afl->fsrv.trace_bits, MAP_SIZE); + memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, + afl->fsrv.map_size); } /* Tell the custom mutator that the trimming was successful */ - afl->stage_cur = afl->mutator->afl_custom_post_trim(afl, 1); + afl->stage_cur = + afl->mutator->afl_custom_post_trim(afl->mutator->data, 1); if (afl->not_on_tty && afl->debug) SAYF("[Custom Trimming] SUCCESS: %d/%d iterations (now at %u bytes)", @@ -265,15 +273,16 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } else { /* Tell the custom mutator that the trimming was unsuccessful */ - afl->stage_cur = afl->mutator->afl_custom_post_trim(afl, 0); + afl->stage_cur = + afl->mutator->afl_custom_post_trim(afl->mutator->data, 0); + if (unlikely(afl->stage_cur < 0)) + FATAL("Error ret in custom_post_trim: %d", afl->stage_cur); if (afl->not_on_tty && afl->debug) SAYF("[Custom Trimming] FAILURE: %d/%d iterations", afl->stage_cur, afl->stage_max); } - ck_free(retbuf); - /* Since this can be slow, update the screen every now and then. */ if (!(trim_exec++ % afl->stats_update_freq)) show_stats(afl); @@ -299,7 +308,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { ck_write(fd, in_buf, q->len, q->fname); close(fd); - memcpy(afl->fsrv.trace_bits, clean_trace, MAP_SIZE); + memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size); update_bitmap_score(afl, q); } @@ -311,53 +320,3 @@ abort_trimming: } -#ifdef USE_PYTHON -void load_custom_mutator_py(afl_state_t *afl, const char *module_name) { - - PyObject **py_functions = afl->py_functions; - - afl->mutator = ck_alloc(sizeof(struct custom_mutator)); - - afl->mutator->name = module_name; - ACTF("Loading Python mutator library from '%s'...", module_name); - - if (py_functions[PY_FUNC_INIT]) afl->mutator->afl_custom_init = init_py; - - /* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator - is quite different from the custom mutator. */ - afl->mutator->afl_custom_fuzz = fuzz_py; - - if (py_functions[PY_FUNC_PRE_SAVE]) - afl->mutator->afl_custom_pre_save = pre_save_py; - - if (py_functions[PY_FUNC_INIT_TRIM]) - afl->mutator->afl_custom_init_trim = init_trim_py; - - if (py_functions[PY_FUNC_POST_TRIM]) - afl->mutator->afl_custom_post_trim = post_trim_py; - - if (py_functions[PY_FUNC_TRIM]) afl->mutator->afl_custom_trim = trim_py; - - if (py_functions[PY_FUNC_HAVOC_MUTATION]) - afl->mutator->afl_custom_havoc_mutation = havoc_mutation_py; - - if (py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY]) - afl->mutator->afl_custom_havoc_mutation_probability = - havoc_mutation_probability_py; - - if (py_functions[PY_FUNC_QUEUE_GET]) - afl->mutator->afl_custom_queue_get = queue_get_py; - - if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY]) - afl->mutator->afl_custom_queue_new_entry = queue_new_entry_py; - - OKF("Python mutator '%s' installed successfully.", module_name); - - /* Initialize the custom mutator */ - if (afl->mutator->afl_custom_init) - afl->mutator->afl_custom_init(afl, UR(afl, 0xFFFFFFFF)); - -} - -#endif - diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index c4d49ec1..4a039a1d 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -31,7 +31,7 @@ int select_algorithm(afl_state_t *afl) { int i_puppet, j_puppet; - double sele = ((double)(UR(afl, 10000)) * 0.0001); + double sele = ((double)(rand_below(afl, 10000)) * 0.0001); j_puppet = 0; for (i_puppet = 0; i_puppet < operator_num; ++i_puppet) { @@ -67,9 +67,9 @@ static u32 choose_block_len(afl_state_t *afl, u32 limit) { u32 min_value, max_value; u32 rlim = MIN(afl->queue_cycle, 3); - if (!afl->run_over10m) rlim = 1; + if (unlikely(!afl->run_over10m)) rlim = 1; - switch (UR(afl, rlim)) { + switch (rand_below(afl, rlim)) { case 0: min_value = 1; @@ -83,7 +83,7 @@ static u32 choose_block_len(afl_state_t *afl, u32 limit) { default: - if (UR(afl, 10)) { + if (rand_below(afl, 10)) { min_value = HAVOC_BLK_MEDIUM; max_value = HAVOC_BLK_LARGE; @@ -99,7 +99,7 @@ static u32 choose_block_len(afl_state_t *afl, u32 limit) { if (min_value >= limit) min_value = 1; - return min_value + UR(afl, MIN(max_value, limit) - min_value + 1); + return min_value + rand_below(afl, MIN(max_value, limit) - min_value + 1); } @@ -347,6 +347,9 @@ u8 fuzz_one_original(afl_state_t *afl) { u8 a_collect[MAX_AUTO_EXTRA]; u32 a_len = 0; +/* Not pretty, but saves a lot of writing */ +#define BUF_PARAMS(name) (void **)&afl->name##_buf, &afl->name##_size + #ifdef IGNORE_FINDS /* In IGNORE_FINDS mode, skip any entries that weren't in the @@ -356,16 +359,17 @@ u8 fuzz_one_original(afl_state_t *afl) { #else - if (afl->mutator && afl->mutator->afl_custom_queue_get) { + if (unlikely(afl->mutator) && unlikely(afl->mutator->afl_custom_queue_get)) { /* The custom mutator will decide to skip this test case or not. */ - if (!afl->mutator->afl_custom_queue_get(afl, afl->queue_cur->fname)) + if (!afl->mutator->afl_custom_queue_get(afl->mutator->data, + afl->queue_cur->fname)) return 1; } - if (afl->pending_favored) { + if (likely(afl->pending_favored)) { /* If we have any favored, non-fuzzed new arrivals in the queue, possibly skip to them at the expense of already-fuzzed or non-favored @@ -373,7 +377,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (((afl->queue_cur->was_fuzzed > 0 || afl->queue_cur->fuzz_level > 0) || !afl->queue_cur->favored) && - UR(afl, 100) < SKIP_TO_NEW_PROB) + rand_below(afl, 100) < SKIP_TO_NEW_PROB) return 1; } else if (!afl->dumb_mode && !afl->queue_cur->favored && @@ -387,11 +391,11 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->queue_cycle > 1 && (afl->queue_cur->fuzz_level == 0 || afl->queue_cur->was_fuzzed)) { - if (UR(afl, 100) < SKIP_NFAV_NEW_PROB) return 1; + if (rand_below(afl, 100) < SKIP_NFAV_NEW_PROB) return 1; } else { - if (UR(afl, 100) < SKIP_NFAV_OLD_PROB) return 1; + if (rand_below(afl, 100) < SKIP_NFAV_OLD_PROB) return 1; } @@ -399,7 +403,7 @@ u8 fuzz_one_original(afl_state_t *afl) { #endif /* ^IGNORE_FINDS */ - if (afl->not_on_tty) { + if (unlikely(afl->not_on_tty)) { ACTF("Fuzzing test case #%u (%u total, %llu uniq crashes found)...", afl->current_entry, afl->queued_paths, afl->unique_crashes); @@ -411,13 +415,13 @@ u8 fuzz_one_original(afl_state_t *afl) { fd = open(afl->queue_cur->fname, O_RDONLY); - if (fd < 0) PFATAL("Unable to open '%s'", afl->queue_cur->fname); + if (unlikely(fd < 0)) PFATAL("Unable to open '%s'", afl->queue_cur->fname); len = afl->queue_cur->len; orig_in = in_buf = mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (orig_in == MAP_FAILED) + if (unlikely(orig_in == MAP_FAILED)) PFATAL("Unable to mmap '%s' with len %d", afl->queue_cur->fname, len); close(fd); @@ -426,7 +430,7 @@ u8 fuzz_one_original(afl_state_t *afl) { single byte anyway, so it wouldn't give us any performance or memory usage benefits. */ - out_buf = ck_alloc_nozero(len); + out_buf = ck_maybe_grow(BUF_PARAMS(out), len); afl->subseq_tmouts = 0; @@ -436,7 +440,7 @@ u8 fuzz_one_original(afl_state_t *afl) { * CALIBRATION (only if failed earlier on) * *******************************************/ - if (afl->queue_cur->cal_failed) { + if (unlikely(afl->queue_cur->cal_failed)) { u8 res = FAULT_TMOUT; @@ -445,11 +449,12 @@ u8 fuzz_one_original(afl_state_t *afl) { res = calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0); - if (res == FAULT_ERROR) FATAL("Unable to execute target application"); + if (unlikely(res == FAULT_ERROR)) + FATAL("Unable to execute target application"); } - if (afl->stop_soon || res != afl->crash_mode) { + if (unlikely(afl->stop_soon) || res != afl->crash_mode) { ++afl->cur_skipped_paths; goto abandon_entry; @@ -466,9 +471,10 @@ u8 fuzz_one_original(afl_state_t *afl) { u8 res = trim_case(afl, afl->queue_cur, in_buf); - if (res == FAULT_ERROR) FATAL("Unable to execute target application"); + if (unlikely(res == FAULT_ERROR)) + FATAL("Unable to execute target application"); - if (afl->stop_soon) { + if (unlikely(afl->stop_soon)) { ++afl->cur_skipped_paths; goto abandon_entry; @@ -491,9 +497,9 @@ u8 fuzz_one_original(afl_state_t *afl) { orig_perf = perf_score = calculate_score(afl, afl->queue_cur); - if (perf_score == 0) goto abandon_entry; + if (unlikely(perf_score == 0)) goto abandon_entry; - if (afl->use_radamsa > 1) goto radamsa_stage; + if (unlikely(afl->use_radamsa > 1)) goto radamsa_stage; if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) { @@ -595,7 +601,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) { - u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) { @@ -607,7 +613,7 @@ u8 fuzz_one_original(afl_state_t *afl) { ++a_len; if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); } else if (cksum != prev_cksum) { @@ -615,7 +621,7 @@ u8 fuzz_one_original(afl_state_t *afl) { worthwhile queued up, and collect that if the answer is yes. */ if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); a_len = 0; prev_cksum = cksum; @@ -716,7 +722,7 @@ u8 fuzz_one_original(afl_state_t *afl) { /* Initialize effector map for the next step (see comments below). Always flag first and last byte as doing something. */ - eff_map = ck_alloc(EFF_ALEN(len)); + eff_map = ck_maybe_grow(BUF_PARAMS(eff), EFF_ALEN(len)); eff_map[0] = 1; if (EFF_APOS(len - 1) != 0) { @@ -755,7 +761,7 @@ u8 fuzz_one_original(afl_state_t *afl) { without wasting time on checksums. */ if (!afl->dumb_mode && len >= EFF_MIN_LEN) - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); else cksum = ~afl->queue_cur->exec_cksum; @@ -1401,7 +1407,7 @@ skip_interest: map. */ if ((afl->extras_cnt > MAX_DET_EXTRAS && - UR(afl, afl->extras_cnt) >= MAX_DET_EXTRAS) || + rand_below(afl, afl->extras_cnt) >= MAX_DET_EXTRAS) || afl->extras[j].len > len - i || !memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) || !memchr(eff_map + EFF_APOS(i), 1, @@ -1440,7 +1446,7 @@ skip_interest: orig_hit_cnt = new_hit_cnt; - ex_tmp = ck_alloc(len + MAX_DICT_FILE); + ex_tmp = ck_maybe_grow(BUF_PARAMS(ex), len + MAX_DICT_FILE); for (i = 0; i <= len; ++i) { @@ -1463,7 +1469,6 @@ skip_interest: if (common_fuzz_stuff(afl, ex_tmp, len + afl->extras[j].len)) { - ck_free(ex_tmp); goto abandon_entry; } @@ -1477,8 +1482,6 @@ skip_interest: } - ck_free(ex_tmp); - new_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_finds[STAGE_EXTRAS_UI] += new_hit_cnt - orig_hit_cnt; @@ -1549,8 +1552,8 @@ custom_mutator_stage: * CUSTOM MUTATORS * *******************/ - if (!afl->mutator) goto havoc_stage; - if (!afl->mutator->afl_custom_fuzz) goto havoc_stage; + if (likely(!afl->mutator)) goto havoc_stage; + if (likely(!afl->mutator->afl_custom_fuzz)) goto havoc_stage; afl->stage_name = "custom mutator"; afl->stage_short = "custom"; @@ -1573,7 +1576,7 @@ custom_mutator_stage: /* Pick a random other queue entry for passing to external API */ do { - tid = UR(afl, afl->queued_paths); + tid = rand_below(afl, afl->queued_paths); } while (tid == afl->current_entry && afl->queued_paths > 1); @@ -1603,19 +1606,24 @@ custom_mutator_stage: /* Read the additional testcase into a new buffer. */ fd = open(target->fname, O_RDONLY); - if (fd < 0) PFATAL("Unable to open '%s'", target->fname); - new_buf = ck_alloc_nozero(target->len); + if (unlikely(fd < 0)) PFATAL("Unable to open '%s'", target->fname); + + new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), target->len); ck_read(fd, new_buf, target->len, target->fname); close(fd); + u8 *mutated_buf = NULL; + size_t mutated_size = afl->mutator->afl_custom_fuzz( - afl, &out_buf, len, new_buf, target->len, max_seed_size); + afl->mutator->data, out_buf, len, &mutated_buf, new_buf, target->len, + max_seed_size); - ck_free(new_buf); + if (unlikely(!mutated_buf)) + FATAL("Error in custom_fuzz. Size returned: %zd", mutated_size); if (mutated_size > 0) { - if (common_fuzz_stuff(afl, out_buf, (u32)mutated_size)) { + if (common_fuzz_stuff(afl, mutated_buf, (u32)mutated_size)) { goto abandon_entry; @@ -1639,7 +1647,8 @@ custom_mutator_stage: } - if (mutated_size < len) out_buf = ck_realloc(out_buf, len); + /* `(afl->)out_buf` may have been changed by the call to custom_fuzz */ + /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs Memcpy. */ memcpy(out_buf, in_buf, len); } @@ -1649,7 +1658,7 @@ custom_mutator_stage: afl->stage_finds[STAGE_CUSTOM_MUTATOR] += new_hit_cnt - orig_hit_cnt; afl->stage_cycles[STAGE_CUSTOM_MUTATOR] += afl->stage_max; - if (afl->custom_only) { + if (likely(afl->custom_only)) { /* Skip other stages */ ret_val = 0; @@ -1679,8 +1688,8 @@ havoc_stage: perf_score = orig_perf; - snprintf(afl->stage_name_buf64, 64, "splice %u", splice_cycle); - afl->stage_name = afl->stage_name_buf64; + snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "splice %u", splice_cycle); + afl->stage_name = afl->stage_name_buf; afl->stage_short = "splice"; afl->stage_max = SPLICE_HAVOC * perf_score / afl->havoc_div / 100; @@ -1700,7 +1709,7 @@ havoc_stage: if (stacked_custom && afl->mutator->afl_custom_havoc_mutation_probability) { stacked_custom_prob = - afl->mutator->afl_custom_havoc_mutation_probability(afl); + afl->mutator->afl_custom_havoc_mutation_probability(afl->mutator->data); if (stacked_custom_prob > 100) FATAL( "The probability returned by afl_custom_havoc_mutation_propability " @@ -1713,34 +1722,49 @@ havoc_stage: for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { - u32 use_stacking = 1 << (1 + UR(afl, HAVOC_STACK_POW2)); + u32 use_stacking = 1 << (1 + rand_below(afl, HAVOC_STACK_POW2)); afl->stage_cur_val = use_stacking; for (i = 0; i < use_stacking; ++i) { - if (stacked_custom && UR(afl, 100) < stacked_custom_prob) { + if (stacked_custom && rand_below(afl, 100) < stacked_custom_prob) { + + u8 * custom_havoc_buf = NULL; + size_t new_len = afl->mutator->afl_custom_havoc_mutation( + afl->mutator->data, out_buf, temp_len, &custom_havoc_buf, MAX_FILE); + if (unlikely(!custom_havoc_buf)) + FATAL("Error in custom_havoc (return %zd)", new_len); + if (likely(new_len > 0 && custom_havoc_buf)) { - temp_len = afl->mutator->afl_custom_havoc_mutation(afl, &out_buf, - temp_len, MAX_FILE); + temp_len = new_len; + if (out_buf != custom_havoc_buf) { + + ck_maybe_grow(BUF_PARAMS(out), temp_len); + memcpy(out_buf, custom_havoc_buf, temp_len); + + } + + } } - switch (UR(afl, 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) { + switch (rand_below( + afl, 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0))) { case 0: /* Flip a single bit somewhere. Spooky! */ - FLIP_BIT(out_buf, UR(afl, temp_len << 3)); + FLIP_BIT(out_buf, rand_below(afl, temp_len << 3)); break; case 1: /* Set byte to interesting value. */ - out_buf[UR(afl, temp_len)] = - interesting_8[UR(afl, sizeof(interesting_8))]; + out_buf[rand_below(afl, temp_len)] = + interesting_8[rand_below(afl, sizeof(interesting_8))]; break; case 2: @@ -1749,15 +1773,15 @@ havoc_stage: if (temp_len < 2) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - *(u16 *)(out_buf + UR(afl, temp_len - 1)) = - interesting_16[UR(afl, sizeof(interesting_16) >> 1)]; + *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = + interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]; } else { - *(u16 *)(out_buf + UR(afl, temp_len - 1)) = - SWAP16(interesting_16[UR(afl, sizeof(interesting_16) >> 1)]); + *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16( + interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]); } @@ -1769,15 +1793,15 @@ havoc_stage: if (temp_len < 4) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - *(u32 *)(out_buf + UR(afl, temp_len - 3)) = - interesting_32[UR(afl, sizeof(interesting_32) >> 2)]; + *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = + interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]; } else { - *(u32 *)(out_buf + UR(afl, temp_len - 3)) = - SWAP32(interesting_32[UR(afl, sizeof(interesting_32) >> 2)]); + *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32( + interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]); } @@ -1787,14 +1811,14 @@ havoc_stage: /* Randomly subtract from byte. */ - out_buf[UR(afl, temp_len)] -= 1 + UR(afl, ARITH_MAX); + out_buf[rand_below(afl, temp_len)] -= 1 + rand_below(afl, ARITH_MAX); break; case 5: /* Randomly add to byte. */ - out_buf[UR(afl, temp_len)] += 1 + UR(afl, ARITH_MAX); + out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX); break; case 6: @@ -1803,16 +1827,16 @@ havoc_stage: if (temp_len < 2) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - u32 pos = UR(afl, temp_len - 1); + u32 pos = rand_below(afl, temp_len - 1); - *(u16 *)(out_buf + pos) -= 1 + UR(afl, ARITH_MAX); + *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = UR(afl, temp_len - 1); - u16 num = 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 1); + u16 num = 1 + rand_below(afl, ARITH_MAX); *(u16 *)(out_buf + pos) = SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num); @@ -1827,16 +1851,16 @@ havoc_stage: if (temp_len < 2) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - u32 pos = UR(afl, temp_len - 1); + u32 pos = rand_below(afl, temp_len - 1); - *(u16 *)(out_buf + pos) += 1 + UR(afl, ARITH_MAX); + *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = UR(afl, temp_len - 1); - u16 num = 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 1); + u16 num = 1 + rand_below(afl, ARITH_MAX); *(u16 *)(out_buf + pos) = SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num); @@ -1851,16 +1875,16 @@ havoc_stage: if (temp_len < 4) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - u32 pos = UR(afl, temp_len - 3); + u32 pos = rand_below(afl, temp_len - 3); - *(u32 *)(out_buf + pos) -= 1 + UR(afl, ARITH_MAX); + *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = UR(afl, temp_len - 3); - u32 num = 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 3); + u32 num = 1 + rand_below(afl, ARITH_MAX); *(u32 *)(out_buf + pos) = SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num); @@ -1875,16 +1899,16 @@ havoc_stage: if (temp_len < 4) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - u32 pos = UR(afl, temp_len - 3); + u32 pos = rand_below(afl, temp_len - 3); - *(u32 *)(out_buf + pos) += 1 + UR(afl, ARITH_MAX); + *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = UR(afl, temp_len - 3); - u32 num = 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 3); + u32 num = 1 + rand_below(afl, ARITH_MAX); *(u32 *)(out_buf + pos) = SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num); @@ -1899,7 +1923,7 @@ havoc_stage: why not. We use XOR with 1-255 to eliminate the possibility of a no-op. */ - out_buf[UR(afl, temp_len)] ^= 1 + UR(afl, 255); + out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255); break; case 11 ... 12: { @@ -1916,7 +1940,7 @@ havoc_stage: del_len = choose_block_len(afl, temp_len - 1); - del_from = UR(afl, temp_len - del_len + 1); + del_from = rand_below(afl, temp_len - del_len + 1); memmove(out_buf + del_from, out_buf + del_from + del_len, temp_len - del_from - del_len); @@ -1933,14 +1957,14 @@ havoc_stage: /* Clone bytes (75%) or insert a block of constant bytes (25%). */ - u8 actually_clone = UR(afl, 4); + u8 actually_clone = rand_below(afl, 4); u32 clone_from, clone_to, clone_len; u8 *new_buf; if (actually_clone) { clone_len = choose_block_len(afl, temp_len); - clone_from = UR(afl, temp_len - clone_len + 1); + clone_from = rand_below(afl, temp_len - clone_len + 1); } else { @@ -1949,9 +1973,10 @@ havoc_stage: } - clone_to = UR(afl, temp_len); + clone_to = rand_below(afl, temp_len); - new_buf = ck_alloc_nozero(temp_len + clone_len); + new_buf = + ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + clone_len); /* Head */ @@ -1963,15 +1988,17 @@ havoc_stage: memcpy(new_buf + clone_to, out_buf + clone_from, clone_len); else memset(new_buf + clone_to, - UR(afl, 2) ? UR(afl, 256) : out_buf[UR(afl, temp_len)], + rand_below(afl, 2) ? rand_below(afl, 256) + : out_buf[rand_below(afl, temp_len)], clone_len); /* Tail */ memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, temp_len - clone_to); - ck_free(out_buf); + swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); out_buf = new_buf; + new_buf = NULL; temp_len += clone_len; } @@ -1989,10 +2016,10 @@ havoc_stage: copy_len = choose_block_len(afl, temp_len - 1); - copy_from = UR(afl, temp_len - copy_len + 1); - copy_to = UR(afl, temp_len - copy_len + 1); + copy_from = rand_below(afl, temp_len - copy_len + 1); + copy_to = rand_below(afl, temp_len - copy_len + 1); - if (UR(afl, 4)) { + if (rand_below(afl, 4)) { if (copy_from != copy_to) memmove(out_buf + copy_to, out_buf + copy_from, copy_len); @@ -2000,7 +2027,8 @@ havoc_stage: } else memset(out_buf + copy_to, - UR(afl, 2) ? UR(afl, 256) : out_buf[UR(afl, temp_len)], + rand_below(afl, 2) ? rand_below(afl, 256) + : out_buf[rand_below(afl, temp_len)], copy_len); break; @@ -2014,18 +2042,18 @@ havoc_stage: /* Overwrite bytes with an extra. */ - if (!afl->extras_cnt || (afl->a_extras_cnt && UR(afl, 2))) { + if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) { /* No user-specified extras or odds in our favor. Let's use an auto-detected one. */ - u32 use_extra = UR(afl, afl->a_extras_cnt); + u32 use_extra = rand_below(afl, afl->a_extras_cnt); u32 extra_len = afl->a_extras[use_extra].len; u32 insert_at; if (extra_len > temp_len) break; - insert_at = UR(afl, temp_len - extra_len + 1); + insert_at = rand_below(afl, temp_len - extra_len + 1); memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, extra_len); @@ -2033,13 +2061,13 @@ havoc_stage: /* No auto extras or odds in our favor. Use the dictionary. */ - u32 use_extra = UR(afl, afl->extras_cnt); + u32 use_extra = rand_below(afl, afl->extras_cnt); u32 extra_len = afl->extras[use_extra].len; u32 insert_at; if (extra_len > temp_len) break; - insert_at = UR(afl, temp_len - extra_len + 1); + insert_at = rand_below(afl, temp_len - extra_len + 1); memcpy(out_buf + insert_at, afl->extras[use_extra].data, extra_len); } @@ -2050,20 +2078,21 @@ havoc_stage: case 16: { - u32 use_extra, extra_len, insert_at = UR(afl, temp_len + 1); + u32 use_extra, extra_len, insert_at = rand_below(afl, temp_len + 1); u8 *new_buf; /* Insert an extra. Do the same dice-rolling stuff as for the previous case. */ - if (!afl->extras_cnt || (afl->a_extras_cnt && UR(afl, 2))) { + if (!afl->extras_cnt || (afl->a_extras_cnt && rand_below(afl, 2))) { - use_extra = UR(afl, afl->a_extras_cnt); + use_extra = rand_below(afl, afl->a_extras_cnt); extra_len = afl->a_extras[use_extra].len; if (temp_len + extra_len >= MAX_FILE) break; - new_buf = ck_alloc_nozero(temp_len + extra_len); + new_buf = + ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + extra_len); /* Head */ memcpy(new_buf, out_buf, insert_at); @@ -2074,12 +2103,13 @@ havoc_stage: } else { - use_extra = UR(afl, afl->extras_cnt); + use_extra = rand_below(afl, afl->extras_cnt); extra_len = afl->extras[use_extra].len; if (temp_len + extra_len >= MAX_FILE) break; - new_buf = ck_alloc_nozero(temp_len + extra_len); + new_buf = + ck_maybe_grow(BUF_PARAMS(out_scratch), temp_len + extra_len); /* Head */ memcpy(new_buf, out_buf, insert_at); @@ -2093,8 +2123,9 @@ havoc_stage: memcpy(new_buf + insert_at + extra_len, out_buf + insert_at, temp_len - insert_at); - ck_free(out_buf); + swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); out_buf = new_buf; + new_buf = NULL; temp_len += extra_len; break; @@ -2110,7 +2141,7 @@ havoc_stage: /* out_buf might have been mangled a bit, so let's restore it to its original size and shape. */ - if (temp_len < len) out_buf = ck_realloc(out_buf, len); + out_buf = ck_maybe_grow(BUF_PARAMS(out), len); temp_len = len; memcpy(out_buf, in_buf, len); @@ -2172,7 +2203,6 @@ retry_splicing: if (in_buf != orig_in) { - ck_free(in_buf); in_buf = orig_in; len = afl->queue_cur->len; @@ -2182,7 +2212,7 @@ retry_splicing: do { - tid = UR(afl, afl->queued_paths); + tid = rand_below(afl, afl->queued_paths); } while (tid == afl->current_entry); @@ -2214,9 +2244,9 @@ retry_splicing: fd = open(target->fname, O_RDONLY); - if (fd < 0) PFATAL("Unable to open '%s'", target->fname); + if (unlikely(fd < 0)) PFATAL("Unable to open '%s'", target->fname); - new_buf = ck_alloc_nozero(target->len); + new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), target->len); ck_read(fd, new_buf, target->len, target->fname); @@ -2228,25 +2258,20 @@ retry_splicing: locate_diffs(in_buf, new_buf, MIN(len, target->len), &f_diff, &l_diff); - if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { - - ck_free(new_buf); - goto retry_splicing; - - } + if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { goto retry_splicing; } /* Split somewhere between the first and last differing byte. */ - split_at = f_diff + UR(afl, l_diff - f_diff); + split_at = f_diff + rand_below(afl, l_diff - f_diff); /* Do the thing. */ len = target->len; memcpy(new_buf, in_buf, split_at); + swap_bufs(BUF_PARAMS(in), BUF_PARAMS(in_scratch)); in_buf = new_buf; - ck_free(out_buf); - out_buf = ck_alloc_nozero(len); + out_buf = ck_maybe_grow(BUF_PARAMS(out), len); memcpy(out_buf, in_buf, len); goto custom_mutator_stage; @@ -2263,7 +2288,7 @@ retry_splicing: radamsa_stage: - if (!afl->use_radamsa || !afl->radamsa_mutate_ptr) goto abandon_entry; + if (likely(!afl->use_radamsa || !afl->radamsa_mutate_ptr)) goto abandon_entry; afl->stage_name = "radamsa"; afl->stage_short = "radamsa"; @@ -2274,12 +2299,14 @@ radamsa_stage: orig_hit_cnt = afl->queued_paths + afl->unique_crashes; - /* Read the additional testcase into a new buffer. */ - u8 *save_buf = ck_alloc_nozero(len); + /* Read the additional testcase. + We'll reuse in_scratch, as it is free at this point. + */ + u8 *save_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), len); memcpy(save_buf, out_buf, len); u32 max_len = len + choose_block_len(afl, HAVOC_BLK_XL); - u8 *new_buf = ck_alloc_nozero(max_len); + u8 *new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), max_len); u8 *tmp_buf; for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { @@ -2299,19 +2326,10 @@ radamsa_stage: } - if (common_fuzz_stuff(afl, tmp_buf, temp_len)) { - - ck_free(save_buf); - ck_free(new_buf); - goto abandon_entry; - - } + if (common_fuzz_stuff(afl, tmp_buf, temp_len)) { goto abandon_entry; } } - ck_free(save_buf); - ck_free(new_buf); - new_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_finds[STAGE_RADAMSA] += new_hit_cnt - orig_hit_cnt; @@ -2341,10 +2359,6 @@ abandon_entry: munmap(orig_in, afl->queue_cur->len); - if (in_buf != orig_in) ck_free(in_buf); - ck_free(out_buf); - ck_free(eff_map); - return ret_val; #undef FLIP_BIT @@ -2391,7 +2405,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { cases. */ if ((afl->queue_cur->was_fuzzed || !afl->queue_cur->favored) && - UR(afl, 100) < SKIP_TO_NEW_PROB) + rand_below(afl, 100) < SKIP_TO_NEW_PROB) return 1; } else if (!afl->dumb_mode && !afl->queue_cur->favored && @@ -2404,11 +2418,11 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (afl->queue_cycle > 1 && !afl->queue_cur->was_fuzzed) { - if (UR(afl, 100) < SKIP_NFAV_NEW_PROB) return 1; + if (rand_below(afl, 100) < SKIP_NFAV_NEW_PROB) return 1; } else { - if (UR(afl, 100) < SKIP_NFAV_OLD_PROB) return 1; + if (rand_below(afl, 100) < SKIP_NFAV_OLD_PROB) return 1; } @@ -2443,7 +2457,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { single byte anyway, so it wouldn't give us any performance or memory usage benefits. */ - out_buf = ck_alloc_nozero(len); + out_buf = ck_maybe_grow(BUF_PARAMS(out), len); afl->subseq_tmouts = 0; @@ -2612,7 +2626,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) { - u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) { @@ -2624,7 +2638,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { ++a_len; if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); } else if (cksum != prev_cksum) { @@ -2632,7 +2646,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { worthwhile queued up, and collect that if the answer is yes. */ if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); a_len = 0; prev_cksum = cksum; @@ -2733,7 +2747,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { /* Initialize effector map for the next step (see comments below). Always flag first and last byte as doing something. */ - eff_map = ck_alloc(EFF_ALEN(len)); + eff_map = ck_maybe_grow(BUF_PARAMS(eff), EFF_ALEN(len)); eff_map[0] = 1; if (EFF_APOS(len - 1) != 0) { @@ -2772,7 +2786,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { without wasting time on checksums. */ if (!afl->dumb_mode && len >= EFF_MIN_LEN) - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); else cksum = ~afl->queue_cur->exec_cksum; @@ -3418,7 +3432,7 @@ skip_interest: map. */ if ((afl->extras_cnt > MAX_DET_EXTRAS && - UR(afl, afl->extras_cnt) >= MAX_DET_EXTRAS) || + rand_below(afl, afl->extras_cnt) >= MAX_DET_EXTRAS) || afl->extras[j].len > len - i || !memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) || !memchr(eff_map + EFF_APOS(i), 1, @@ -3457,7 +3471,7 @@ skip_interest: orig_hit_cnt = new_hit_cnt; - ex_tmp = ck_alloc(len + MAX_DICT_FILE); + ex_tmp = ck_maybe_grow(BUF_PARAMS(ex), len + MAX_DICT_FILE); for (i = 0; i <= len; ++i) { @@ -3480,7 +3494,6 @@ skip_interest: if (common_fuzz_stuff(afl, ex_tmp, len + afl->extras[j].len)) { - ck_free(ex_tmp); goto abandon_entry; } @@ -3494,8 +3507,6 @@ skip_interest: } /* for i = 0; i <= len */ - ck_free(ex_tmp); - new_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_finds[STAGE_EXTRAS_UI] += new_hit_cnt - orig_hit_cnt; @@ -3584,9 +3595,9 @@ pacemaker_fuzzing: perf_score = orig_perf; - snprintf(afl->stage_name_buf64, 64, MOpt_globals.splice_stageformat, - splice_cycle); - afl->stage_name = afl->stage_name_buf64; + snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, + MOpt_globals.splice_stageformat, splice_cycle); + afl->stage_name = afl->stage_name_buf; afl->stage_short = MOpt_globals.splice_stagenameshort; afl->stage_max = SPLICE_HAVOC * perf_score / afl->havoc_div / 100; @@ -3605,7 +3616,8 @@ pacemaker_fuzzing: afl->orig_hit_cnt_puppet = afl->queued_paths + afl->unique_crashes; afl->last_limit_time_start = get_cur_time(); afl->SPLICE_CYCLES_puppet = - (UR(afl, SPLICE_CYCLES_puppet_up - SPLICE_CYCLES_puppet_low + 1) + + (rand_below( + afl, SPLICE_CYCLES_puppet_up - SPLICE_CYCLES_puppet_low + 1) + SPLICE_CYCLES_puppet_low); } @@ -3634,9 +3646,9 @@ pacemaker_fuzzing: } else { perf_score = orig_perf; - snprintf(afl->stage_name_buf64, 64, MOpt_globals.splice_stageformat, - splice_cycle); - afl->stage_name = afl->stage_name_buf64; + snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, + MOpt_globals.splice_stageformat, splice_cycle); + afl->stage_name = afl->stage_name_buf; afl->stage_short = MOpt_globals.splice_stagenameshort; afl->stage_max = SPLICE_HAVOC * perf_score / afl->havoc_div / 100; @@ -3653,7 +3665,7 @@ pacemaker_fuzzing: for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { - u32 use_stacking = 1 << (1 + UR(afl, HAVOC_STACK_POW2)); + u32 use_stacking = 1 << (1 + rand_below(afl, HAVOC_STACK_POW2)); afl->stage_cur_val = use_stacking; @@ -3669,13 +3681,13 @@ pacemaker_fuzzing: case 0: /* Flip a single bit somewhere. Spooky! */ - FLIP_BIT(out_buf, UR(afl, temp_len << 3)); + FLIP_BIT(out_buf, rand_below(afl, temp_len << 3)); MOpt_globals.cycles_v2[STAGE_FLIP1] += 1; break; case 1: if (temp_len < 2) break; - temp_len_puppet = UR(afl, (temp_len << 3) - 1); + temp_len_puppet = rand_below(afl, (temp_len << 3) - 1); FLIP_BIT(out_buf, temp_len_puppet); FLIP_BIT(out_buf, temp_len_puppet + 1); MOpt_globals.cycles_v2[STAGE_FLIP2] += 1; @@ -3683,7 +3695,7 @@ pacemaker_fuzzing: case 2: if (temp_len < 2) break; - temp_len_puppet = UR(afl, (temp_len << 3) - 3); + temp_len_puppet = rand_below(afl, (temp_len << 3) - 3); FLIP_BIT(out_buf, temp_len_puppet); FLIP_BIT(out_buf, temp_len_puppet + 1); FLIP_BIT(out_buf, temp_len_puppet + 2); @@ -3693,55 +3705,57 @@ pacemaker_fuzzing: case 3: if (temp_len < 4) break; - out_buf[UR(afl, temp_len)] ^= 0xFF; + out_buf[rand_below(afl, temp_len)] ^= 0xFF; MOpt_globals.cycles_v2[STAGE_FLIP8] += 1; break; case 4: if (temp_len < 8) break; - *(u16 *)(out_buf + UR(afl, temp_len - 1)) ^= 0xFFFF; + *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) ^= 0xFFFF; MOpt_globals.cycles_v2[STAGE_FLIP16] += 1; break; case 5: if (temp_len < 8) break; - *(u32 *)(out_buf + UR(afl, temp_len - 3)) ^= 0xFFFFFFFF; + *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) ^= 0xFFFFFFFF; MOpt_globals.cycles_v2[STAGE_FLIP32] += 1; break; case 6: - out_buf[UR(afl, temp_len)] -= 1 + UR(afl, ARITH_MAX); - out_buf[UR(afl, temp_len)] += 1 + UR(afl, ARITH_MAX); + out_buf[rand_below(afl, temp_len)] -= + 1 + rand_below(afl, ARITH_MAX); + out_buf[rand_below(afl, temp_len)] += + 1 + rand_below(afl, ARITH_MAX); MOpt_globals.cycles_v2[STAGE_ARITH8] += 1; break; case 7: /* Randomly subtract from word, random endian. */ if (temp_len < 8) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - u32 pos = UR(afl, temp_len - 1); - *(u16 *)(out_buf + pos) -= 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 1); + *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = UR(afl, temp_len - 1); - u16 num = 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 1); + u16 num = 1 + rand_below(afl, ARITH_MAX); *(u16 *)(out_buf + pos) = SWAP16(SWAP16(*(u16 *)(out_buf + pos)) - num); } /* Randomly add to word, random endian. */ - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - u32 pos = UR(afl, temp_len - 1); - *(u16 *)(out_buf + pos) += 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 1); + *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = UR(afl, temp_len - 1); - u16 num = 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 1); + u16 num = 1 + rand_below(afl, ARITH_MAX); *(u16 *)(out_buf + pos) = SWAP16(SWAP16(*(u16 *)(out_buf + pos)) + num); @@ -3753,15 +3767,15 @@ pacemaker_fuzzing: case 8: /* Randomly subtract from dword, random endian. */ if (temp_len < 8) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - u32 pos = UR(afl, temp_len - 3); - *(u32 *)(out_buf + pos) -= 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 3); + *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = UR(afl, temp_len - 3); - u32 num = 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 3); + u32 num = 1 + rand_below(afl, ARITH_MAX); *(u32 *)(out_buf + pos) = SWAP32(SWAP32(*(u32 *)(out_buf + pos)) - num); @@ -3769,15 +3783,15 @@ pacemaker_fuzzing: /* Randomly add to dword, random endian. */ // if (temp_len < 4) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - u32 pos = UR(afl, temp_len - 3); - *(u32 *)(out_buf + pos) += 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 3); + *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX); } else { - u32 pos = UR(afl, temp_len - 3); - u32 num = 1 + UR(afl, ARITH_MAX); + u32 pos = rand_below(afl, temp_len - 3); + u32 num = 1 + rand_below(afl, ARITH_MAX); *(u32 *)(out_buf + pos) = SWAP32(SWAP32(*(u32 *)(out_buf + pos)) + num); @@ -3789,23 +3803,25 @@ pacemaker_fuzzing: case 9: /* Set byte to interesting value. */ if (temp_len < 4) break; - out_buf[UR(afl, temp_len)] = - interesting_8[UR(afl, sizeof(interesting_8))]; + out_buf[rand_below(afl, temp_len)] = + interesting_8[rand_below(afl, sizeof(interesting_8))]; MOpt_globals.cycles_v2[STAGE_INTEREST8] += 1; break; case 10: /* Set word to interesting value, randomly choosing endian. */ if (temp_len < 8) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - *(u16 *)(out_buf + UR(afl, temp_len - 1)) = - interesting_16[UR(afl, sizeof(interesting_16) >> 1)]; + *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = + interesting_16[rand_below(afl, + sizeof(interesting_16) >> 1)]; } else { - *(u16 *)(out_buf + UR(afl, temp_len - 1)) = SWAP16( - interesting_16[UR(afl, sizeof(interesting_16) >> 1)]); + *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = + SWAP16(interesting_16[rand_below( + afl, sizeof(interesting_16) >> 1)]); } @@ -3817,15 +3833,17 @@ pacemaker_fuzzing: if (temp_len < 8) break; - if (UR(afl, 2)) { + if (rand_below(afl, 2)) { - *(u32 *)(out_buf + UR(afl, temp_len - 3)) = - interesting_32[UR(afl, sizeof(interesting_32) >> 2)]; + *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = + interesting_32[rand_below(afl, + sizeof(interesting_32) >> 2)]; } else { - *(u32 *)(out_buf + UR(afl, temp_len - 3)) = SWAP32( - interesting_32[UR(afl, sizeof(interesting_32) >> 2)]); + *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = + SWAP32(interesting_32[rand_below( + afl, sizeof(interesting_32) >> 2)]); } @@ -3838,7 +3856,7 @@ pacemaker_fuzzing: why not. We use XOR with 1-255 to eliminate the possibility of a no-op. */ - out_buf[UR(afl, temp_len)] ^= 1 + UR(afl, 255); + out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255); MOpt_globals.cycles_v2[STAGE_RANDOMBYTE] += 1; break; @@ -3856,7 +3874,7 @@ pacemaker_fuzzing: del_len = choose_block_len(afl, temp_len - 1); - del_from = UR(afl, temp_len - del_len + 1); + del_from = rand_below(afl, temp_len - del_len + 1); memmove(out_buf + del_from, out_buf + del_from + del_len, temp_len - del_from - del_len); @@ -3874,14 +3892,14 @@ pacemaker_fuzzing: /* Clone bytes (75%) or insert a block of constant bytes (25%). */ - u8 actually_clone = UR(afl, 4); + u8 actually_clone = rand_below(afl, 4); u32 clone_from, clone_to, clone_len; u8 *new_buf; if (actually_clone) { clone_len = choose_block_len(afl, temp_len); - clone_from = UR(afl, temp_len - clone_len + 1); + clone_from = rand_below(afl, temp_len - clone_len + 1); } else { @@ -3890,9 +3908,10 @@ pacemaker_fuzzing: } - clone_to = UR(afl, temp_len); + clone_to = rand_below(afl, temp_len); - new_buf = ck_alloc_nozero(temp_len + clone_len); + new_buf = ck_maybe_grow(BUF_PARAMS(out_scratch), + temp_len + clone_len); /* Head */ @@ -3904,14 +3923,16 @@ pacemaker_fuzzing: memcpy(new_buf + clone_to, out_buf + clone_from, clone_len); else memset(new_buf + clone_to, - UR(afl, 2) ? UR(afl, 256) : out_buf[UR(afl, temp_len)], + rand_below(afl, 2) + ? rand_below(afl, 256) + : out_buf[rand_below(afl, temp_len)], clone_len); /* Tail */ memcpy(new_buf + clone_to + clone_len, out_buf + clone_to, temp_len - clone_to); - ck_free(out_buf); + swap_bufs(BUF_PARAMS(out), BUF_PARAMS(out_scratch)); out_buf = new_buf; temp_len += clone_len; MOpt_globals.cycles_v2[STAGE_Clone75] += 1; @@ -3931,10 +3952,10 @@ pacemaker_fuzzing: copy_len = choose_block_len(afl, temp_len - 1); - copy_from = UR(afl, temp_len - copy_len + 1); - copy_to = UR(afl, temp_len - copy_len + 1); + copy_from = rand_below(afl, temp_len - copy_len + 1); + copy_to = rand_below(afl, temp_len - copy_len + 1); - if (UR(afl, 4)) { + if (rand_below(afl, 4)) { if (copy_from != copy_to) memmove(out_buf + copy_to, out_buf + copy_from, copy_len); @@ -3942,7 +3963,8 @@ pacemaker_fuzzing: } else memset(out_buf + copy_to, - UR(afl, 2) ? UR(afl, 256) : out_buf[UR(afl, temp_len)], + rand_below(afl, 2) ? rand_below(afl, 256) + : out_buf[rand_below(afl, temp_len)], copy_len); MOpt_globals.cycles_v2[STAGE_OverWrite75] += 1; break; @@ -3963,7 +3985,7 @@ pacemaker_fuzzing: /* out_buf might have been mangled a bit, so let's restore it to its original size and shape. */ - if (temp_len < len) out_buf = ck_realloc(out_buf, len); + out_buf = ck_maybe_grow(BUF_PARAMS(out), len); temp_len = len; memcpy(out_buf, in_buf, len); @@ -4041,7 +4063,6 @@ pacemaker_fuzzing: if (in_buf != orig_in) { - ck_free(in_buf); in_buf = orig_in; len = afl->queue_cur->len; @@ -4052,7 +4073,7 @@ pacemaker_fuzzing: do { - tid = UR(afl, afl->queued_paths); + tid = rand_below(afl, afl->queued_paths); } while (tid == afl->current_entry); @@ -4086,7 +4107,7 @@ pacemaker_fuzzing: if (fd < 0) PFATAL("Unable to open '%s'", target->fname); - new_buf = ck_alloc_nozero(target->len); + new_buf = ck_maybe_grow(BUF_PARAMS(in_scratch), target->len); ck_read(fd, new_buf, target->len, target->fname); @@ -4100,22 +4121,21 @@ pacemaker_fuzzing: if (f_diff < 0 || l_diff < 2 || f_diff == l_diff) { - ck_free(new_buf); goto retry_splicing_puppet; } /* Split somewhere between the first and last differing byte. */ - split_at = f_diff + UR(afl, l_diff - f_diff); + split_at = f_diff + rand_below(afl, l_diff - f_diff); /* Do the thing. */ len = target->len; memcpy(new_buf, in_buf, split_at); + swap_bufs(BUF_PARAMS(in), BUF_PARAMS(in_scratch)); in_buf = new_buf; - ck_free(out_buf); - out_buf = ck_alloc_nozero(len); + out_buf = ck_maybe_grow(BUF_PARAMS(out), len); memcpy(out_buf, in_buf, len); goto havoc_stage_puppet; @@ -4131,7 +4151,8 @@ pacemaker_fuzzing: if (splice_cycle >= afl->SPLICE_CYCLES_puppet) afl->SPLICE_CYCLES_puppet = - (UR(afl, SPLICE_CYCLES_puppet_up - SPLICE_CYCLES_puppet_low + 1) + + (rand_below( + afl, SPLICE_CYCLES_puppet_up - SPLICE_CYCLES_puppet_low + 1) + SPLICE_CYCLES_puppet_low); afl->splicing_with = -1; @@ -4149,10 +4170,6 @@ pacemaker_fuzzing: munmap(orig_in, afl->queue_cur->len); - if (in_buf != orig_in) ck_free(in_buf); - ck_free(out_buf); - ck_free(eff_map); - if (afl->key_puppet == 1) { if (unlikely( @@ -4374,18 +4391,13 @@ u8 fuzz_one(afl_state_t *afl) { int key_val_lv = 0; #ifdef _AFL_DOCUMENT_MUTATIONS - if (afl->do_document == 0) { - char *fn = alloc_printf("%s/mutations", afl->out_dir); - if (fn) { - - afl->do_document = mkdir(fn, 0700); // if it exists we do not care - afl->do_document = 1; - ck_free(fn); - - } else + u8 path_buf[PATH_MAX]; + if (afl->do_document == 0) { - PFATAL("malloc()"); + snprintf(path_buf, PATH_MAX, "%s/mutations", afl->out_dir); + afl->do_document = mkdir(path_buf, 0700); // if it exists we do not care + afl->do_document = 1; } else { @@ -4413,5 +4425,7 @@ u8 fuzz_one(afl_state_t *afl) { return key_val_lv; +#undef BUF_PARAMS + } diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 595c1ed0..12c3a09d 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -28,9 +28,93 @@ /* Python stuff */ #ifdef USE_PYTHON -int init_py_module(afl_state_t *afl, u8 *module_name) { +static void *unsupported(afl_state_t *afl, unsigned int seed) { - if (!module_name) return 1; + FATAL("Python Mutator cannot be called twice yet"); + return NULL; + +} + +/* sorry for this makro... +it just fills in `&py_mutator->something_buf, &py_mutator->something_size`. */ +#define BUF_PARAMS(name) \ + (void **)&((py_mutator_t *)py_mutator)->name##_buf, \ + &((py_mutator_t *)py_mutator)->name##_size + +size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf, + u8 *add_buf, size_t add_buf_size, size_t max_size) { + + size_t mutated_size; + PyObject *py_args, *py_value; + py_args = PyTuple_New(3); + py_mutator_t *py = (py_mutator_t *)py_mutator; + + /* buf */ + py_value = PyByteArray_FromStringAndSize(buf, buf_size); + if (!py_value) { + + Py_DECREF(py_args); + FATAL("Failed to convert arguments"); + + } + + PyTuple_SetItem(py_args, 0, py_value); + + /* add_buf */ + py_value = PyByteArray_FromStringAndSize(add_buf, add_buf_size); + if (!py_value) { + + Py_DECREF(py_args); + FATAL("Failed to convert arguments"); + + } + + PyTuple_SetItem(py_args, 1, py_value); + + /* max_size */ +#if PY_MAJOR_VERSION >= 3 + py_value = PyLong_FromLong(max_size); +#else + py_value = PyInt_FromLong(max_size); +#endif + if (!py_value) { + + Py_DECREF(py_args); + FATAL("Failed to convert arguments"); + + } + + PyTuple_SetItem(py_args, 2, py_value); + + py_value = PyObject_CallObject(py->py_functions[PY_FUNC_FUZZ], py_args); + + Py_DECREF(py_args); + + if (py_value != NULL) { + + mutated_size = PyByteArray_Size(py_value); + + *out_buf = ck_maybe_grow(BUF_PARAMS(fuzz), mutated_size); + + memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size); + Py_DECREF(py_value); + return mutated_size; + + } else { + + PyErr_Print(); + FATAL("python custom fuzz: call failed"); + + } + +} + +static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { + + if (!module_name) return NULL; + + py_mutator_t *py = calloc(1, sizeof(py_mutator_t)); + if (!py) PFATAL("Could not allocate memory for python mutator!"); Py_Initialize(); @@ -40,17 +124,18 @@ int init_py_module(afl_state_t *afl, u8 *module_name) { PyObject *py_name = PyString_FromString(module_name); #endif - afl->py_module = PyImport_Import(py_name); + py->py_module = PyImport_Import(py_name); Py_DECREF(py_name); - PyObject * py_module = afl->py_module; - PyObject **py_functions = afl->py_functions; + PyObject * py_module = py->py_module; + PyObject **py_functions = py->py_functions; - if (afl->py_module != NULL) { + if (py_module != NULL) { u8 py_notrim = 0, py_idx; - py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(afl->py_module, "init"); - py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(afl->py_module, "fuzz"); + /* init, required */ + py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init"); + py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz"); py_functions[PY_FUNC_PRE_SAVE] = PyObject_GetAttrString(py_module, "pre_save"); py_functions[PY_FUNC_INIT_TRIM] = @@ -66,6 +151,7 @@ int init_py_module(afl_state_t *afl, u8 *module_name) { PyObject_GetAttrString(py_module, "queue_get"); py_functions[PY_FUNC_QUEUE_NEW_ENTRY] = PyObject_GetAttrString(py_module, "queue_new_entry"); + py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit"); for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) { @@ -96,7 +182,7 @@ int init_py_module(afl_state_t *afl, u8 *module_name) { "Cannot find/call function with index %d in external " "Python module.\n", py_idx); - return 1; + return NULL; } @@ -119,23 +205,27 @@ int init_py_module(afl_state_t *afl, u8 *module_name) { PyErr_Print(); fprintf(stderr, "Failed to load \"%s\"\n", module_name); - return 1; + return NULL; } - return 0; + return py; } -void finalize_py_module(afl_state_t *afl) { +void finalize_py_module(void *py_mutator) { - if (afl->py_module != NULL) { + py_mutator_t *py = (py_mutator_t *)py_mutator; + + if (py->py_module != NULL) { + + deinit_py(py_mutator); u32 i; for (i = 0; i < PY_FUNC_COUNT; ++i) - Py_XDECREF(afl->py_functions[i]); + Py_XDECREF(py->py_functions[i]); - Py_DECREF(afl->py_module); + Py_DECREF(py->py_module); } @@ -143,7 +233,8 @@ void finalize_py_module(afl_state_t *afl) { } -void init_py(afl_state_t *afl, unsigned int seed) { +static void init_py(afl_state_t *afl, py_mutator_t *py_mutator, + unsigned int seed) { PyObject *py_args, *py_value; @@ -158,14 +249,14 @@ void init_py(afl_state_t *afl, unsigned int seed) { if (!py_value) { Py_DECREF(py_args); - fprintf(stderr, "Cannot convert argument\n"); - return; + FATAL("Cannot convert argument in python init."); } PyTuple_SetItem(py_args, 0, py_value); - py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_INIT], py_args); + py_value = + PyObject_CallObject(py_mutator->py_functions[PY_FUNC_INIT], py_args); Py_DECREF(py_args); @@ -173,115 +264,133 @@ void init_py(afl_state_t *afl, unsigned int seed) { PyErr_Print(); fprintf(stderr, "Call failed\n"); - return; + FATAL("Custom py mutator INIT failed."); } } -size_t fuzz_py(afl_state_t *afl, u8 **buf, size_t buf_size, u8 *add_buf, - size_t add_buf_size, size_t max_size) { +void deinit_py(void *py_mutator) { - size_t mutated_size; PyObject *py_args, *py_value; - py_args = PyTuple_New(3); - /* buf */ - py_value = PyByteArray_FromStringAndSize(*buf, buf_size); - if (!py_value) { + py_args = PyTuple_New(0); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_DEINIT], py_args); + Py_DECREF(py_args); - Py_DECREF(py_args); - FATAL("Failed to convert arguments"); + if (py_value != NULL) { + + Py_DECREF(py_value); + + } else { + + PyErr_Print(); + FATAL("Call failed"); } - PyTuple_SetItem(py_args, 0, py_value); +} - /* add_buf */ - py_value = PyByteArray_FromStringAndSize(add_buf, add_buf_size); - if (!py_value) { +void load_custom_mutator_py(afl_state_t *afl, char *module_name) { - Py_DECREF(py_args); - FATAL("Failed to convert arguments"); + afl->mutator = ck_alloc(sizeof(struct custom_mutator)); + afl->mutator->pre_save_buf = NULL; + afl->mutator->pre_save_size = 0; - } + afl->mutator->name = module_name; + ACTF("Loading Python mutator library from '%s'...", module_name); - PyTuple_SetItem(py_args, 1, py_value); + py_mutator_t *py_mutator; + py_mutator = init_py_module(afl, module_name); + afl->mutator->data = py_mutator; + if (!py_mutator) { FATAL("Failed to load python mutator."); } - /* max_size */ -#if PY_MAJOR_VERSION >= 3 - py_value = PyLong_FromLong(max_size); -#else - py_value = PyInt_FromLong(max_size); -#endif - if (!py_value) { + PyObject **py_functions = py_mutator->py_functions; - Py_DECREF(py_args); - FATAL("Failed to convert arguments"); + if (py_functions[PY_FUNC_INIT]) afl->mutator->afl_custom_init = unsupported; - } + if (py_functions[PY_FUNC_DEINIT]) afl->mutator->afl_custom_deinit = deinit_py; - PyTuple_SetItem(py_args, 2, py_value); + /* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator + is quite different from the custom mutator. */ + afl->mutator->afl_custom_fuzz = fuzz_py; - py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_FUZZ], py_args); + if (py_functions[PY_FUNC_PRE_SAVE]) + afl->mutator->afl_custom_pre_save = pre_save_py; - Py_DECREF(py_args); + if (py_functions[PY_FUNC_INIT_TRIM]) + afl->mutator->afl_custom_init_trim = init_trim_py; - if (py_value != NULL) { + if (py_functions[PY_FUNC_POST_TRIM]) + afl->mutator->afl_custom_post_trim = post_trim_py; - mutated_size = PyByteArray_Size(py_value); - if (buf_size < mutated_size) *buf = ck_realloc(*buf, mutated_size); + if (py_functions[PY_FUNC_TRIM]) afl->mutator->afl_custom_trim = trim_py; - memcpy(*buf, PyByteArray_AsString(py_value), mutated_size); - Py_DECREF(py_value); - return mutated_size; + if (py_functions[PY_FUNC_HAVOC_MUTATION]) + afl->mutator->afl_custom_havoc_mutation = havoc_mutation_py; - } else { + if (py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY]) + afl->mutator->afl_custom_havoc_mutation_probability = + havoc_mutation_probability_py; - PyErr_Print(); - FATAL("Call failed"); + if (py_functions[PY_FUNC_QUEUE_GET]) + afl->mutator->afl_custom_queue_get = queue_get_py; - } + if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY]) + afl->mutator->afl_custom_queue_new_entry = queue_new_entry_py; + + OKF("Python mutator '%s' installed successfully.", module_name); + + /* Initialize the custom mutator */ + init_py(afl, py_mutator, rand_below(afl, 0xFFFFFFFF)); } -size_t pre_save_py(afl_state_t *afl, u8 *buf, size_t buf_size, u8 **out_buf) { +size_t pre_save_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf) { + + size_t py_out_buf_size; + PyObject * py_args, *py_value; + py_mutator_t *py = (py_mutator_t *)py_mutator; - size_t out_buf_size; - PyObject *py_args, *py_value; py_args = PyTuple_New(1); py_value = PyByteArray_FromStringAndSize(buf, buf_size); if (!py_value) { Py_DECREF(py_args); - FATAL("Failed to convert arguments"); + FATAL("Failed to convert arguments in custom pre_save"); } PyTuple_SetItem(py_args, 0, py_value); - py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_PRE_SAVE], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_PRE_SAVE], py_args); Py_DECREF(py_args); if (py_value != NULL) { - out_buf_size = PyByteArray_Size(py_value); - *out_buf = malloc(out_buf_size); - memcpy(*out_buf, PyByteArray_AsString(py_value), out_buf_size); + py_out_buf_size = PyByteArray_Size(py_value); + + ck_maybe_grow(BUF_PARAMS(pre_save), py_out_buf_size); + + memcpy(py->pre_save_buf, PyByteArray_AsString(py_value), py_out_buf_size); Py_DECREF(py_value); - return out_buf_size; + + *out_buf = py->pre_save_buf; + return py_out_buf_size; } else { PyErr_Print(); - FATAL("Call failed"); + FATAL("Python custom mutator: pre_save call failed."); } } -u32 init_trim_py(afl_state_t *afl, u8 *buf, size_t buf_size) { +s32 init_trim_py(void *py_mutator, u8 *buf, size_t buf_size) { PyObject *py_args, *py_value; @@ -296,7 +405,8 @@ u32 init_trim_py(afl_state_t *afl, u8 *buf, size_t buf_size) { PyTuple_SetItem(py_args, 0, py_value); - py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_INIT_TRIM], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_INIT_TRIM], py_args); Py_DECREF(py_args); if (py_value != NULL) { @@ -318,7 +428,7 @@ u32 init_trim_py(afl_state_t *afl, u8 *buf, size_t buf_size) { } -u32 post_trim_py(afl_state_t *afl, u8 success) { +s32 post_trim_py(void *py_mutator, u8 success) { PyObject *py_args, *py_value; @@ -334,7 +444,8 @@ u32 post_trim_py(afl_state_t *afl, u8 success) { PyTuple_SetItem(py_args, 0, py_value); - py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_POST_TRIM], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_POST_TRIM], py_args); Py_DECREF(py_args); if (py_value != NULL) { @@ -356,19 +467,21 @@ u32 post_trim_py(afl_state_t *afl, u8 success) { } -void trim_py(afl_state_t *afl, u8 **out_buf, size_t *out_buf_size) { +size_t trim_py(void *py_mutator, u8 **out_buf) { PyObject *py_args, *py_value; + size_t ret; py_args = PyTuple_New(0); - py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_TRIM], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_TRIM], py_args); Py_DECREF(py_args); if (py_value != NULL) { - *out_buf_size = PyByteArray_Size(py_value); - *out_buf = malloc(*out_buf_size); - memcpy(*out_buf, PyByteArray_AsString(py_value), *out_buf_size); + ret = PyByteArray_Size(py_value); + *out_buf = ck_maybe_grow(BUF_PARAMS(trim), ret); + memcpy(*out_buf, PyByteArray_AsString(py_value), ret); Py_DECREF(py_value); } else { @@ -378,17 +491,19 @@ void trim_py(afl_state_t *afl, u8 **out_buf, size_t *out_buf_size) { } + return ret; + } -size_t havoc_mutation_py(afl_state_t *afl, u8 **buf, size_t buf_size, - size_t max_size) { +size_t havoc_mutation_py(void *py_mutator, u8 *buf, size_t buf_size, + u8 **out_buf, size_t max_size) { size_t mutated_size; PyObject *py_args, *py_value; py_args = PyTuple_New(2); /* buf */ - py_value = PyByteArray_FromStringAndSize(*buf, buf_size); + py_value = PyByteArray_FromStringAndSize(buf, buf_size); if (!py_value) { Py_DECREF(py_args); @@ -413,17 +528,28 @@ size_t havoc_mutation_py(afl_state_t *afl, u8 **buf, size_t buf_size, PyTuple_SetItem(py_args, 1, py_value); - py_value = - PyObject_CallObject(afl->py_functions[PY_FUNC_HAVOC_MUTATION], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_HAVOC_MUTATION], + py_args); Py_DECREF(py_args); if (py_value != NULL) { mutated_size = PyByteArray_Size(py_value); - if (buf_size < mutated_size) *buf = ck_realloc(*buf, mutated_size); + if (mutated_size <= buf_size) { + + /* We reuse the input buf here. */ + *out_buf = buf; - memcpy(*buf, PyByteArray_AsString(py_value), mutated_size); + } else { + + /* A new buf is needed... */ + *out_buf = ck_maybe_grow(BUF_PARAMS(havoc), mutated_size); + + } + + memcpy(*out_buf, PyByteArray_AsString(py_value), mutated_size); Py_DECREF(py_value); return mutated_size; @@ -437,13 +563,15 @@ size_t havoc_mutation_py(afl_state_t *afl, u8 **buf, size_t buf_size, } -u8 havoc_mutation_probability_py(afl_state_t *afl) { +u8 havoc_mutation_probability_py(void *py_mutator) { PyObject *py_args, *py_value; py_args = PyTuple_New(0); py_value = PyObject_CallObject( - afl->py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY], py_args); + ((py_mutator_t *)py_mutator) + ->py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY], + py_args); Py_DECREF(py_args); if (py_value != NULL) { @@ -461,7 +589,7 @@ u8 havoc_mutation_probability_py(afl_state_t *afl) { } -u8 queue_get_py(afl_state_t *afl, const u8 *filename) { +u8 queue_get_py(void *py_mutator, const u8 *filename) { PyObject *py_args, *py_value; @@ -483,7 +611,8 @@ u8 queue_get_py(afl_state_t *afl, const u8 *filename) { PyTuple_SetItem(py_args, 0, py_value); // Call Python function - py_value = PyObject_CallObject(afl->py_functions[PY_FUNC_QUEUE_GET], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_QUEUE_GET], py_args); Py_DECREF(py_args); if (py_value != NULL) { @@ -509,7 +638,7 @@ u8 queue_get_py(afl_state_t *afl, const u8 *filename) { } -void queue_new_entry_py(afl_state_t *afl, const u8 *filename_new_queue, +void queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue, const u8 *filename_orig_queue) { PyObject *py_args, *py_value; @@ -552,8 +681,9 @@ void queue_new_entry_py(afl_state_t *afl, const u8 *filename_new_queue, PyTuple_SetItem(py_args, 1, py_value); // Call - py_value = - PyObject_CallObject(afl->py_functions[PY_FUNC_QUEUE_NEW_ENTRY], py_args); + py_value = PyObject_CallObject( + ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_QUEUE_NEW_ENTRY], + py_args); Py_DECREF(py_args); if (py_value == NULL) { @@ -565,5 +695,7 @@ void queue_new_entry_py(afl_state_t *afl, const u8 *filename_new_queue, } +#undef BUF_PARAMS + #endif /* USE_PYTHON */ diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index cfeab798..346c2639 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -23,6 +23,7 @@ */ #include "afl-fuzz.h" +#include <limits.h> /* Mark deterministic checks as done for a particular queue entry. We use the .state file to avoid repeating deterministic fuzzing when resuming aborted @@ -30,18 +31,16 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) { - u8 *fn = strrchr(q->fname, '/'); + u8 fn[PATH_MAX]; s32 fd; - fn = alloc_printf("%s/queue/.state/deterministic_done/%s", afl->out_dir, - fn + 1); + snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir, + strrchr(q->fname, '/') + 1); fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd < 0) PFATAL("Unable to create '%s'", fn); close(fd); - ck_free(fn); - q->passed_det = 1; } @@ -51,10 +50,13 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) { void mark_as_variable(afl_state_t *afl, struct queue_entry *q) { - u8 *fn = strrchr(q->fname, '/') + 1, *ldest; + u8 fn[PATH_MAX]; + u8 ldest[PATH_MAX]; + + u8 *fn_name = strrchr(q->fname, '/') + 1; - ldest = alloc_printf("../../%s", fn); - fn = alloc_printf("%s/queue/.state/variable_behavior/%s", afl->out_dir, fn); + sprintf(ldest, "../../%s", fn_name); + sprintf(fn, "%s/queue/.state/variable_behavior/%s", afl->out_dir, fn_name); if (symlink(ldest, fn)) { @@ -64,9 +66,6 @@ void mark_as_variable(afl_state_t *afl, struct queue_entry *q) { } - ck_free(ldest); - ck_free(fn); - q->var_behavior = 1; } @@ -76,14 +75,14 @@ void mark_as_variable(afl_state_t *afl, struct queue_entry *q) { void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { - u8 *fn; + u8 fn[PATH_MAX]; if (state == q->fs_redundant) return; q->fs_redundant = state; - fn = strrchr(q->fname, '/'); - fn = alloc_printf("%s/queue/.state/redundant_edges/%s", afl->out_dir, fn + 1); + sprintf(fn, "%s/queue/.state/redundant_edges/%s", afl->out_dir, + strrchr(q->fname, '/') + 1); if (state) { @@ -99,8 +98,6 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { } - ck_free(fn); - } /* Append new test case to the queue. */ @@ -114,6 +111,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { q->depth = afl->cur_depth + 1; q->passed_det = passed_det; q->n_fuzz = 1; + q->trace_mini = NULL; if (q->depth > afl->max_depth) afl->max_depth = q->depth; @@ -147,7 +145,8 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { /* At the initialization stage, queue_cur is NULL */ if (afl->queue_cur) fname_orig = afl->queue_cur->fname; - afl->mutator->afl_custom_queue_new_entry(afl, fname, fname_orig); + afl->mutator->afl_custom_queue_new_entry(afl->mutator->data, fname, + fname_orig); } @@ -185,35 +184,50 @@ void destroy_queue(afl_state_t *afl) { void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { u32 i; - u64 fav_factor = q->exec_us * q->len; - u64 fuzz_p2 = next_p2(q->n_fuzz); + u64 fav_factor; + u64 fuzz_p2 = next_pow2(q->n_fuzz); + + if (afl->schedule == MMOPT || afl->schedule == RARE || + unlikely(afl->fixed_seed)) + fav_factor = q->len << 2; + else + fav_factor = q->exec_us * q->len; /* For every byte set in afl->fsrv.trace_bits[], see if there is a previous winner, and how it compares to us. */ - - for (i = 0; i < MAP_SIZE; ++i) + for (i = 0; i < afl->fsrv.map_size; ++i) if (afl->fsrv.trace_bits[i]) { if (afl->top_rated[i]) { /* Faster-executing or smaller test cases are favored. */ - u64 top_rated_fuzz_p2 = next_p2(afl->top_rated[i]->n_fuzz); - u64 top_rated_fav_factor = - afl->top_rated[i]->exec_us * afl->top_rated[i]->len; + u64 top_rated_fav_factor; + u64 top_rated_fuzz_p2 = next_pow2(afl->top_rated[i]->n_fuzz); - if (fuzz_p2 > top_rated_fuzz_p2) { + if (afl->schedule == MMOPT || afl->schedule == RARE || + unlikely(afl->fixed_seed)) + top_rated_fav_factor = afl->top_rated[i]->len << 2; + else + top_rated_fav_factor = + afl->top_rated[i]->exec_us * afl->top_rated[i]->len; + if (fuzz_p2 > top_rated_fuzz_p2) continue; + else if (fuzz_p2 == top_rated_fuzz_p2) + if (fav_factor > top_rated_fav_factor) continue; - } else if (fuzz_p2 == top_rated_fuzz_p2) { + if (afl->schedule == MMOPT || afl->schedule == RARE || + unlikely(afl->fixed_seed)) { - if (fav_factor > top_rated_fav_factor) continue; + if (fav_factor > afl->top_rated[i]->len << 2) continue; - } + } else { - if (fav_factor > afl->top_rated[i]->exec_us * afl->top_rated[i]->len) - continue; + if (fav_factor > afl->top_rated[i]->exec_us * afl->top_rated[i]->len) + continue; + + } /* Looks like we're going to win. Decrease ref count for the previous winner, discard its afl->fsrv.trace_bits[] if necessary. */ @@ -234,8 +248,10 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { if (!q->trace_mini) { - q->trace_mini = ck_alloc(MAP_SIZE >> 3); - minimize_bits(q->trace_mini, afl->fsrv.trace_bits); + u32 len = (afl->fsrv.map_size >> 3); + if (len == 0) len = 1; + q->trace_mini = ck_alloc(len); + minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits); } @@ -254,14 +270,17 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { void cull_queue(afl_state_t *afl) { struct queue_entry *q; - static u8 temp_v[MAP_SIZE >> 3]; + u32 len = (afl->fsrv.map_size >> 3); u32 i; + u8 temp_v[MAP_SIZE >> 3]; + + if (len == 0) len = 1; if (afl->dumb_mode || !afl->score_changed) return; afl->score_changed = 0; - memset(temp_v, 255, MAP_SIZE >> 3); + memset(temp_v, 255, len); afl->queued_favored = 0; afl->pending_favored = 0; @@ -278,10 +297,10 @@ void cull_queue(afl_state_t *afl) { /* Let's see if anything in the bitmap isn't captured in temp_v. If yes, and if it has a afl->top_rated[] contender, let's use it. */ - for (i = 0; i < MAP_SIZE; ++i) + for (i = 0; i < afl->fsrv.map_size; ++i) if (afl->top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) { - u32 j = MAP_SIZE >> 3; + u32 j = len; /* Remove all bits belonging to the current entry from temp_v. */ @@ -328,7 +347,8 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { // Longer execution time means longer work on the input, the deeper in // coverage, the better the fuzzing, right? -mh - if (afl->schedule != MMOPT) { + if (afl->schedule != MMOPT && afl->schedule != RARE && + likely(!afl->fixed_seed)) { if (q->exec_us * 0.1 > avg_exec_us) perf_score = 10; @@ -438,7 +458,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { if (q->fuzz_level < 16) factor = ((u32)(1 << q->fuzz_level)) / (fuzz == 0 ? 1 : fuzz); else - factor = MAX_FACTOR / (fuzz == 0 ? 1 : next_p2(fuzz)); + factor = MAX_FACTOR / (fuzz == 0 ? 1 : next_pow2(fuzz)); break; case LIN: factor = q->fuzz_level / (fuzz == 0 ? 1 : fuzz); break; @@ -448,8 +468,29 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) { break; case MMOPT: + /* -- this was a more complex setup, which is good, but competed with + -- rare. the simpler algo however is good when rare is not. + // the newer the entry, the higher the pref_score + perf_score *= (1 + (double)((double)q->depth / + (double)afl->queued_paths)); + // with special focus on the last 8 entries + if (afl->max_depth - q->depth < 8) perf_score *= (1 + ((8 - + (afl->max_depth - q->depth)) / 5)); + */ + // put focus on the last 5 entries + if (afl->max_depth - q->depth < 5) perf_score *= 2; + + break; + + case RARE: - if (afl->max_depth - q->depth < 5) perf_score *= 1.5; + // increase the score for every bitmap byte for which this entry + // is the top contender + perf_score += (q->tc_ref * 10); + // the more often fuzz result paths are equal to this queue entry, + // reduce its value + perf_score *= + (1 - (double)((double)q->n_fuzz / (double)afl->total_execs)); break; diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index c8d54ce2..ba24890b 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -88,7 +88,7 @@ static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u32 *cksum) { if (unlikely(common_fuzz_stuff(afl, buf, len))) return 1; - *cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + *cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); return 0; } @@ -97,7 +97,7 @@ static void rand_replace(afl_state_t *afl, u8 *buf, u32 len) { u32 i; for (i = 0; i < len; ++i) - buf[i] = UR(afl, 256); + buf[i] = rand_below(afl, 256); } @@ -337,7 +337,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { } - maybe_add_auto(afl, (u8 *)&v, shape); + maybe_add_auto((u8 *)afl, (u8 *)&v, shape); u64 rev; switch (shape) { @@ -345,15 +345,15 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { case 1: break; case 2: rev = SWAP16((u16)v); - maybe_add_auto(afl, (u8 *)&rev, shape); + maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); break; case 4: rev = SWAP32((u32)v); - maybe_add_auto(afl, (u8 *)&rev, shape); + maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); break; case 8: rev = SWAP64(v); - maybe_add_auto(afl, (u8 *)&rev, shape); + maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); break; } @@ -511,8 +511,8 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { if (fails == 8) { if (afl->pass_stats[key].total == 0) { - maybe_add_auto(afl, o->v0, SHAPE_BYTES(h->shape)); - maybe_add_auto(afl, o->v1, SHAPE_BYTES(h->shape)); + maybe_add_auto((u8 *)afl, o->v0, SHAPE_BYTES(h->shape)); + maybe_add_auto((u8 *)afl, o->v1, SHAPE_BYTES(h->shape)); } } @@ -569,9 +569,10 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, afl->shm.cmp_map->headers[k].hits = 0; if (afl->shm.cmp_map->headers[k].type == CMP_TYPE_INS) - afl->stage_max += MIN(afl->shm.cmp_map->headers[k].hits, CMP_MAP_H); + afl->stage_max += MIN((u32)afl->shm.cmp_map->headers[k].hits, CMP_MAP_H); else - afl->stage_max += MIN(afl->shm.cmp_map->headers[k].hits, CMP_MAP_RTN_H); + afl->stage_max += + MIN((u32)afl->shm.cmp_map->headers[k].hits, CMP_MAP_RTN_H); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index cdec75e8..1ddd7e1a 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -27,78 +27,62 @@ #include <sys/time.h> #include <signal.h> -/* Execute target application, monitoring for timeouts. Return status - information. The called program will update afl->fsrv.trace_bits[]. */ - -void timeout_handle(union sigval timer_data) { +#include "cmplog.h" - pid_t child_pid = timer_data.sival_int; - if (child_pid > 0) kill(child_pid, SIGKILL); - -} +/* Execute target application, monitoring for timeouts. Return status + information. The called program will update afl->fsrv->trace_bits. */ -u8 run_target(afl_state_t *afl, u32 timeout) { +u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { s32 res; - int sret; - - fd_set readfds; - - static struct timeval it; - static u32 prev_timed_out = 0; + u32 exec_ms; int status = 0; u32 tb4; - afl->fsrv.child_timed_out = 0; + fsrv->child_timed_out = 0; - /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we + /* After this memset, fsrv->trace_bits[] are effectively volatile, so we must prevent any earlier operations from venturing into that territory. */ - memset(afl->fsrv.trace_bits, 0, MAP_SIZE); + memset(fsrv->trace_bits, 0, fsrv->map_size); MEM_BARRIER(); - + /* we have the fork server (or faux server) up and running, so simply tell it to have at it, and then read back PID. */ - if ((res = write(afl->fsrv.fsrv_ctl_fd, &prev_timed_out, 4)) != 4) { + if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) { if (afl->stop_soon) return 0; RPFATAL(res, "Unable to request new process from fork server (OOM?)"); } - if ((res = read(afl->fsrv.fsrv_st_fd, &afl->fsrv.child_pid, 4)) != 4) { + if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) { if (afl->stop_soon) return 0; RPFATAL(res, "Unable to request new process from fork server (OOM?)"); } - if (afl->fsrv.child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); + if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); - /* use select to monitor the forkserver for timeouts. */ + exec_ms = read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); - FD_ZERO(&readfds); - FD_SET(afl->fsrv.fsrv_st_fd, &readfds); - it.tv_sec = ((timeout) / 1000); - it.tv_usec = ((timeout) % 1000) * 1000; - - sret = select(afl->fsrv.fsrv_st_fd + 1, &readfds, NULL, NULL, &it); - - if (sret == 0) { + if (exec_ms > timeout) { /* If there was no response from forkserver after timeout seconds, we kill the child. The forkserver should inform us afterwards */ - kill(afl->fsrv.child_pid, SIGKILL); - afl->fsrv.child_timed_out = 1; + kill(fsrv->child_pid, SIGKILL); + fsrv->child_timed_out = 1; + if (read(fsrv->fsrv_st_fd, &status, 4) < 4) exec_ms = 0; } - if ((res = read(afl->fsrv.fsrv_st_fd, &status, 4)) != 4) { + if (!exec_ms) { if (afl->stop_soon) return 0; SAYF("\n" cLRD "[-] " cRST @@ -121,30 +105,30 @@ u8 run_target(afl_state_t *afl, u32 timeout) { "\n\n" "If all else fails you can disable the fork server via " "AFL_NO_FORKSRV=1.\n", - afl->fsrv.mem_limit); + fsrv->mem_limit); RPFATAL(res, "Unable to communicate with fork server"); } - if (!WIFSTOPPED(status)) afl->fsrv.child_pid = 0; + if (!WIFSTOPPED(status)) fsrv->child_pid = 0; ++afl->total_execs; - /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the - compiler below this point. Past this location, afl->fsrv.trace_bits[] + /* Any subsequent operations on fsrv->trace_bits must not be moved by the + compiler below this point. Past this location, fsrv->trace_bits[] behave very normally and do not have to be treated as volatile. */ MEM_BARRIER(); - tb4 = *(u32 *)afl->fsrv.trace_bits; + tb4 = *(u32 *)fsrv->trace_bits; #ifdef WORD_SIZE_64 - classify_counts((u64 *)afl->fsrv.trace_bits); + classify_counts(afl, (u64 *)fsrv->trace_bits); #else - classify_counts((u32 *)afl->fsrv.trace_bits); + classify_counts(afl, (u32 *)fsrv->trace_bits); #endif /* ^WORD_SIZE_64 */ - prev_timed_out = afl->fsrv.child_timed_out; + fsrv->prev_timed_out = fsrv->child_timed_out; /* Report outcome to caller. */ @@ -152,7 +136,7 @@ u8 run_target(afl_state_t *afl, u32 timeout) { afl->kill_signal = WTERMSIG(status); - if (afl->fsrv.child_timed_out && afl->kill_signal == SIGKILL) + if (fsrv->child_timed_out && afl->kill_signal == SIGKILL) return FAULT_TMOUT; return FAULT_CRASH; @@ -162,7 +146,7 @@ u8 run_target(afl_state_t *afl, u32 timeout) { /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and must use a special exit code. */ - if (afl->fsrv.uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { + if (fsrv->uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { afl->kill_signal = 0; return FAULT_CRASH; @@ -185,20 +169,16 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) { s32 fd = afl->fsrv.out_fd; #ifdef _AFL_DOCUMENT_MUTATIONS - s32 doc_fd; - char *fn = alloc_printf("%s/mutations/%09u:%s", afl->out_dir, + s32 doc_fd; + char fn[PATH_MAX]; + snprintf(fn, PATH_MAX, ("%s/mutations/%09u:%s", afl->out_dir, afl->document_counter++, describe_op(afl, 0)); - if (fn != NULL) { - - if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) { - - if (write(doc_fd, mem, len) != len) - PFATAL("write to mutation file failed: %s", fn); - close(doc_fd); - } + if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) { - ck_free(fn); + if (write(doc_fd, mem, len) != len) + PFATAL("write to mutation file failed: %s", fn); + close(doc_fd); } @@ -223,16 +203,22 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) { lseek(fd, 0, SEEK_SET); - if (afl->mutator && afl->mutator->afl_custom_pre_save) { + if (unlikely(afl->mutator && afl->mutator->afl_custom_pre_save)) { + + u8 *new_buf = NULL; + + size_t new_size = afl->mutator->afl_custom_pre_save(afl->mutator->data, mem, + len, &new_buf); + + if (unlikely(!new_buf)) + FATAL("Custom_pre_save failed (ret: %lu)", (long unsigned)new_size); - u8 * new_data; - size_t new_size = - afl->mutator->afl_custom_pre_save(afl, mem, len, &new_data); - ck_write(fd, new_data, new_size, afl->fsrv.out_file); - ck_free(new_data); + /* everything as planned. use the new data. */ + ck_write(fd, new_buf, new_size, afl->fsrv.out_file); } else { + /* boring uncustom. */ ck_write(fd, mem, len, afl->fsrv.out_file); } @@ -299,8 +285,6 @@ static void write_with_gap(afl_state_t *afl, void *mem, u32 len, u32 skip_at, u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, u32 handicap, u8 from_queue) { - static u8 first_trace[MAP_SIZE]; - u8 fault = 0, new_bits = 0, var_detected = 0, first_run = (q->exec_cksum == 0); @@ -326,12 +310,22 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, /* Make sure the forkserver is up before we do anything, and let's not count its spin-up time toward binary calibration. */ - if (!afl->fsrv.fsrv_pid) afl_fsrv_start(&afl->fsrv, afl->argv); - if (afl->dumb_mode != 1 && !afl->no_forkserver && !afl->cmplog_fsrv_pid && - afl->shm.cmplog_mode) - init_cmplog_forkserver(afl); + if (!afl->fsrv.fsrv_pid) { + + if (afl->fsrv.cmplog_binary && + afl->fsrv.init_child_func != cmplog_exec_child) { + + FATAL("BUG in afl-fuzz detected. Cmplog mode not set correctly."); + + } + + afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, + afl->afl_env.afl_debug_child_output); + + } - if (q->exec_cksum) memcpy(first_trace, afl->fsrv.trace_bits, MAP_SIZE); + if (q->exec_cksum) + memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); start_us = get_cur_time_us(); @@ -344,7 +338,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, write_to_testcase(afl, use_mem, q->len); - fault = run_target(afl, use_tmout); + fault = run_target(afl, &afl->fsrv, use_tmout); /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed, we want to bail out quickly. */ @@ -352,14 +346,14 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, if (afl->stop_soon || fault != afl->crash_mode) goto abort_calibration; if (!afl->dumb_mode && !afl->stage_cur && - !count_bytes(afl->fsrv.trace_bits)) { + !count_bytes(afl, afl->fsrv.trace_bits)) { fault = FAULT_NOINST; goto abort_calibration; } - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (q->exec_cksum != cksum) { @@ -370,23 +364,21 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, u32 i; - for (i = 0; i < MAP_SIZE; ++i) { - - if (!afl->var_bytes[i] && first_trace[i] != afl->fsrv.trace_bits[i]) { + for (i = 0; i < afl->fsrv.map_size; ++i) { + if (unlikely(!afl->var_bytes[i]) && + unlikely(afl->first_trace[i] != afl->fsrv.trace_bits[i])) afl->var_bytes[i] = 1; - afl->stage_max = CAL_CYCLES_LONG; - - } } var_detected = 1; + afl->stage_max = CAL_CYCLES_LONG; } else { q->exec_cksum = cksum; - memcpy(first_trace, afl->fsrv.trace_bits, MAP_SIZE); + memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); } @@ -403,7 +395,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, This is used for fuzzing air time calculations in calculate_score(). */ q->exec_us = (stop_us - start_us) / afl->stage_max; - q->bitmap_size = count_bytes(afl->fsrv.trace_bits); + q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits); q->handicap = handicap; q->cal_failed = 0; @@ -431,7 +423,7 @@ abort_calibration: if (var_detected) { - afl->var_byte_count = count_bytes(afl->var_bytes); + afl->var_byte_count = count_bytes(afl, afl->var_bytes); if (!q->var_behavior) { @@ -471,8 +463,6 @@ void sync_fuzzers(afl_state_t *afl) { while ((sd_ent = readdir(sd))) { - static u8 stage_tmp[128]; - DIR * qd; struct dirent *qd_ent; u8 * qd_path, *qd_synced_path; @@ -511,13 +501,14 @@ void sync_fuzzers(afl_state_t *afl) { /* Show stats */ - sprintf(stage_tmp, "sync %u", ++sync_cnt); - afl->stage_name = stage_tmp; + snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "sync %u", ++sync_cnt); + + afl->stage_name = afl->stage_name_buf; afl->stage_cur = 0; afl->stage_max = 0; - /* For every file queued by this fuzzer, parse ID and see if we have looked - at it before; exec a test case if not. */ + /* For every file queued by this fuzzer, parse ID and see if we have + looked at it before; exec a test case if not. */ while ((qd_ent = readdir(qd))) { @@ -564,7 +555,7 @@ void sync_fuzzers(afl_state_t *afl) { write_to_testcase(afl, mem, st.st_size); - fault = run_target(afl, afl->fsrv.exec_tmout); + fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); if (afl->stop_soon) goto close_sync; @@ -608,26 +599,25 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (afl->mutator && afl->mutator->afl_custom_trim) return trim_case_custom(afl, q, in_buf); - static u8 tmp[64]; - static u8 clean_trace[MAP_SIZE]; - u8 needs_write = 0, fault = 0; u32 trim_exec = 0; u32 remove_len; u32 len_p2; + u8 val_bufs[2][STRINGIFY_VAL_SIZE_MAX]; + /* Although the trimmer will be less useful when variable behavior is detected, it will still work to some extent, so we don't check for this. */ if (q->len < 5) return 0; - afl->stage_name = tmp; + afl->stage_name = afl->stage_name_buf; afl->bytes_trim_in += q->len; /* Select initial chunk len, starting with large steps. */ - len_p2 = next_p2(q->len); + len_p2 = next_pow2(q->len); remove_len = MAX(len_p2 / TRIM_START_STEPS, TRIM_MIN_BYTES); @@ -638,7 +628,9 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { u32 remove_pos = remove_len; - sprintf(tmp, "trim %s/%s", DI(remove_len), DI(remove_len)); + sprintf(afl->stage_name_buf, "trim %s/%s", + u_stringify_int(val_bufs[0], remove_len), + u_stringify_int(val_bufs[1], remove_len)); afl->stage_cur = 0; afl->stage_max = q->len / remove_len; @@ -650,14 +642,15 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail); - fault = run_target(afl, afl->fsrv.exec_tmout); + fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); ++afl->trim_execs; if (afl->stop_soon || fault == FAULT_ERROR) goto abort_trimming; - /* Note that we don't keep track of crashes or hangs here; maybe TODO? */ + /* Note that we don't keep track of crashes or hangs here; maybe TODO? + */ - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); /* If the deletion had no impact on the trace, make it permanent. This isn't perfect for variable-path inputs, but we're just making a @@ -669,7 +662,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { u32 move_tail = q->len - remove_pos - trim_avail; q->len -= trim_avail; - len_p2 = next_p2(q->len); + len_p2 = next_pow2(q->len); memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, move_tail); @@ -680,7 +673,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (!needs_write) { needs_write = 1; - memcpy(clean_trace, afl->fsrv.trace_bits, MAP_SIZE); + memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); } @@ -722,7 +715,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { ck_write(fd, in_buf, q->len, q->fname); close(fd); - memcpy(afl->fsrv.trace_bits, clean_trace, MAP_SIZE); + memcpy(afl->fsrv.trace_bits, afl->clean_trace, afl->fsrv.map_size); update_bitmap_score(afl, q); } @@ -744,14 +737,19 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { if (afl->post_handler) { - out_buf = afl->post_handler(out_buf, &len); - if (!out_buf || !len) return 0; + u8 *post_buf = NULL; + + size_t post_len = + afl->post_handler(afl->post_data, out_buf, len, &post_buf); + if (!post_buf || !post_len) return 0; + out_buf = post_buf; + len = post_len; } write_to_testcase(afl, out_buf, len); - fault = run_target(afl, afl->fsrv.exec_tmout); + fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); if (afl->stop_soon) return 1; diff --git a/src/afl-fuzz-globals.c b/src/afl-fuzz-state.c index efffa749..f58345fb 100644 --- a/src/afl-fuzz-globals.c +++ b/src/afl-fuzz-state.c @@ -30,10 +30,9 @@ 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", "fast", "coe", "lin", - "quad", "exploit", "mmopt"}; +char *power_names[POWER_SCHEDULES_NUM] = { -u8 *doc_path = NULL; /* gath to documentation dir */ + "explore", "fast", "coe", "lin", "quad", "exploit", "mmopt", "rare"}; /* Initialize MOpt "globals" for this afl state */ @@ -78,6 +77,10 @@ list_t afl_states = {.element_prealloc_count = 0}; void afl_state_init(afl_state_t *afl) { + /* thanks to this memset, growing vars like out_buf + and out_size are NULL/0 by default. */ + memset(afl, 0, sizeof(afl_state_t)); + afl->w_init = 0.9; afl->w_end = 0.3; afl->g_max = 5000; @@ -96,6 +99,10 @@ void afl_state_init(afl_state_t *afl) { afl->fsrv.use_stdin = 1; + afl->fsrv.map_size = MAP_SIZE; + afl->fsrv.function_opt = (u8 *)afl; + afl->fsrv.function_ptr = &maybe_add_auto; + afl->cal_cycles = CAL_CYCLES; afl->cal_cycles_long = CAL_CYCLES_LONG; @@ -114,6 +121,29 @@ void afl_state_init(afl_state_t *afl) { afl->fsrv.child_pid = -1; afl->fsrv.out_dir_fd = -1; + afl->cmplog_prev_timed_out = 0; + + /* statis file */ + afl->last_bitmap_cvg = 0; + afl->last_stability = 0; + afl->last_eps = 0; + + /* plot file saves from last run */ + afl->plot_prev_qp = 0; + afl->plot_prev_pf = 0; + afl->plot_prev_pnf = 0; + afl->plot_prev_ce = 0; + afl->plot_prev_md = 0; + afl->plot_prev_qc = 0; + afl->plot_prev_uc = 0; + afl->plot_prev_uh = 0; + + afl->stats_last_stats_ms = 0; + afl->stats_last_plot_ms = 0; + afl->stats_last_ms = 0; + afl->stats_last_execs = 0; + afl->stats_avg_exec = -1; + init_mopt_globals(afl); list_append(&afl_states, afl); @@ -254,6 +284,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_autoresume = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_CAL_FAST", + + afl_environment_variable_len)) { + + afl->afl_env.afl_cal_fast = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TMPDIR", afl_environment_variable_len)) { @@ -321,6 +358,17 @@ void read_afl_environment(afl_state_t *afl, char **envp) { void afl_state_deinit(afl_state_t *afl) { + if (afl->post_deinit) afl->post_deinit(afl->post_data); + if (afl->in_place_resume) ck_free(afl->in_dir); + if (afl->sync_id) ck_free(afl->out_dir); + + free(afl->out_buf); + free(afl->out_scratch_buf); + free(afl->eff_buf); + free(afl->in_buf); + free(afl->in_scratch_buf); + free(afl->ex_buf); + list_remove(&afl_states, afl); } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 63cca14d..2e680dbb 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -24,25 +24,27 @@ */ #include "afl-fuzz.h" +#include <limits.h> /* Update stats file for unattended monitoring. */ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, double eps) { - static double last_bcvg, last_stab, last_eps; - static struct rusage rus; + struct rusage rus; - u8 * fn = alloc_printf("%s/fuzzer_stats", afl->out_dir); - s32 fd; - FILE *f; + unsigned long long int cur_time = get_cur_time(); + u8 fn[PATH_MAX]; + s32 fd; + FILE * f; + uint32_t t_bytes = count_non_255_bytes(afl, afl->virgin_bits); + + snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) PFATAL("Unable to create '%s'", fn); - ck_free(fn); - f = fdopen(fd, "w"); if (!f) PFATAL("fdopen() failed"); @@ -52,15 +54,15 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, if (!bitmap_cvg && !stability && !eps) { - bitmap_cvg = last_bcvg; - stability = last_stab; - eps = last_eps; + bitmap_cvg = afl->last_bitmap_cvg; + stability = afl->last_stability; + eps = afl->last_eps; } else { - last_bcvg = bitmap_cvg; - last_stab = stability; - last_eps = eps; + afl->last_bitmap_cvg = bitmap_cvg; + afl->last_stability = stability; + afl->last_eps = eps; } @@ -70,8 +72,10 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, f, "start_time : %llu\n" "last_update : %llu\n" + "run_time : %llu\n" "fuzzer_pid : %d\n" "cycles_done : %llu\n" + "cycles_wo_finds : %llu\n" "execs_done : %llu\n" "execs_per_sec : %0.02f\n" // "real_execs_per_sec: %0.02f\n" // damn the name is too long @@ -93,17 +97,20 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, "last_hang : %llu\n" "execs_since_crash : %llu\n" "exec_timeout : %u\n" - "slowest_exec_ms : %llu\n" + "slowest_exec_ms : %u\n" "peak_rss_mb : %lu\n" + "edges_found : %u\n" + "var_byte_count : %u\n" "afl_banner : %s\n" "afl_version : " VERSION "\n" "target_mode : %s%s%s%s%s%s%s%s\n" "command_line : %s\n", - afl->start_time / 1000, get_cur_time() / 1000, getpid(), - afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->total_execs, - /*eps,*/ afl->total_execs / - ((double)(get_cur_time() - afl->start_time) / 1000), + afl->start_time / 1000, cur_time / 1000, + (cur_time - afl->start_time) / 1000, getpid(), + afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds, + afl->total_execs, + afl->total_execs / ((double)(get_cur_time() - afl->start_time) / 1000), afl->queued_paths, afl->queued_favored, afl->queued_discovered, afl->queued_imported, afl->max_depth, afl->current_entry, afl->pending_favored, afl->pending_not_fuzzed, afl->queued_variable, @@ -116,12 +123,13 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, #else (unsigned long int)(rus.ru_maxrss >> 10), #endif - afl->use_banner, afl->unicorn_mode ? "unicorn" : "", - afl->qemu_mode ? "qemu " : "", afl->dumb_mode ? " dumb " : "", - afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "", + t_bytes, afl->var_byte_count, afl->use_banner, + afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "", + afl->dumb_mode ? " dumb " : "", afl->no_forkserver ? "no_fsrv " : "", + afl->crash_mode ? "crash " : "", afl->persistent_mode ? "persistent " : "", afl->deferred_mode ? "deferred " : "", - (afl->unicorn_mode || afl->qemu_mode || afl->dumb_mode || + (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->dumb_mode || afl->no_forkserver || afl->crash_mode || afl->persistent_mode || afl->deferred_mode) ? "" @@ -137,23 +145,24 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) { - static u32 prev_qp, prev_pf, prev_pnf, prev_ce, prev_md; - static u64 prev_qc, prev_uc, prev_uh; - - if (prev_qp == afl->queued_paths && prev_pf == afl->pending_favored && - prev_pnf == afl->pending_not_fuzzed && prev_ce == afl->current_entry && - prev_qc == afl->queue_cycle && prev_uc == afl->unique_crashes && - prev_uh == afl->unique_hangs && prev_md == afl->max_depth) + if (afl->plot_prev_qp == afl->queued_paths && + afl->plot_prev_pf == afl->pending_favored && + afl->plot_prev_pnf == afl->pending_not_fuzzed && + afl->plot_prev_ce == afl->current_entry && + afl->plot_prev_qc == afl->queue_cycle && + afl->plot_prev_uc == afl->unique_crashes && + afl->plot_prev_uh == afl->unique_hangs && + afl->plot_prev_md == afl->max_depth) return; - prev_qp = afl->queued_paths; - prev_pf = afl->pending_favored; - prev_pnf = afl->pending_not_fuzzed; - prev_ce = afl->current_entry; - prev_qc = afl->queue_cycle; - prev_uc = afl->unique_crashes; - prev_uh = afl->unique_hangs; - prev_md = afl->max_depth; + afl->plot_prev_qp = afl->queued_paths; + afl->plot_prev_pf = afl->pending_favored; + afl->plot_prev_pnf = afl->pending_not_fuzzed; + afl->plot_prev_ce = afl->current_entry; + afl->plot_prev_qc = afl->queue_cycle; + afl->plot_prev_uc = afl->unique_crashes; + afl->plot_prev_uh = afl->unique_hangs; + afl->plot_prev_md = afl->max_depth; /* Fields in the file: @@ -192,21 +201,47 @@ static void check_term_size(afl_state_t *afl) { void show_stats(afl_state_t *afl) { - static u64 last_stats_ms, last_plot_ms, last_ms, last_execs; - static double avg_exec; - double t_byte_ratio, stab_ratio; + double t_byte_ratio, stab_ratio; u64 cur_ms; u32 t_bytes, t_bits; u32 banner_len, banner_pad; u8 tmp[256]; + u8 time_tmp[64]; + + u8 val_buf[8][STRINGIFY_VAL_SIZE_MAX]; +#define IB(i) (val_buf[(i)]) cur_ms = get_cur_time(); + if (afl->most_time_key) { + + if (afl->most_time * 1000 < cur_ms - afl->start_time) { + + afl->most_time_key = 2; + afl->stop_soon = 2; + + } + + } + + if (afl->most_execs_key == 1) { + + if (afl->most_execs <= afl->total_execs) { + + afl->most_execs_key = 2; + afl->stop_soon = 2; + + } + + } + /* If not enough time has passed since last UI update, bail out. */ - if (cur_ms - last_ms < 1000 / UI_TARGET_HZ && !afl->force_ui_update) return; + if (cur_ms - afl->stats_last_ms < 1000 / UI_TARGET_HZ && + !afl->force_ui_update) + return; /* Check if we're past the 10 minute mark. */ @@ -214,49 +249,51 @@ void show_stats(afl_state_t *afl) { /* Calculate smoothed exec speed stats. */ - if (!last_execs) { + if (!afl->stats_last_execs) { - avg_exec = ((double)afl->total_execs) * 1000 / (cur_ms - afl->start_time); + afl->stats_avg_exec = + ((double)afl->total_execs) * 1000 / (cur_ms - afl->start_time); } else { - double cur_avg = - ((double)(afl->total_execs - last_execs)) * 1000 / (cur_ms - last_ms); + double cur_avg = ((double)(afl->total_execs - afl->stats_last_execs)) * + 1000 / (cur_ms - afl->stats_last_ms); /* If there is a dramatic (5x+) jump in speed, reset the indicator more quickly. */ - if (cur_avg * 5 < avg_exec || cur_avg / 5 > avg_exec) avg_exec = cur_avg; + if (cur_avg * 5 < afl->stats_avg_exec || cur_avg / 5 > afl->stats_avg_exec) + afl->stats_avg_exec = cur_avg; - avg_exec = avg_exec * (1.0 - 1.0 / AVG_SMOOTHING) + - cur_avg * (1.0 / AVG_SMOOTHING); + afl->stats_avg_exec = afl->stats_avg_exec * (1.0 - 1.0 / AVG_SMOOTHING) + + cur_avg * (1.0 / AVG_SMOOTHING); } - last_ms = cur_ms; - last_execs = afl->total_execs; + afl->stats_last_ms = cur_ms; + afl->stats_last_execs = afl->total_execs; /* Tell the callers when to contact us (as measured in execs). */ - afl->stats_update_freq = avg_exec / (UI_TARGET_HZ * 10); + afl->stats_update_freq = afl->stats_avg_exec / (UI_TARGET_HZ * 10); if (!afl->stats_update_freq) afl->stats_update_freq = 1; /* Do some bitmap stats. */ - t_bytes = count_non_255_bytes(afl->virgin_bits); - t_byte_ratio = ((double)t_bytes * 100) / MAP_SIZE; + t_bytes = count_non_255_bytes(afl, afl->virgin_bits); + t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.map_size; - if (t_bytes) - stab_ratio = 100 - ((double)afl->var_byte_count) * 100 / t_bytes; + if (likely(t_bytes) && unlikely(afl->var_byte_count)) + stab_ratio = 100 - (((double)afl->var_byte_count * 100) / t_bytes); else stab_ratio = 100; /* Roughly every minute, update fuzzer stats and save auto tokens. */ - if (cur_ms - last_stats_ms > STATS_UPDATE_SEC * 1000) { + if (cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000) { - last_stats_ms = cur_ms; - write_stats_file(afl, t_byte_ratio, stab_ratio, avg_exec); + afl->stats_last_stats_ms = cur_ms; + write_stats_file(afl, t_byte_ratio, stab_ratio, afl->stats_avg_exec); save_auto(afl); write_bitmap(afl); @@ -264,10 +301,10 @@ void show_stats(afl_state_t *afl) { /* Every now and then, write plot data. */ - if (cur_ms - last_plot_ms > PLOT_UPDATE_SEC * 1000) { + if (cur_ms - afl->stats_last_plot_ms > PLOT_UPDATE_SEC * 1000) { - last_plot_ms = cur_ms; - maybe_update_plot_file(afl, t_byte_ratio, avg_exec); + afl->stats_last_plot_ms = cur_ms; + maybe_update_plot_file(afl, t_byte_ratio, afl->stats_avg_exec); } @@ -290,7 +327,7 @@ void show_stats(afl_state_t *afl) { /* Compute some mildly useful bitmap stats. */ - t_bits = (MAP_SIZE << 3) - count_bits(afl->virgin_bits); + t_bits = (afl->fsrv.map_size << 3) - count_bits(afl, afl->virgin_bits); /* Now, for the visuals... */ @@ -384,9 +421,10 @@ void show_stats(afl_state_t *afl) { } + u_stringify_time_diff(time_tmp, cur_ms, afl->start_time); SAYF(bV bSTOP " run time : " cRST "%-33s " bSTG bV bSTOP " cycles done : %s%-5s " bSTG bV "\n", - DTD(cur_ms, afl->start_time), tmp, DI(afl->queue_cycle - 1)); + time_tmp, tmp, u_stringify_int(IB(0), afl->queue_cycle - 1)); /* We want to warn people about not seeing new paths after a full cycle, except when resuming fuzzing or running in non-instrumented mode. */ @@ -395,8 +433,8 @@ void show_stats(afl_state_t *afl) { (afl->last_path_time || afl->resuming_fuzz || afl->queue_cycle == 1 || afl->in_bitmap || afl->crash_mode)) { - SAYF(bV bSTOP " last new path : " cRST "%-33s ", - DTD(cur_ms, afl->last_path_time)); + u_stringify_time_diff(time_tmp, cur_ms, afl->last_path_time); + SAYF(bV bSTOP " last new path : " cRST "%-33s ", time_tmp); } else { @@ -413,25 +451,26 @@ void show_stats(afl_state_t *afl) { } SAYF(bSTG bV bSTOP " total paths : " cRST "%-5s " bSTG bV "\n", - DI(afl->queued_paths)); + u_stringify_int(IB(0), afl->queued_paths)); /* Highlight crashes in red if found, denote going over the KEEP_UNIQUE_CRASH limit with a '+' appended to the count. */ - sprintf(tmp, "%s%s", DI(afl->unique_crashes), + sprintf(tmp, "%s%s", u_stringify_int(IB(0), afl->unique_crashes), (afl->unique_crashes >= KEEP_UNIQUE_CRASH) ? "+" : ""); + u_stringify_time_diff(time_tmp, cur_ms, afl->last_crash_time); SAYF(bV bSTOP " last uniq crash : " cRST "%-33s " bSTG bV bSTOP " uniq crashes : %s%-6s" bSTG bV "\n", - DTD(cur_ms, afl->last_crash_time), afl->unique_crashes ? cLRD : cRST, - tmp); + time_tmp, afl->unique_crashes ? cLRD : cRST, tmp); - sprintf(tmp, "%s%s", DI(afl->unique_hangs), + sprintf(tmp, "%s%s", u_stringify_int(IB(0), afl->unique_hangs), (afl->unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : ""); + u_stringify_time_diff(time_tmp, cur_ms, afl->last_hang_time); SAYF(bV bSTOP " last uniq hang : " cRST "%-33s " bSTG bV bSTOP " uniq hangs : " cRST "%-6s" bSTG bV "\n", - DTD(cur_ms, afl->last_hang_time), tmp); + time_tmp, tmp); SAYF(bVR bH bSTOP cCYA " cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA @@ -441,21 +480,22 @@ void show_stats(afl_state_t *afl) { together, but then cram them into a fixed-width field - so we need to put them in a temporary buffer first. */ - sprintf(tmp, "%s%s%u (%0.01f%%)", DI(afl->current_entry), + sprintf(tmp, "%s%s%u (%0.01f%%)", u_stringify_int(IB(0), afl->current_entry), afl->queue_cur->favored ? "." : "*", afl->queue_cur->fuzz_level, ((double)afl->current_entry * 100) / afl->queued_paths); SAYF(bV bSTOP " now processing : " cRST "%-16s " bSTG bV bSTOP, tmp); sprintf(tmp, "%0.02f%% / %0.02f%%", - ((double)afl->queue_cur->bitmap_size) * 100 / MAP_SIZE, t_byte_ratio); + ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.map_size, + t_byte_ratio); SAYF(" map density : %s%-21s" bSTG bV "\n", t_byte_ratio > 70 ? cLRD : ((t_bytes < 200 && !afl->dumb_mode) ? cPIN : cRST), tmp); - sprintf(tmp, "%s (%0.02f%%)", DI(afl->cur_skipped_paths), + sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->cur_skipped_paths), ((double)afl->cur_skipped_paths * 100) / afl->queued_paths); SAYF(bV bSTOP " paths timed out : " cRST "%-16s " bSTG bV, tmp); @@ -468,7 +508,7 @@ void show_stats(afl_state_t *afl) { " stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); - sprintf(tmp, "%s (%0.02f%%)", DI(afl->queued_favored), + sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_favored), ((double)afl->queued_favored) * 100 / afl->queued_paths); /* Yeah... it's still going on... halp? */ @@ -479,58 +519,61 @@ void show_stats(afl_state_t *afl) { if (!afl->stage_max) { - sprintf(tmp, "%s/-", DI(afl->stage_cur)); + sprintf(tmp, "%s/-", u_stringify_int(IB(0), afl->stage_cur)); } else { - sprintf(tmp, "%s/%s (%0.02f%%)", DI(afl->stage_cur), DI(afl->stage_max), + sprintf(tmp, "%s/%s (%0.02f%%)", u_stringify_int(IB(0), afl->stage_cur), + u_stringify_int(IB(1), afl->stage_max), ((double)afl->stage_cur) * 100 / afl->stage_max); } SAYF(bV bSTOP " stage execs : " cRST "%-21s" bSTG bV bSTOP, tmp); - sprintf(tmp, "%s (%0.02f%%)", DI(afl->queued_with_cov), + sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_with_cov), ((double)afl->queued_with_cov) * 100 / afl->queued_paths); SAYF(" new edges on : " cRST "%-22s" bSTG bV "\n", tmp); - sprintf(tmp, "%s (%s%s unique)", DI(afl->total_crashes), - DI(afl->unique_crashes), + sprintf(tmp, "%s (%s%s unique)", u_stringify_int(IB(0), afl->total_crashes), + u_stringify_int(IB(1), afl->unique_crashes), (afl->unique_crashes >= KEEP_UNIQUE_CRASH) ? "+" : ""); if (afl->crash_mode) { SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP " new crashes : %s%-22s" bSTG bV "\n", - DI(afl->total_execs), afl->unique_crashes ? cLRD : cRST, tmp); + u_stringify_int(IB(0), afl->total_execs), + afl->unique_crashes ? cLRD : cRST, tmp); } else { SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP " total crashes : %s%-22s" bSTG bV "\n", - DI(afl->total_execs), afl->unique_crashes ? cLRD : cRST, tmp); + u_stringify_int(IB(0), afl->total_execs), + afl->unique_crashes ? cLRD : cRST, tmp); } /* Show a warning about slow execution. */ - if (avg_exec < 100) { + if (afl->stats_avg_exec < 100) { - sprintf(tmp, "%s/sec (%s)", DF(avg_exec), - avg_exec < 20 ? "zzzz..." : "slow!"); + sprintf(tmp, "%s/sec (%s)", u_stringify_float(IB(0), afl->stats_avg_exec), + afl->stats_avg_exec < 20 ? "zzzz..." : "slow!"); SAYF(bV bSTOP " exec speed : " cLRD "%-20s ", tmp); } else { - sprintf(tmp, "%s/sec", DF(avg_exec)); + sprintf(tmp, "%s/sec", u_stringify_float(IB(0), afl->stats_avg_exec)); SAYF(bV bSTOP " exec speed : " cRST "%-20s ", tmp); } - sprintf(tmp, "%s (%s%s unique)", DI(afl->total_tmouts), - DI(afl->unique_tmouts), + sprintf(tmp, "%s (%s%s unique)", u_stringify_int(IB(0), afl->total_tmouts), + u_stringify_int(IB(1), afl->unique_tmouts), (afl->unique_hangs >= KEEP_UNIQUE_HANG) ? "+" : ""); SAYF(bSTG bV bSTOP " total tmouts : " cRST "%-22s" bSTG bV "\n", tmp); @@ -547,70 +590,81 @@ void show_stats(afl_state_t *afl) { } else { - sprintf( - tmp, "%s/%s, %s/%s, %s/%s", DI(afl->stage_finds[STAGE_FLIP1]), - DI(afl->stage_cycles[STAGE_FLIP1]), DI(afl->stage_finds[STAGE_FLIP2]), - DI(afl->stage_cycles[STAGE_FLIP2]), DI(afl->stage_finds[STAGE_FLIP4]), - DI(afl->stage_cycles[STAGE_FLIP4])); + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + u_stringify_int(IB(0), afl->stage_finds[STAGE_FLIP1]), + u_stringify_int(IB(1), afl->stage_cycles[STAGE_FLIP1]), + u_stringify_int(IB(2), afl->stage_finds[STAGE_FLIP2]), + u_stringify_int(IB(3), afl->stage_cycles[STAGE_FLIP2]), + u_stringify_int(IB(4), afl->stage_finds[STAGE_FLIP4]), + u_stringify_int(IB(5), afl->stage_cycles[STAGE_FLIP4])); } SAYF(bV bSTOP " bit flips : " cRST "%-36s " bSTG bV bSTOP " levels : " cRST "%-10s" bSTG bV "\n", - tmp, DI(afl->max_depth)); + tmp, u_stringify_int(IB(0), afl->max_depth)); if (!afl->skip_deterministic) - sprintf( - tmp, "%s/%s, %s/%s, %s/%s", DI(afl->stage_finds[STAGE_FLIP8]), - DI(afl->stage_cycles[STAGE_FLIP8]), DI(afl->stage_finds[STAGE_FLIP16]), - DI(afl->stage_cycles[STAGE_FLIP16]), DI(afl->stage_finds[STAGE_FLIP32]), - DI(afl->stage_cycles[STAGE_FLIP32])); + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + u_stringify_int(IB(0), afl->stage_finds[STAGE_FLIP8]), + u_stringify_int(IB(1), afl->stage_cycles[STAGE_FLIP8]), + u_stringify_int(IB(2), afl->stage_finds[STAGE_FLIP16]), + u_stringify_int(IB(3), afl->stage_cycles[STAGE_FLIP16]), + u_stringify_int(IB(4), afl->stage_finds[STAGE_FLIP32]), + u_stringify_int(IB(5), afl->stage_cycles[STAGE_FLIP32])); SAYF(bV bSTOP " byte flips : " cRST "%-36s " bSTG bV bSTOP " pending : " cRST "%-10s" bSTG bV "\n", - tmp, DI(afl->pending_not_fuzzed)); + tmp, u_stringify_int(IB(0), afl->pending_not_fuzzed)); if (!afl->skip_deterministic) - sprintf(tmp, "%s/%s, %s/%s, %s/%s", DI(afl->stage_finds[STAGE_ARITH8]), - DI(afl->stage_cycles[STAGE_ARITH8]), - DI(afl->stage_finds[STAGE_ARITH16]), - DI(afl->stage_cycles[STAGE_ARITH16]), - DI(afl->stage_finds[STAGE_ARITH32]), - DI(afl->stage_cycles[STAGE_ARITH32])); + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + u_stringify_int(IB(0), afl->stage_finds[STAGE_ARITH8]), + u_stringify_int(IB(1), afl->stage_cycles[STAGE_ARITH8]), + u_stringify_int(IB(2), afl->stage_finds[STAGE_ARITH16]), + u_stringify_int(IB(3), afl->stage_cycles[STAGE_ARITH16]), + u_stringify_int(IB(4), afl->stage_finds[STAGE_ARITH32]), + u_stringify_int(IB(5), afl->stage_cycles[STAGE_ARITH32])); SAYF(bV bSTOP " arithmetics : " cRST "%-36s " bSTG bV bSTOP " pend fav : " cRST "%-10s" bSTG bV "\n", - tmp, DI(afl->pending_favored)); + tmp, u_stringify_int(IB(0), afl->pending_favored)); if (!afl->skip_deterministic) - sprintf(tmp, "%s/%s, %s/%s, %s/%s", DI(afl->stage_finds[STAGE_INTEREST8]), - DI(afl->stage_cycles[STAGE_INTEREST8]), - DI(afl->stage_finds[STAGE_INTEREST16]), - DI(afl->stage_cycles[STAGE_INTEREST16]), - DI(afl->stage_finds[STAGE_INTEREST32]), - DI(afl->stage_cycles[STAGE_INTEREST32])); + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + u_stringify_int(IB(0), afl->stage_finds[STAGE_INTEREST8]), + u_stringify_int(IB(1), afl->stage_cycles[STAGE_INTEREST8]), + u_stringify_int(IB(2), afl->stage_finds[STAGE_INTEREST16]), + u_stringify_int(IB(3), afl->stage_cycles[STAGE_INTEREST16]), + u_stringify_int(IB(4), afl->stage_finds[STAGE_INTEREST32]), + u_stringify_int(IB(5), afl->stage_cycles[STAGE_INTEREST32])); SAYF(bV bSTOP " known ints : " cRST "%-36s " bSTG bV bSTOP " own finds : " cRST "%-10s" bSTG bV "\n", - tmp, DI(afl->queued_discovered)); + tmp, u_stringify_int(IB(0), afl->queued_discovered)); if (!afl->skip_deterministic) - sprintf(tmp, "%s/%s, %s/%s, %s/%s", DI(afl->stage_finds[STAGE_EXTRAS_UO]), - DI(afl->stage_cycles[STAGE_EXTRAS_UO]), - DI(afl->stage_finds[STAGE_EXTRAS_UI]), - DI(afl->stage_cycles[STAGE_EXTRAS_UI]), - DI(afl->stage_finds[STAGE_EXTRAS_AO]), - DI(afl->stage_cycles[STAGE_EXTRAS_AO])); + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + u_stringify_int(IB(0), afl->stage_finds[STAGE_EXTRAS_UO]), + u_stringify_int(IB(1), afl->stage_cycles[STAGE_EXTRAS_UO]), + u_stringify_int(IB(2), afl->stage_finds[STAGE_EXTRAS_UI]), + u_stringify_int(IB(3), afl->stage_cycles[STAGE_EXTRAS_UI]), + u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]), + u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO])); SAYF(bV bSTOP " dictionary : " cRST "%-36s " bSTG bV bSTOP " imported : " cRST "%-10s" bSTG bV "\n", - tmp, afl->sync_id ? DI(afl->queued_imported) : (u8 *)"n/a"); - - sprintf( - tmp, "%s/%s, %s/%s, %s/%s", DI(afl->stage_finds[STAGE_HAVOC]), - DI(afl->stage_cycles[STAGE_HAVOC]), DI(afl->stage_finds[STAGE_SPLICE]), - DI(afl->stage_cycles[STAGE_SPLICE]), DI(afl->stage_finds[STAGE_RADAMSA]), - DI(afl->stage_cycles[STAGE_RADAMSA])); + tmp, + afl->sync_id ? u_stringify_int(IB(0), afl->queued_imported) + : (u8 *)"n/a"); + + sprintf(tmp, "%s/%s, %s/%s, %s/%s", + u_stringify_int(IB(0), afl->stage_finds[STAGE_HAVOC]), + u_stringify_int(IB(2), afl->stage_cycles[STAGE_HAVOC]), + u_stringify_int(IB(3), afl->stage_finds[STAGE_SPLICE]), + u_stringify_int(IB(4), afl->stage_cycles[STAGE_SPLICE]), + u_stringify_int(IB(5), afl->stage_finds[STAGE_RADAMSA]), + u_stringify_int(IB(6), afl->stage_cycles[STAGE_RADAMSA])); SAYF(bV bSTOP " havoc/rad : " cRST "%-36s " bSTG bV bSTOP, tmp); @@ -631,23 +685,25 @@ void show_stats(afl_state_t *afl) { if (afl->shm.cmplog_mode) { sprintf(tmp, "%s/%s, %s/%s, %s/%s, %s/%s", - DI(afl->stage_finds[STAGE_PYTHON]), - DI(afl->stage_cycles[STAGE_PYTHON]), - DI(afl->stage_finds[STAGE_CUSTOM_MUTATOR]), - DI(afl->stage_cycles[STAGE_CUSTOM_MUTATOR]), - DI(afl->stage_finds[STAGE_COLORIZATION]), - DI(afl->stage_cycles[STAGE_COLORIZATION]), - DI(afl->stage_finds[STAGE_ITS]), DI(afl->stage_cycles[STAGE_ITS])); + u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]), + u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]), + u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR]), + u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR]), + u_stringify_int(IB(4), afl->stage_finds[STAGE_COLORIZATION]), + u_stringify_int(IB(5), afl->stage_cycles[STAGE_COLORIZATION]), + u_stringify_int(IB(6), afl->stage_finds[STAGE_ITS]), + u_stringify_int(IB(7), afl->stage_cycles[STAGE_ITS])); SAYF(bV bSTOP " custom/rq : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n", tmp); } else { - sprintf(tmp, "%s/%s, %s/%s", DI(afl->stage_finds[STAGE_PYTHON]), - DI(afl->stage_cycles[STAGE_PYTHON]), - DI(afl->stage_finds[STAGE_CUSTOM_MUTATOR]), - DI(afl->stage_cycles[STAGE_CUSTOM_MUTATOR])); + sprintf(tmp, "%s/%s, %s/%s", + u_stringify_int(IB(0), afl->stage_finds[STAGE_PYTHON]), + u_stringify_int(IB(1), afl->stage_cycles[STAGE_PYTHON]), + u_stringify_int(IB(2), afl->stage_finds[STAGE_CUSTOM_MUTATOR]), + u_stringify_int(IB(3), afl->stage_cycles[STAGE_CUSTOM_MUTATOR])); SAYF(bV bSTOP " py/custom : " cRST "%-36s " bSTG bVR bH20 bH2 bH bRB "\n", tmp); @@ -663,7 +719,7 @@ void show_stats(afl_state_t *afl) { sprintf(tmp, "%0.02f%%/%s, ", ((double)(afl->bytes_trim_in - afl->bytes_trim_out)) * 100 / afl->bytes_trim_in, - DI(afl->trim_execs)); + u_stringify_int(IB(0), afl->trim_execs)); } @@ -688,8 +744,9 @@ void show_stats(afl_state_t *afl) { if (afl->mutator) { - sprintf(tmp, "%s/%s", DI(afl->stage_finds[STAGE_CUSTOM_MUTATOR]), - DI(afl->stage_cycles[STAGE_CUSTOM_MUTATOR])); + sprintf(tmp, "%s/%s", + u_stringify_int(IB(0), afl->stage_finds[STAGE_CUSTOM_MUTATOR]), + u_stringify_int(IB(1), afl->stage_cycles[STAGE_CUSTOM_MUTATOR])); SAYF(bV bSTOP " custom mut. : " cRST "%-36s " bSTG bV RESET_G1, tmp); } else { @@ -702,6 +759,8 @@ void show_stats(afl_state_t *afl) { if (afl->cpu_core_count) { + char *spacing = SP10, snap[24] = " " cLGN "snapshot" cRST " "; + double cur_runnable = get_runnable_processes(); u32 cur_utilization = cur_runnable * 100 / afl->cpu_core_count; @@ -716,23 +775,25 @@ void show_stats(afl_state_t *afl) { if (!afl->no_cpu_meter_red && cur_utilization >= 150) cpu_color = cLRD; + if (afl->fsrv.snapshot) spacing = snap; + #ifdef HAVE_AFFINITY if (afl->cpu_aff >= 0) { - SAYF(SP10 cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, MIN(afl->cpu_aff, 999), - cpu_color, MIN(cur_utilization, 999)); + SAYF("%s" cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, spacing, + MIN(afl->cpu_aff, 999), cpu_color, MIN(cur_utilization, 999)); } else { - SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color, + SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color, MIN(cur_utilization, 999)); } #else - SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color, + SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color, MIN(cur_utilization, 999)); #endif /* ^HAVE_AFFINITY */ @@ -744,6 +805,8 @@ void show_stats(afl_state_t *afl) { /* Last line */ SAYF(SET_G1 "\n" bSTG bLB bH30 bH20 bH2 bRB bSTOP cRST RESET_G1); +#undef IB + /* Hallelujah! */ fflush(0); @@ -762,6 +825,9 @@ void show_init_stats(afl_state_t *afl) { u64 avg_us = 0; u32 max_len = 0; + u8 val_bufs[4][STRINGIFY_VAL_SIZE_MAX]; +#define IB(i) val_bufs[(i)], sizeof(val_bufs[(i)]) + if (afl->total_cal_cycles) avg_us = afl->total_cal_us / afl->total_cal_cycles; while (q) { @@ -780,7 +846,7 @@ void show_init_stats(afl_state_t *afl) { SAYF("\n"); - if (avg_us > ((afl->qemu_mode || afl->unicorn_mode) ? 50000 : 10000)) + if (avg_us > ((afl->fsrv.qemu_mode || afl->unicorn_mode) ? 50000 : 10000)) WARNF(cLRD "The target binary is pretty slow! See %s/perf_tips.md.", doc_path); @@ -797,10 +863,10 @@ void show_init_stats(afl_state_t *afl) { if (max_len > 50 * 1024) WARNF(cLRD "Some test cases are huge (%s) - see %s/perf_tips.md!", - DMS(max_len), doc_path); + stringify_mem_size(IB(0), max_len), doc_path); else if (max_len > 10 * 1024) - WARNF("Some test cases are big (%s) - see %s/perf_tips.md.", DMS(max_len), - doc_path); + WARNF("Some test cases are big (%s) - see %s/perf_tips.md.", + stringify_mem_size(IB(0), max_len), doc_path); if (afl->useless_at_start && !afl->in_bitmap) WARNF(cLRD "Some test cases look useless. Consider using a smaller set."); @@ -824,7 +890,8 @@ void show_init_stats(afl_state_t *afl) { max_bits, ((double)afl->total_bitmap_size) / (afl->total_bitmap_entries ? afl->total_bitmap_entries : 1), - DI(min_us), DI(max_us), DI(avg_us)); + stringify_int(IB(0), min_us), stringify_int(IB(1), max_us), + stringify_int(IB(2), avg_us)); if (!afl->timeout_given) { @@ -868,6 +935,7 @@ void show_init_stats(afl_state_t *afl) { afl->hang_tmout = MIN(EXEC_TIMEOUT, afl->fsrv.exec_tmout * 2 + 100); OKF("All set and ready to roll!"); +#undef IB } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index b89bccb4..2320be5a 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -24,8 +24,7 @@ */ #include "afl-fuzz.h" - -u8 be_quiet = 0; +#include "cmplog.h" static u8 *get_libradamsa_path(u8 *own_loc) { @@ -96,8 +95,8 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { "Execution control settings:\n" " -p schedule - power schedules recompute a seed's performance " "score.\n" - " <explore (default), fast, coe, lin, quad, exploit, " - "mmopt>\n" + " <explore(default), fast, coe, lin, quad, exploit, " + "mmopt, rare>\n" " see docs/power_schedules.md\n" " -f file - location read by the fuzzed program (stdin)\n" " -t msec - timeout for each run (auto-scaled, 50-%d ms)\n" @@ -130,12 +129,11 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { "Testing settings:\n" " -s seed - use a fixed seed for the RNG\n" - " -V seconds - fuzz for a maximum total time of seconds then " - "terminate\n" - " -E execs - fuzz for a maximum number of total executions then " + " -V seconds - fuzz for a specific time then terminate\n" + " -E execs - fuzz for a approx. no of total executions then " "terminate\n" - " Note: -V/-E are not precise, they are checked after a queue entry " - "is done\n which can be many minutes/execs later\n\n" + " Note: not precise and can have several more " + "executions.\n\n" "Other stuff:\n" " -T text - text banner to show on the screen\n" @@ -145,7 +143,7 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { " -B bitmap.txt - mutate a specific test case, use the out/fuzz_bitmap " "file\n" " -C - crash exploration mode (the peruvian rabbit thing)\n" - " -e ext - File extension for the temporarily generated test " + " -e ext - file extension for the temporarily generated test " "case\n\n", argv0, EXEC_TIMEOUT, MEM_LIMIT); @@ -167,6 +165,7 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n" "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" + "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n" "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" @@ -199,6 +198,8 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { #ifdef USE_PYTHON SAYF("Compiled with %s module support, see docs/custom_mutator.md\n", (char *)PYTHON_VERSION); +#else + SAYF("Compiled without python module support\n"); #endif SAYF("For additional help please consult %s/README.md\n\n", doc_path); @@ -212,6 +213,8 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { static int stricmp(char const *a, char const *b) { + if (!a || !b) FATAL("Null reference"); + for (;; ++a, ++b) { int d; @@ -230,8 +233,7 @@ int main(int argc, char **argv_orig, char **envp) { u64 prev_queued = 0; u32 sync_interval_cnt = 0, seek_to, show_help = 0; u8 * extras_dir = 0; - u8 mem_limit_given = 0; - u8 exit_1 = !!get_afl_env("AFL_BENCH_JUST_ONE"); + u8 mem_limit_given = 0, exit_1 = 0; char **use_argv; struct timeval tv; @@ -245,12 +247,14 @@ int main(int argc, char **argv_orig, char **envp) { afl_state_init(afl); afl_fsrv_init(&afl->fsrv); + if (get_afl_env("AFL_DEBUG")) afl->debug = 1; read_afl_environment(afl, envp); + exit_1 = !!afl->afl_env.afl_bench_just_one; SAYF(cCYA "afl-fuzz" VERSION cRST " based on afl by Michal Zalewski and a big online community\n"); - doc_path = access(DOC_PATH, F_OK) ? (u8 *)"docs" : doc_path; + doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH; gettimeofday(&tv, &tz); afl->init_seed = tv.tv_sec ^ tv.tv_usec ^ getpid(); @@ -304,6 +308,10 @@ int main(int argc, char **argv_orig, char **envp) { afl->schedule = MMOPT; + } else if (!stricmp(optarg, "rare")) { + + afl->schedule = RARE; + } else if (!stricmp(optarg, "explore") || !stricmp(optarg, "default") || !stricmp(optarg, "normal") || !stricmp(optarg, "afl")) { @@ -493,8 +501,8 @@ int main(int argc, char **argv_orig, char **envp) { case 'Q': /* QEMU mode */ - if (afl->qemu_mode) FATAL("Multiple -Q options not supported"); - afl->qemu_mode = 1; + if (afl->fsrv.qemu_mode) FATAL("Multiple -Q options not supported"); + afl->fsrv.qemu_mode = 1; if (!mem_limit_given) afl->fsrv.mem_limit = MEM_LIMIT_QEMU; @@ -519,7 +527,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'W': /* Wine+QEMU mode */ if (afl->use_wine) FATAL("Multiple -W options not supported"); - afl->qemu_mode = 1; + afl->fsrv.qemu_mode = 1; afl->use_wine = 1; if (!mem_limit_given) afl->fsrv.mem_limit = 0; @@ -682,13 +690,14 @@ int main(int argc, char **argv_orig, char **envp) { OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL"); if (afl->sync_id && afl->force_deterministic && - getenv("AFL_CUSTOM_MUTATOR_ONLY")) + afl->afl_env.afl_custom_mutator_only) WARNF( "Using -M master with the AFL_CUSTOM_MUTATOR_ONLY mutator options will " "result in no deterministic mutations being done!"); if (afl->fixed_seed) OKF("Running with fixed seed: %u", (u32)afl->init_seed); srandom((u32)afl->init_seed); + srand((u32)afl->init_seed); // in case it is a different implementation if (afl->use_radamsa) { @@ -719,6 +728,16 @@ int main(int argc, char **argv_orig, char **envp) { } +#if defined(__SANITIZE_ADDRESS__) + if (afl->fsrv.mem_limit) { + + WARNF("in the ASAN build we disable all memory limits"); + afl->fsrv.mem_limit = 0; + + } + +#endif + setup_signal_handlers(); check_asan_opts(); @@ -732,7 +751,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->dumb_mode) { if (afl->crash_mode) FATAL("-C and -n are mutually exclusive"); - if (afl->qemu_mode) FATAL("-Q and -n are mutually exclusive"); + if (afl->fsrv.qemu_mode) FATAL("-Q and -n are mutually exclusive"); if (afl->unicorn_mode) FATAL("-U and -n are mutually exclusive"); } @@ -760,8 +779,9 @@ int main(int argc, char **argv_orig, char **envp) { case LIN: OKF("Using linear power schedule (LIN)"); break; case QUAD: OKF("Using quadratic power schedule (QUAD)"); break; case MMOPT: OKF("Using modified MOpt power schedule (MMOPT)"); break; + case RARE: OKF("Using rare edge focus power schedule (RARE)"); break; case EXPLORE: - OKF("Using exploration-based constant power schedule (EXPLORE)"); + OKF("Using exploration-based constant power schedule (EXPLORE, default)"); break; default: FATAL("Unknown power schedule"); break; @@ -799,7 +819,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->afl_env.afl_preload) { - if (afl->qemu_mode) { + if (afl->fsrv.qemu_mode) { u8 *qemu_preload = getenv("QEMU_SET_ENV"); u8 *afl_preload = getenv("AFL_PRELOAD"); @@ -845,7 +865,7 @@ int main(int argc, char **argv_orig, char **envp) { check_if_tty(afl); if (afl->afl_env.afl_force_ui) afl->not_on_tty = 0; - if (get_afl_env("AFL_CAL_FAST")) { + if (afl->afl_env.afl_cal_fast) { /* Use less calibration cycles, for slow applications */ afl->cal_cycles = 3; @@ -853,8 +873,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (get_afl_env("AFL_DEBUG")) afl->debug = 1; - if (afl->afl_env.afl_custom_mutator_only) { /* This ensures we don't proceed to havoc/splice */ @@ -902,21 +920,21 @@ int main(int argc, char **argv_orig, char **envp) { if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL && !afl->in_place_resume) { - char tmpfile[afl->file_extension ? strlen(afl->tmp_dir) + 1 + 10 + 1 + - strlen(afl->file_extension) + 1 - : strlen(afl->tmp_dir) + 1 + 10 + 1]; + char tmpfile[PATH_MAX]; + if (afl->file_extension) { - sprintf(tmpfile, "%s/.cur_input.%s", afl->tmp_dir, afl->file_extension); + snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir, + afl->file_extension); } else { - sprintf(tmpfile, "%s/.cur_input", afl->tmp_dir); + snprintf(tmpfile, PATH_MAX, "%s/.cur_input", afl->tmp_dir); } - if (access(tmpfile, F_OK) != - -1) // there is still a race condition here, but well ... + /* there is still a race condition here, but well ... */ + if (access(tmpfile, F_OK) != -1) FATAL( "AFL_TMPDIR already has an existing temporary input file: %s - if " "this is not from another instance, then just remove the file.", @@ -968,7 +986,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->unicorn_mode) FATAL("CmpLog and Unicorn mode are not compatible at the moment, sorry"); - if (!afl->qemu_mode) check_binary(afl, afl->cmplog_binary); + if (!afl->fsrv.qemu_mode) check_binary(afl, afl->cmplog_binary); } @@ -976,7 +994,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->start_time = get_cur_time(); - if (afl->qemu_mode) { + if (afl->fsrv.qemu_mode) { if (afl->use_wine) use_argv = get_wine_argv(argv[0], &afl->fsrv.target_path, argc - optind, @@ -992,6 +1010,21 @@ int main(int argc, char **argv_orig, char **envp) { } afl->argv = use_argv; + + if (afl->cmplog_binary) { + + ACTF("Spawning cmplog forkserver"); + afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv); + // TODO: this is semi-nice + afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits; + afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode; + afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary; + afl->cmplog_fsrv.init_child_func = cmplog_exec_child; + afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, + afl->afl_env.afl_debug_child_output); + + } + perform_dry_run(afl); cull_queue(afl); @@ -1040,9 +1073,9 @@ int main(int argc, char **argv_orig, char **envp) { } - show_stats(afl); + // show_stats(afl); - if (afl->not_on_tty) { + if (unlikely(afl->not_on_tty)) { ACTF("Entering queue cycle %llu.", afl->queue_cycle); fflush(stdout); @@ -1086,64 +1119,15 @@ int main(int argc, char **argv_orig, char **envp) { afl->queue_cur = afl->queue_cur->next; ++afl->current_entry; - if (afl->most_time_key == 1) { - - u64 cur_ms_lv = get_cur_time(); - if (afl->most_time * 1000 < cur_ms_lv - afl->start_time) { - - afl->most_time_key = 2; - afl->stop_soon = 2; - break; - - } - - } - - if (afl->most_execs_key == 1) { - - if (afl->most_execs <= afl->total_execs) { - - afl->most_execs_key = 2; - afl->stop_soon = 2; - break; - - } - - } - - } - - if (afl->queue_cur) show_stats(afl); - - /* - * ATTENTION - the following 10 lines were copied from a PR to Google's afl - * repository - and slightly fixed. - * These lines have nothing to do with the purpose of original PR though. - * Looks like when an exit condition was completed (AFL_BENCH_JUST_ONE, - * AFL_EXIT_WHEN_DONE or AFL_BENCH_UNTIL_CRASH) the child and forkserver - * where not killed? - */ - /* if we stopped programmatically, we kill the forkserver and the current - runner. if we stopped manually, this is done by the signal handler */ - if (afl->stop_soon == 2) { - - if (afl->fsrv.child_pid > 0) kill(afl->fsrv.child_pid, SIGKILL); - if (afl->fsrv.fsrv_pid > 0) kill(afl->fsrv.fsrv_pid, SIGKILL); - if (afl->cmplog_child_pid > 0) kill(afl->cmplog_child_pid, SIGKILL); - if (afl->cmplog_fsrv_pid > 0) kill(afl->cmplog_fsrv_pid, SIGKILL); - /* Now that we've killed the forkserver, we wait for it to be able to get - * rusage stats. */ - if (waitpid(afl->fsrv.fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); } - } write_bitmap(afl); - write_stats_file(afl, 0, 0, 0); maybe_update_plot_file(afl, 0, 0); save_auto(afl); stop_fuzzing: + write_stats_file(afl, 0, 0, 0); afl->force_ui_update = 1; // ensure the screen is reprinted show_stats(afl); // print the screen one last time @@ -1177,6 +1161,7 @@ stop_fuzzing: ck_free(afl->fsrv.target_path); ck_free(afl->fsrv.out_file); ck_free(afl->sync_id); + afl_state_deinit(afl); free(afl); /* not tracked */ argv_cpy_free(argv); diff --git a/src/afl-gcc.c b/src/afl-gcc.c index b0153b49..32cd36cb 100644 --- a/src/afl-gcc.c +++ b/src/afl-gcc.c @@ -142,12 +142,12 @@ static void edit_params(u32 argc, char **argv) { if (!strcmp(name, "afl-clang++")) { u8 *alt_cxx = getenv("AFL_CXX"); - cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"clang++"; + cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"clang++"; } else { u8 *alt_cc = getenv("AFL_CC"); - cc_params[0] = alt_cc ? alt_cc : (u8 *)"clang"; + cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"clang"; } @@ -187,17 +187,17 @@ static void edit_params(u32 argc, char **argv) { if (!strcmp(name, "afl-g++")) { u8 *alt_cxx = getenv("AFL_CXX"); - cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"g++"; + cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"g++"; } else if (!strcmp(name, "afl-gcj")) { u8 *alt_cc = getenv("AFL_GCJ"); - cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcj"; + cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcj"; } else { u8 *alt_cc = getenv("AFL_CC"); - cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcc"; + cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcc"; } diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c index 70ed4dbc..6c2fa147 100644 --- a/src/afl-gotcpu.c +++ b/src/afl-gotcpu.c @@ -90,7 +90,7 @@ static u64 get_cpu_usage_us(void) { static u32 measure_preemption(u32 target_ms) { - static volatile u32 v1, v2; + volatile u32 v1, v2 = 0; u64 st_t, en_t, st_c, en_c, real_delta, slice_delta; s32 loop_repeats = 0; diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c index 7bdf8d03..9db84e77 100644 --- a/src/afl-sharedmem.c +++ b/src/afl-sharedmem.c @@ -95,7 +95,7 @@ void afl_shm_deinit(sharedmem_t *shm) { /* At exit, remove all leftover maps */ -void afl_shm_atexit() { +void afl_shm_atexit(void) { LIST_FOREACH(&shm_list, sharedmem_t, { afl_shm_deinit(el); }); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 0051bbec..c84fa36c 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -59,13 +59,10 @@ #include <sys/types.h> #include <sys/resource.h> -u8 be_quiet; - char *stdin_file; /* stdin file */ u8 *in_dir, /* input folder */ - *doc_path, /* Path to docs */ - *at_file = NULL; /* Substitution string for @@ */ + *at_file = NULL; /* Substitution string for @@ */ static u8 *in_data; /* Input data */ @@ -84,8 +81,6 @@ u8 quiet_mode, /* Hide non-essential messages? */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ -static u8 qemu_mode; - /* Classify tuple counts. Instead of mapping to individual bits, as in afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */ @@ -157,7 +152,8 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { if (!strncmp(outfile, "/dev/", 5)) { - fd = open(outfile, O_WRONLY, 0600); + fd = open(outfile, O_WRONLY); + if (fd < 0) PFATAL("Unable to open '%s'", fsrv->out_file); } else if (!strcmp(outfile, "-")) { @@ -224,26 +220,6 @@ static u32 write_results(afl_forkserver_t *fsrv) { } -/* Write output file. */ - -static s32 write_to_file(u8 *path, u8 *mem, u32 len) { - - s32 ret; - - unlink(path); /* Ignore errors */ - - ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600); - - if (ret < 0) PFATAL("Unable to create '%s'", path); - - ck_write(ret, mem, len, path); - - lseek(ret, 0, SEEK_SET); - - return ret; - -} - /* Write modified data to file for testing. If use_stdin is clear, the old file is unlinked and a new one is created. Otherwise, out_fd is rewound and truncated. */ @@ -263,9 +239,8 @@ static void write_to_testcase(afl_forkserver_t *fsrv, void *mem, u32 len) { static u8 run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len) { - static struct itimerval it; - static u32 prev_timed_out = 0; - int status = 0; + struct itimerval it; + int status = 0; memset(fsrv->trace_bits, 0, MAP_SIZE); MEM_BARRIER(); @@ -277,7 +252,7 @@ static u8 run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem, /* we have the fork server up and running, so simply tell it to have at it, and then read back PID. */ - if ((res = write(fsrv->fsrv_ctl_fd, &prev_timed_out, 4)) != 4) { + if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) { if (stop_soon) return 0; RPFATAL(res, "Unable to request new process from fork server (OOM?)"); @@ -505,7 +480,7 @@ static void handle_stop_sig(int sig) { /* Do basic preparations - persistent fds, filenames, etc. */ -static void set_up_environment(void) { +static void set_up_environment(afl_forkserver_t *fsrv) { setenv("ASAN_OPTIONS", "abort_on_error=1:" @@ -522,7 +497,7 @@ static void set_up_environment(void) { if (get_afl_env("AFL_PRELOAD")) { - if (qemu_mode) { + if (fsrv->qemu_mode) { u8 *qemu_preload = getenv("QEMU_SET_ENV"); u8 *afl_preload = getenv("AFL_PRELOAD"); @@ -579,11 +554,6 @@ static void setup_signal_handlers(void) { sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); - /* Exec timeout notifications. */ - - sa.sa_handler = handle_timeout; - sigaction(SIGALRM, &sa, NULL); - } /* Show banner. */ @@ -826,10 +796,10 @@ int main(int argc, char **argv_orig, char **envp) { case 'Q': - if (qemu_mode) FATAL("Multiple -Q options not supported"); + if (fsrv->qemu_mode) FATAL("Multiple -Q options not supported"); if (!mem_limit_given) fsrv->mem_limit = MEM_LIMIT_QEMU; - qemu_mode = 1; + fsrv->qemu_mode = 1; break; case 'U': @@ -843,7 +813,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'W': /* Wine+QEMU mode */ if (use_wine) FATAL("Multiple -W options not supported"); - qemu_mode = 1; + fsrv->qemu_mode = 1; use_wine = 1; if (!mem_limit_given) fsrv->mem_limit = 0; @@ -888,7 +858,7 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->trace_bits = afl_shm_init(&shm, MAP_SIZE, 0); setup_signal_handlers(); - set_up_environment(); + set_up_environment(fsrv); find_binary(fsrv, argv[optind]); @@ -913,7 +883,7 @@ int main(int argc, char **argv_orig, char **envp) { for (i = optind; i < argc; i++) if (strcmp(argv[i], "@@") == 0) arg_offset = i; - if (qemu_mode) { + if (fsrv->qemu_mode) { if (use_wine) use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind, @@ -979,7 +949,8 @@ int main(int argc, char **argv_orig, char **envp) { } - afl_fsrv_start(fsrv, use_argv); + afl_fsrv_start(fsrv, use_argv, &stop_soon, + get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); while (done == 0 && (dir_ent = readdir(dir_in))) { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 17e9af5a..3be6b2c0 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -61,8 +61,7 @@ static u8 *mask_bitmap; /* Mask for trace bits (-B) */ u8 *in_file, /* Minimizer input test case */ - *output_file, /* Minimizer output file */ - *doc_path; /* Path to docs */ + *output_file; /* Minimizer output file */ static u8 *in_data; /* Input data for trimming */ @@ -77,13 +76,10 @@ u8 crash_mode, /* Crash-centric mode? */ hang_mode, /* Minimize as long as it hangs */ exit_crash, /* Treat non-zero exit as crash? */ edges_only, /* Ignore hit counts? */ - exact_mode, /* Require path match for crashes? */ - be_quiet; + exact_mode; /* Require path match for crashes? */ static volatile u8 stop_soon; /* Ctrl-C pressed? */ -static u8 qemu_mode; - /* * forkserver section */ @@ -247,166 +243,20 @@ static void write_to_testcase(afl_forkserver_t *fsrv, void *mem, u32 len) { } -/* Handle timeout signal. */ -/* -static void handle_timeout(int sig) { - - if (child_pid > 0) { - - child_timed_out = 1; - kill(child_pid, SIGKILL); - - } else if (child_pid == -1 && forksrv_pid > 0) { - - child_timed_out = 1; - kill(forksrv_pid, SIGKILL); - - } - -} - -*/ - -/* start the app and it's forkserver */ -/* -static void init_forkserver(char **argv) { - - static struct itimerval it; - int st_pipe[2], ctl_pipe[2]; - int status = 0; - s32 rlen; - - ACTF("Spinning up the fork server..."); - if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); - - forksrv_pid = fork(); - - if (forksrv_pid < 0) PFATAL("fork() failed"); - - if (!forksrv_pid) { - - struct rlimit r; - - if (dup2(use_stdin ? out_fd : dev_null_fd, 0) < 0 || - dup2(dev_null_fd, 1) < 0 || - dup2(dev_null_fd, 2) < 0) { - - *(u32*)trace_bits = EXEC_FAIL_SIG; - PFATAL("dup2() failed"); - - } - - close(dev_null_fd); - close(out_fd); - - setsid(); - - if (mem_limit) { - - r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; - -#ifdef RLIMIT_AS - - setrlimit(RLIMIT_AS, &r); // Ignore errors - -#else - - setrlimit(RLIMIT_DATA, &r); // Ignore errors - -#endif // ^RLIMIT_AS - - } - - r.rlim_max = r.rlim_cur = 0; - setrlimit(RLIMIT_CORE, &r); // Ignore errors - - // Set up control and status pipes, close the unneeded original fds. - - if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed"); - if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed"); - - close(ctl_pipe[0]); - close(ctl_pipe[1]); - close(st_pipe[0]); - close(st_pipe[1]); - - execv(fsrv->target_path, argv); - - *(u32*)trace_bits = EXEC_FAIL_SIG; - exit(0); - - } - - // Close the unneeded endpoints. - - close(ctl_pipe[0]); - close(st_pipe[1]); - - fsrv_ctl_fd = ctl_pipe[1]; - fsrv_st_fd = st_pipe[0]; - - // Configure timeout, wait for child, cancel timeout. - - if (exec_tmout) { - - child_timed_out = 0; - it.it_value.tv_sec = (exec_tmout * FORK_WAIT_MULT / 1000); - it.it_value.tv_usec = ((exec_tmout * FORK_WAIT_MULT) % 1000) * 1000; - - } - - setitimer(ITIMER_REAL, &it, NULL); - - rlen = read(fsrv_st_fd, &status, 4); - - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 0; - setitimer(ITIMER_REAL, &it, NULL); - - // If we have a four-byte "hello" message from the server, we're all set. - // Otherwise, try to figure out what went wrong. - - if (rlen == 4) { - - ACTF("All right - fork server is up."); - return; - - } - - if (waitpid(forksrv_pid, &status, 0) <= 0) - PFATAL("waitpid() failed"); - - u8 child_crashed; - - if (WIFSIGNALED(status)) - child_crashed = 1; - - if (child_timed_out) - SAYF(cLRD "\n+++ Program timed off +++\n" cRST); - else if (stop_soon) - SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST); - else if (child_crashed) - SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST, WTERMSIG(status)); - -} - -*/ - /* Execute target application. Returns 0 if the changes are a dud, or 1 if they should be kept. */ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, u8 first_run) { - static struct itimerval it; - static u32 prev_timed_out = 0; - int status = 0; + struct itimerval it; + int status = 0; u32 cksum; fsrv->child_timed_out = 0; - memset(fsrv->trace_bits, 0, MAP_SIZE); + memset(fsrv->trace_bits, 0, fsrv->map_size); MEM_BARRIER(); write_to_testcase(fsrv, mem, len); @@ -416,7 +266,7 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, /* we have the fork server up and running, so simply tell it to have at it, and then read back PID. */ - if ((res = write(fsrv->fsrv_ctl_fd, &prev_timed_out, 4)) != 4) { + if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) { if (stop_soon) return 0; RPFATAL(res, "Unable to request new process from fork server (OOM?)"); @@ -541,7 +391,7 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, } - cksum = hash32(fsrv->trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(fsrv->trace_bits, fsrv->map_size, HASH_CONST); if (first_run) orig_cksum = cksum; @@ -552,17 +402,6 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, } -/* Find first power of two greater or equal to val. */ - -static u32 next_p2(u32 val) { - - u32 ret = 1; - while (val > ret) - ret <<= 1; - return ret; - -} - /* Actually minimize! */ static void minimize(afl_forkserver_t *fsrv, char **argv) { @@ -580,7 +419,7 @@ static void minimize(afl_forkserver_t *fsrv, char **argv) { * BLOCK NORMALIZATION * ***********************/ - set_len = next_p2(in_len / TMIN_SET_STEPS); + set_len = next_pow2(in_len / TMIN_SET_STEPS); set_pos = 0; if (set_len < TMIN_SET_MIN_SIZE) set_len = TMIN_SET_MIN_SIZE; @@ -630,7 +469,7 @@ next_pass: * BLOCK DELETION * ******************/ - del_len = next_p2(in_len / TRIM_START_STEPS); + del_len = next_pow2(in_len / TRIM_START_STEPS); stage_o_len = in_len; ACTF(cBRI "Stage #1: " cRST "Removing blocks of data..."); @@ -905,7 +744,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) { if (get_afl_env("AFL_PRELOAD")) { - if (qemu_mode) { + if (fsrv->qemu_mode) { u8 *qemu_preload = getenv("QEMU_SET_ENV"); u8 *afl_preload = getenv("AFL_PRELOAD"); @@ -962,11 +801,6 @@ static void setup_signal_handlers(void) { sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); - /* Exec timeout notifications. */ - - sa.sa_handler = handle_timeout; - sigaction(SIGALRM, &sa, NULL); - } /* Display usage hints. */ @@ -1193,10 +1027,10 @@ int main(int argc, char **argv_orig, char **envp) { case 'Q': - if (qemu_mode) FATAL("Multiple -Q options not supported"); + if (fsrv->qemu_mode) FATAL("Multiple -Q options not supported"); if (!mem_limit_given) fsrv->mem_limit = MEM_LIMIT_QEMU; - qemu_mode = 1; + fsrv->qemu_mode = 1; break; case 'U': @@ -1210,7 +1044,7 @@ int main(int argc, char **argv_orig, char **envp) { case 'W': /* Wine+QEMU mode */ if (use_wine) FATAL("Multiple -W options not supported"); - qemu_mode = 1; + fsrv->qemu_mode = 1; use_wine = 1; if (!mem_limit_given) fsrv->mem_limit = 0; @@ -1271,7 +1105,7 @@ int main(int argc, char **argv_orig, char **envp) { find_binary(fsrv, argv[optind]); detect_file_args(argv + optind, fsrv->out_file, &fsrv->use_stdin); - if (qemu_mode) { + if (fsrv->qemu_mode) { if (use_wine) use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind, @@ -1297,7 +1131,8 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); - afl_fsrv_start(fsrv, use_argv); + afl_fsrv_start(fsrv, use_argv, &stop_soon, + get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", fsrv->mem_limit, fsrv->exec_tmout, edges_only ? ", edges only" : ""); diff --git a/src/third_party/libradamsa/Makefile b/src/third_party/libradamsa/GNUmakefile index c5a78ead..c5a78ead 100644 --- a/src/third_party/libradamsa/Makefile +++ b/src/third_party/libradamsa/GNUmakefile diff --git a/src/third_party/libradamsa/libradamsa.c b/src/third_party/libradamsa/libradamsa.c index f3677fa7..27cf91bc 100644 --- a/src/third_party/libradamsa/libradamsa.c +++ b/src/third_party/libradamsa/libradamsa.c @@ -2177,7 +2177,7 @@ static uint llen(word *ptr) { return len; } -static void set_signal_handler() { +static void set_signal_handler(void) { struct sigaction sa; sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); @@ -2312,7 +2312,7 @@ static word prim_set(word wptr, hval pos, word val) { return (word) new; } -static void setdown() { +static void setdown(void) { tcsetattr(0, TCSANOW, &tsettings); /* return stdio settings */ } @@ -30773,7 +30773,7 @@ int secondary(int nargs, char **argv) { return 127; } -void radamsa_init() { +void radamsa_init(void) { int nobjs=0, nwords=0; hp = (byte *) &heap; /* builtin heap */ state = IFALSE; @@ -30815,7 +30815,7 @@ size_t copy_list(uint8_t *ptr, word lispval, size_t max) { lispval = G(lispval, 2); // list = cdr(list) } if (lispval != INULL && max == 0) { - printf("ERROR: lisp return value was not a proper list. Trailing %lu\n", lispval); + printf("ERROR: lisp return value was not a proper list. Trailing %lu\n", (unsigned long)lispval); } return n; } diff --git a/src/third_party/libradamsa/radamsa.h b/src/third_party/libradamsa/radamsa.h index d54fa2ec..33cccde4 100644 --- a/src/third_party/libradamsa/radamsa.h +++ b/src/third_party/libradamsa/radamsa.h @@ -1,15 +1,13 @@ #include <inttypes.h> #include <stddef.h> -extern void radamsa_init(); +extern void radamsa_init(void); -extern size_t radamsa(uint8_t *ptr, size_t len, - uint8_t *target, size_t max, +extern size_t radamsa(uint8_t *ptr, size_t len, + uint8_t *target, size_t max, unsigned int seed); -extern size_t radamsa_inplace(uint8_t *ptr, - size_t len, - size_t max, +extern size_t radamsa_inplace(uint8_t *ptr, + size_t len, + size_t max, unsigned int seed); - - |