diff options
author | van Hauser <vh@thc.org> | 2023-04-26 16:33:42 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-26 16:33:42 +0200 |
commit | 7ca1b85c5e8229fa49620d0fb542c86965ef5abb (patch) | |
tree | 49357cab6a9fea70f30f43b129b02434772f5e66 | |
parent | dbb317162415a28e3fd2ff4c574292c924493a00 (diff) | |
parent | b18bc7b98fa23ef805ed2ee3eec04dc1929afd49 (diff) | |
download | afl++-7ca1b85c5e8229fa49620d0fb542c86965ef5abb.tar.gz |
Merge pull request #1715 from AFLplusplus/dev
push to stable
-rw-r--r-- | TODO.md | 1 | ||||
-rwxr-xr-x | afl-cmin | 143 | ||||
-rwxr-xr-x | afl-cmin.bash | 112 | ||||
-rw-r--r-- | custom_mutators/atnwalk/Makefile | 7 | ||||
-rw-r--r-- | custom_mutators/atnwalk/README.md | 4 | ||||
-rw-r--r-- | custom_mutators/honggfuzz/custom_mutator_helpers.h | 22 | ||||
-rw-r--r-- | custom_mutators/honggfuzz/honggfuzz.c | 18 | ||||
-rw-r--r-- | custom_mutators/honggfuzz/mangle.c | 1181 | ||||
l--------- | custom_mutators/radamsa/custom_mutator_helpers.h | 1 | ||||
-rw-r--r-- | custom_mutators/radamsa/radamsa-mutator.c | 11 | ||||
-rw-r--r-- | docs/Changelog.md | 11 | ||||
-rw-r--r-- | docs/FAQ.md | 3 | ||||
-rw-r--r-- | docs/env_variables.md | 9 | ||||
-rw-r--r-- | include/envs.h | 4 | ||||
-rw-r--r-- | instrumentation/SanitizerCoverageLTO.so.cc | 3 | ||||
-rw-r--r-- | instrumentation/afl-compiler-rt.o.c | 16 | ||||
-rw-r--r-- | src/afl-cc.c | 2 | ||||
-rw-r--r-- | src/afl-fuzz-init.c | 35 | ||||
-rw-r--r-- | src/afl-fuzz.c | 2 | ||||
-rw-r--r-- | src/afl-showmap.c | 174 |
20 files changed, 1112 insertions, 647 deletions
diff --git a/TODO.md b/TODO.md index dba75070..2efcefea 100644 --- a/TODO.md +++ b/TODO.md @@ -10,7 +10,6 @@ - parallel builds for source-only targets - get rid of check_binary, replace with more forkserver communication - first fuzzer should be a main automatically? not sure. - - reload fuzz binary on signal ## Maybe diff --git a/afl-cmin b/afl-cmin index e2c26d91..63cfdd7e 100755 --- a/afl-cmin +++ b/afl-cmin @@ -103,9 +103,10 @@ function usage() { " -o dir - output directory for minimized files\n" \ "\n" \ "Execution control settings:\n" \ +" -T tasks - how many parallel tasks to run (default: 1, all=nproc)\n" \ " -f file - location read by the fuzzed program (stdin)\n" \ " -m megs - memory limit for child process ("mem_limit" MB)\n" \ -" -t msec - run time limit for child process (default: none)\n" \ +" -t msec - run time limit for child process (default: 5000)\n" \ " -O - use binary-only instrumentation (FRIDA mode)\n" \ " -Q - use binary-only instrumentation (QEMU mode)\n" \ " -U - use unicorn-based instrumentation (unicorn mode)\n" \ @@ -119,7 +120,6 @@ function usage() { "For additional tips, please consult README.md\n" \ "\n" \ "Environment variables used:\n" \ -"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \ "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \ "AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \ "AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \ @@ -159,13 +159,19 @@ BEGIN { # process options Opterr = 1 # default is to diagnose Optind = 1 # skip ARGV[0] - while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXY?")) != -1) { + while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXYT:?")) != -1) { if (_go_c == "i") { if (!Optarg) usage() if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} in_dir = Optarg continue } else + if (_go_c == "T") { + if (!Optarg) usage() + if (threads) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} + threads = Optarg + continue + } else if (_go_c == "o") { if (!Optarg) usage() if (out_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} @@ -234,7 +240,7 @@ BEGIN { } # while options if (!mem_limit) mem_limit = "none" - if (!timeout) timeout = "none" + if (!timeout) timeout = "5000" # get program args i = 0 @@ -253,21 +259,30 @@ BEGIN { # Do a sanity check to discourage the use of /tmp, since we can't really # handle this safely from an awk script. - if (!ENVIRON["AFL_ALLOW_TMP"]) { - dirlist[0] = in_dir - dirlist[1] = target_bin - dirlist[2] = out_dir - dirlist[3] = stdin_file - "pwd" | getline dirlist[4] # current directory - for (dirind in dirlist) { - dir = dirlist[dirind] - - if (dir ~ /^(\/var)?\/tmp/) { - print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr" - exit 1 - } - } - delete dirlist + #if (!ENVIRON["AFL_ALLOW_TMP"]) { + # dirlist[0] = in_dir + # dirlist[1] = target_bin + # dirlist[2] = out_dir + # dirlist[3] = stdin_file + # "pwd" | getline dirlist[4] # current directory + # for (dirind in dirlist) { + # dir = dirlist[dirind] + # + # if (dir ~ /^(\/var)?\/tmp/) { + # print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr" + # exit 1 + # } + # } + # delete dirlist + #} + + if (threads && stdin_file) { + print "[-] Error: -T and -f cannot be used together." > "/dev/stderr" + exit 1 + } + + if (!threads && !stdin_file && !nyx_mode) { + print "[*] Are you aware of the '-T all' parallelize option that improves the speed for large/slow corpuses?" } # If @@ is specified, but there's no -f, let's come up with a temporary input @@ -350,6 +365,18 @@ BEGIN { exit 1 } + if (threads) { + "nproc" | getline nproc + if (threads == "all") { + threads = nproc + } else { + if (!(threads > 1 && threads <= nproc)) { + print "[-] Error: -T option must be between 1 and "nproc" or \"all\"." > "/dev/stderr" + exit 1 + } + } + } + # Check for the more efficient way to copy files... if (0 != system("mkdir -p -m 0700 "trace_dir)) { print "[-] Error: Cannot create directory "trace_dir > "/dev/stderr" @@ -459,27 +486,79 @@ BEGIN { # STEP 1: Collecting traces # ############################# + if (threads) { + + inputsperfile = in_count / threads + if (in_count % threads) { + inputsperfile++; + } + + cnt = 0; + tmpfile=out_dir "/.filelist" + for (instance = 1; instance < threads; instance++) { + for (i = 0; i < inputsperfile; i++) { + print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."instance + cnt++ + } + } + for (; cnt < in_count; cnt++) { + print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."threads + } + + } + print "[*] Obtaining traces for "in_count" input files in '"in_dir"'." cur = 0; - if (!stdin_file) { - print " Processing "in_count" files (forkserver mode)..." -# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string - retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string) + + if (threads > 1) { + + print "[*] Creating " threads " parallel tasks with about " inputsperfile " each." + for (i = 1; i <= threads; i++) { + + if (!stdin_file) { +# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &" + retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &") + } else { + stdin_file=tmpfile"."i".stdin" +# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null; > "tmpfile"."i".done ; } &" + retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null; > "tmpfile"."i".done ; } &") + } + } + print "[*] Waiting for parallel tasks to complete ..." + # wait for all processes to finish + ok=0 + while (ok < threads) { + ok=0 + for (i = 1; i <= threads; i++) { + if (system("test -f "tmpfile"."i".done") == 0) { + ok++ + } + } + } + print "[*] Done!" + system("rm -f "tmpfile"*") } else { - print " Processing "in_count" files (forkserver mode)..." + if (!stdin_file) { + print " Processing "in_count" files (forkserver mode)..." +# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string + retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string) + } else { + print " Processing "in_count" files (forkserver mode)..." # print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null" - retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null") - } + retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" </dev/null") + } - if (retval && (!AFL_CMIN_CRASHES_ONLY && !AFL_CMIN_ALLOW_ANY)) { - print "[!] Exit code "retval" != 0 received from afl-showmap (this means a crashing or timeout input is likely present), terminating..." + if (retval && (!AFL_CMIN_CRASHES_ONLY && !AFL_CMIN_ALLOW_ANY)) { + print "[!] Exit code "retval" != 0 received from afl-showmap (this means a crashing or timeout input is likely present), terminating..." - if (!ENVIRON["AFL_KEEP_TRACES"]) { - system("rm -rf "trace_dir" 2>/dev/null") - system("rmdir "out_dir) + if (!ENVIRON["AFL_KEEP_TRACES"]) { + system("rm -rf "trace_dir" 2>/dev/null") + system("rmdir "out_dir) + } + exit retval } - exit retval + } ####################################################### diff --git a/afl-cmin.bash b/afl-cmin.bash index 5258758e..d390ff65 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -7,6 +7,8 @@ # # Copyright 2014, 2015 Google Inc. All rights reserved. # +# Copyright 2019-2023 AFLplusplus +# # 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: @@ -36,7 +38,7 @@ # array sizes. # -echo "corpus minimization tool for afl-fuzz by Michal Zalewski" +echo "corpus minimization tool for afl-fuzz" echo ######### @@ -46,14 +48,14 @@ echo # Process command-line options... MEM_LIMIT=none -TIMEOUT=none +TIMEOUT=5000 -unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \ - AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE +unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN F_ARG \ + AFL_CMIN_CRASHES_ONLY AFL_CMIN_ALLOW_ANY QEMU_MODE UNICORN_MODE T_ARG export AFL_QUIET=1 -while getopts "+i:o:f:m:t:eOQUAChXY" opt; do +while getopts "+i:o:f:m:t:T:eOQUAChXY" opt; do case "$opt" in @@ -69,6 +71,7 @@ while getopts "+i:o:f:m:t:eOQUAChXY" opt; do ;; "f") STDIN_FILE="$OPTARG" + F_ARG=1 ;; "m") MEM_LIMIT="$OPTARG" @@ -106,6 +109,9 @@ while getopts "+i:o:f:m:t:eOQUAChXY" opt; do EXTRA_PAR="$EXTRA_PAR -U" UNICORN_MODE=1 ;; + "T") + T_ARG="$OPTARG" + ;; "?") exit 1 ;; @@ -130,9 +136,10 @@ Required parameters: Execution control settings: - -f file - location read by the fuzzed program (stdin) - -m megs - memory limit for child process ($MEM_LIMIT MB) - -t msec - run time limit for child process (none) + -T tasks - how many parallel processes to create (default=1, "all"=nproc) + -f file - location read by the fuzzed program (default: stdin) + -m megs - memory limit for child process (default=$MEM_LIMIT MB) + -t msec - run time limit for child process (default: 5000ms) -O - use binary-only instrumentation (FRIDA mode) -Q - use binary-only instrumentation (QEMU mode) -U - use unicorn-based instrumentation (Unicorn mode) @@ -199,6 +206,11 @@ fi # Check for obvious errors. +if [ ! "$T_ARG" = "" -a ! "$F_ARG" = "" -a ! "$NYX_MODE" == 1 ]; then + echo "[-] Error: -T and -f can not be used together." 1>&2 + exit 1 +fi + if [ ! "$MEM_LIMIT" = "none" ]; then if [ "$MEM_LIMIT" -lt "5" ]; then @@ -233,7 +245,7 @@ if [ "$NYX_MODE" = "" ]; then fi -grep -aq AFL_DUMP_MAP_SIZE "./$TARGET_BIN" && { +grep -aq AFL_DUMP_MAP_SIZE "$TARGET_BIN" && { echo "[!] Trying to obtain the map size of the target ..." MAPSIZE=`AFL_DUMP_MAP_SIZE=1 "./$TARGET_BIN" 2>/dev/null` test -n "$MAPSIZE" && { @@ -299,14 +311,34 @@ if [ ! -x "$SHOWMAP" ]; then exit 1 fi +THREADS= +if [ ! "$T_ARG" = "" ]; then + if [ "$T_ARG" = "all" ]; then + THREADS=$(nproc) + else + if [ "$T_ARG" -gt 1 -a "$T_ARG" -le "$(nproc)" ]; then + THREADS=$T_ARG + else + echo "[-] Error: -T parameter must between 2 and $(nproc) or \"all\"." 1>&2 + fi + fi +else + if [ "$F_ARG" = ""]; then + echo "[*] Are you aware of the '-T all' parallelize option that massively improves the speed?" + fi +fi + IN_COUNT=$((`ls -- "$IN_DIR" 2>/dev/null | wc -l`)) if [ "$IN_COUNT" = "0" ]; then - echo "[+] Hmm, no inputs in the target directory. Nothing to be done." + echo "[-] Hmm, no inputs in the target directory. Nothing to be done." rm -rf "$TRACE_DIR" exit 1 fi +echo "[*] Are you aware that afl-cmin is faster than this afl-cmin.bash script?" +echo "[+] Found $IN_COUNT files for minimizing." + FIRST_FILE=`ls "$IN_DIR" | head -1` # Make sure that we're not dealing with a directory. @@ -355,6 +387,18 @@ else fi +TMPFILE=$OUT_DIR/.list.$$ +if [ ! "$THREADS" = "" ]; then + ls -- "$IN_DIR" > $TMPFILE 2>/dev/null + IN_COUNT=$(cat $TMPFILE | wc -l) + SPLIT=$(($IN_COUNT / $THREADS)) + if [ "$(($IN_COUNT % $THREADS))" -gt 0 ]; then + SPLIT=$(($SPLIT + 1)) + fi + echo "[+] Splitting workload into $THREADS tasks with $SPLIT items on average each." + split -l $SPLIT $TMPFILE $TMPFILE. +fi + # Let's roll! ############################# @@ -363,6 +407,7 @@ fi echo "[*] Obtaining traces for input files in '$IN_DIR'..." +if [ "$THREADS" = "" ]; then ( CUR=0 @@ -386,17 +431,58 @@ echo "[*] Obtaining traces for input files in '$IN_DIR'..." printf "\\r Processing file $CUR/$IN_COUNT... " cp "$IN_DIR/$fn" "$STDIN_FILE" - "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null done - fi + echo + ) -echo +else + + PIDS= + CNT=0 + for inputs in $(ls ${TMPFILE}.*); do + +( + + if [ "$STDIN_FILE" = "" ]; then + + cat $inputs | while read -r fn; do + + "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -- "$@" <"$IN_DIR/$fn" + + done + + else + + STDIN_FILE="$inputs.$$" + cat $inputs | while read -r fn; do + + cp "$IN_DIR/$fn" "$STDIN_FILE" + "$SHOWMAP" -m "$MEM_LIMIT" -t "$TIMEOUT" -o "$TRACE_DIR/$fn" -Z $EXTRA_PAR -H "$STDIN_FILE" -- "$@" </dev/null + + done + + fi + +) & + + PIDS="$PIDS $!" + done + + echo "[+] Waiting for running tasks IDs:$PIDS" + wait + echo "[+] all $THREADS running tasks completed." + rm -f ${TMPFILE}* + + echo trace dir files: $(ls $TRACE_DIR/*|wc -l) + +fi + ########################## # STEP 2: SORTING TUPLES # diff --git a/custom_mutators/atnwalk/Makefile b/custom_mutators/atnwalk/Makefile new file mode 100644 index 00000000..bf83cae5 --- /dev/null +++ b/custom_mutators/atnwalk/Makefile @@ -0,0 +1,7 @@ +all: atnwalk.so + +atnwalk.so: atnwalk.c + $(CC) -I ../../include/ -shared -fPIC -O3 -o atnwalk.so atnwalk.c + +clean: + rm -f *.so *.o *~ core diff --git a/custom_mutators/atnwalk/README.md b/custom_mutators/atnwalk/README.md index badb856f..730349a3 100644 --- a/custom_mutators/atnwalk/README.md +++ b/custom_mutators/atnwalk/README.md @@ -6,9 +6,7 @@ Refer to [https://github.com/atnwalk/testbed](https://github.com/atnwalk/testbed ## Build -```bash -gcc -I ../../include/ -shared -fPIC -Wall -O3 atnwalk.c -o atnwalk.so -``` +Just type `make` to build `atnwalk.so`. ## Run diff --git a/custom_mutators/honggfuzz/custom_mutator_helpers.h b/custom_mutators/honggfuzz/custom_mutator_helpers.h deleted file mode 100644 index 57754697..00000000 --- a/custom_mutators/honggfuzz/custom_mutator_helpers.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CUSTOM_MUTATOR_HELPERS -#define CUSTOM_MUTATOR_HELPERS - -#include "config.h" -#include "types.h" -#include "afl-fuzz.h" -#include <stdlib.h> - -#define INITIAL_GROWTH_SIZE (64) - -/* Use in a struct: creates a name_buf and a name_size variable. */ -#define BUF_VAR(type, name) \ - type * name##_buf; \ - size_t name##_size; -/* this filles in `&structptr->something_buf, &structptr->something_size`. */ -#define BUF_PARAMS(struct, name) \ - (void **)&struct->name##_buf, &struct->name##_size - -#undef INITIAL_GROWTH_SIZE - -#endif - diff --git a/custom_mutators/honggfuzz/honggfuzz.c b/custom_mutators/honggfuzz/honggfuzz.c index d7b3c9c5..0dd59aee 100644 --- a/custom_mutators/honggfuzz/honggfuzz.c +++ b/custom_mutators/honggfuzz/honggfuzz.c @@ -3,14 +3,14 @@ #include <stdlib.h> #include <string.h> -#include "custom_mutator_helpers.h" +#include "afl-fuzz.h" #include "mangle.h" #define NUMBER_OF_MUTATIONS 5 -uint8_t * queue_input; +uint8_t *queue_input; size_t queue_input_size; -afl_state_t * afl_struct; +afl_state_t *afl_struct; run_t run; honggfuzz_t global; struct _dynfile_t dynfile; @@ -18,8 +18,8 @@ struct _dynfile_t dynfile; typedef struct my_mutator { afl_state_t *afl; - run_t * run; - u8 * mutator_buf; + run_t *run; + u8 *mutator_buf; unsigned int seed; unsigned int extras_cnt, a_extras_cnt; @@ -65,9 +65,9 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { /* When a new queue entry is added we check if there are new dictionary entries to add to honggfuzz structure */ -uint8_t afl_custom_queue_new_entry(my_mutator_t * data, - const uint8_t *filename_new_queue, - const uint8_t *filename_orig_queue) { +void afl_custom_queue_new_entry(my_mutator_t *data, + const uint8_t *filename_new_queue, + const uint8_t *filename_orig_queue) { if (run.global->mutate.dictionaryCnt >= 1024) return; @@ -97,7 +97,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t * data, } - return 0; + return; } diff --git a/custom_mutators/honggfuzz/mangle.c b/custom_mutators/honggfuzz/mangle.c index 637d428d..7b7ccb91 100644 --- a/custom_mutators/honggfuzz/mangle.c +++ b/custom_mutators/honggfuzz/mangle.c @@ -39,11 +39,16 @@ #include "libhfcommon/log.h" #include "libhfcommon/util.h" -static inline size_t mangle_LenLeft(run_t* run, size_t off) { - if (off >= run->dynfile->size) { - LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size); - } - return (run->dynfile->size - off - 1); +static inline size_t mangle_LenLeft(run_t *run, size_t off) { + + if (off >= run->dynfile->size) { + + LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size); + + } + + return (run->dynfile->size - off - 1); + } /* @@ -51,196 +56,233 @@ static inline size_t mangle_LenLeft(run_t* run, size_t off) { * Based on an idea by https://twitter.com/gamozolabs */ static inline size_t mangle_getLen(size_t max) { - if (max > _HF_INPUT_MAX_SIZE) { - LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max, (size_t)_HF_INPUT_MAX_SIZE); - } - if (max == 0) { - LOG_F("max == 0"); - } - if (max == 1) { - return 1; - } - /* Give 50% chance the the uniform distribution */ - if (util_rnd64() & 1) { - return (size_t)util_rndGet(1, max); - } + if (max > _HF_INPUT_MAX_SIZE) { + + LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max, + (size_t)_HF_INPUT_MAX_SIZE); + + } + + if (max == 0) { LOG_F("max == 0"); } + if (max == 1) { return 1; } + + /* Give 50% chance the the uniform distribution */ + if (util_rnd64() & 1) { return (size_t)util_rndGet(1, max); } + + /* effectively exprand() */ + return (size_t)util_rndGet(1, util_rndGet(1, max)); - /* effectively exprand() */ - return (size_t)util_rndGet(1, util_rndGet(1, max)); } /* Prefer smaller values here, so use mangle_getLen() */ -static inline size_t mangle_getOffSet(run_t* run) { - return mangle_getLen(run->dynfile->size) - 1; +static inline size_t mangle_getOffSet(run_t *run) { + + return mangle_getLen(run->dynfile->size) - 1; + } /* Offset which can be equal to the file size */ -static inline size_t mangle_getOffSetPlus1(run_t* run) { - size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE); - return mangle_getLen(reqlen) - 1; +static inline size_t mangle_getOffSetPlus1(run_t *run) { + + size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE); + return mangle_getLen(reqlen) - 1; + } -static inline void mangle_Move(run_t* run, size_t off_from, size_t off_to, size_t len) { - if (off_from >= run->dynfile->size) { - return; - } - if (off_to >= run->dynfile->size) { - return; - } - if (off_from == off_to) { - return; - } +static inline void mangle_Move(run_t *run, size_t off_from, size_t off_to, + size_t len) { + + if (off_from >= run->dynfile->size) { return; } + if (off_to >= run->dynfile->size) { return; } + if (off_from == off_to) { return; } - size_t len_from = run->dynfile->size - off_from; - len = HF_MIN(len, len_from); + size_t len_from = run->dynfile->size - off_from; + len = HF_MIN(len, len_from); - size_t len_to = run->dynfile->size - off_to; - len = HF_MIN(len, len_to); + size_t len_to = run->dynfile->size - off_to; + len = HF_MIN(len, len_to); + + memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len); - memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len); } -static inline void mangle_Overwrite( - run_t* run, size_t off, const uint8_t* src, size_t len, bool printable) { - if (len == 0) { - return; - } - size_t maxToCopy = run->dynfile->size - off; - if (len > maxToCopy) { - len = maxToCopy; - } +static inline void mangle_Overwrite(run_t *run, size_t off, const uint8_t *src, + size_t len, bool printable) { + + if (len == 0) { return; } + size_t maxToCopy = run->dynfile->size - off; + if (len > maxToCopy) { len = maxToCopy; } + + memmove(&run->dynfile->data[off], src, len); + if (printable) { util_turnToPrintable(&run->dynfile->data[off], len); } - memmove(&run->dynfile->data[off], src, len); - if (printable) { - util_turnToPrintable(&run->dynfile->data[off], len); - } } -static inline size_t mangle_Inflate(run_t* run, size_t off, size_t len, bool printable) { - if (run->dynfile->size >= run->global->mutate.maxInputSz) { - return 0; - } - if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) { - len = run->global->mutate.maxInputSz - run->dynfile->size; - } +static inline size_t mangle_Inflate(run_t *run, size_t off, size_t len, + bool printable) { - input_setSize(run, run->dynfile->size + len); - mangle_Move(run, off, off + len, run->dynfile->size); - if (printable) { - memset(&run->dynfile->data[off], ' ', len); - } + if (run->dynfile->size >= run->global->mutate.maxInputSz) { return 0; } + if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) { + + len = run->global->mutate.maxInputSz - run->dynfile->size; + + } + + input_setSize(run, run->dynfile->size + len); + mangle_Move(run, off, off + len, run->dynfile->size); + if (printable) { memset(&run->dynfile->data[off], ' ', len); } + + return len; - return len; } -static inline void mangle_Insert( - run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) { - len = mangle_Inflate(run, off, len, printable); - mangle_Overwrite(run, off, val, len, printable); +static inline void mangle_Insert(run_t *run, size_t off, const uint8_t *val, + size_t len, bool printable) { + + len = mangle_Inflate(run, off, len, printable); + mangle_Overwrite(run, off, val, len, printable); + } -static inline void mangle_UseValue(run_t* run, const uint8_t* val, size_t len, bool printable) { - if (util_rnd64() & 1) { - mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable); - } else { - mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable); - } +static inline void mangle_UseValue(run_t *run, const uint8_t *val, size_t len, + bool printable) { + + if (util_rnd64() & 1) { + + mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable); + + } else { + + mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable); + + } + } -static inline void mangle_UseValueAt( - run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) { - if (util_rnd64() & 1) { - mangle_Overwrite(run, off, val, len, printable); - } else { - mangle_Insert(run, off, val, len, printable); - } +static inline void mangle_UseValueAt(run_t *run, size_t off, const uint8_t *val, + size_t len, bool printable) { + + if (util_rnd64() & 1) { + + mangle_Overwrite(run, off, val, len, printable); + + } else { + + mangle_Insert(run, off, val, len, printable); + + } + } -static void mangle_MemSwap(run_t* run, bool printable HF_ATTR_UNUSED) { - /* No big deal if those two are overlapping */ - size_t off1 = mangle_getOffSet(run); - size_t maxlen1 = run->dynfile->size - off1; - size_t off2 = mangle_getOffSet(run); - size_t maxlen2 = run->dynfile->size - off2; - size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2)); +static void mangle_MemSwap(run_t *run, bool printable HF_ATTR_UNUSED) { - if (off1 == off2) { - return; - } + /* No big deal if those two are overlapping */ + size_t off1 = mangle_getOffSet(run); + size_t maxlen1 = run->dynfile->size - off1; + size_t off2 = mangle_getOffSet(run); + size_t maxlen2 = run->dynfile->size - off2; + size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2)); + + if (off1 == off2) { return; } + + for (size_t i = 0; i < (len / 2); i++) { + + /* + * First - from the head, next from the tail. Don't worry about layout of + * the overlapping part - there's no good solution to that, and it can be + * left somewhat scrambled, while still preserving the entropy + */ + const uint8_t tmp1 = run->dynfile->data[off2 + i]; + run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i]; + run->dynfile->data[off1 + i] = tmp1; + const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i]; + run->dynfile->data[off2 + (len - 1) - i] = + run->dynfile->data[off1 + (len - 1) - i]; + run->dynfile->data[off1 + (len - 1) - i] = tmp2; + + } - for (size_t i = 0; i < (len / 2); i++) { - /* - * First - from the head, next from the tail. Don't worry about layout of the overlapping - * part - there's no good solution to that, and it can be left somewhat scrambled, - * while still preserving the entropy - */ - const uint8_t tmp1 = run->dynfile->data[off2 + i]; - run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i]; - run->dynfile->data[off1 + i] = tmp1; - const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i]; - run->dynfile->data[off2 + (len - 1) - i] = run->dynfile->data[off1 + (len - 1) - i]; - run->dynfile->data[off1 + (len - 1) - i] = tmp2; - } } -static void mangle_MemCopy(run_t* run, bool printable HF_ATTR_UNUSED) { - size_t off = mangle_getOffSet(run); - size_t len = mangle_getLen(run->dynfile->size - off); +static void mangle_MemCopy(run_t *run, bool printable HF_ATTR_UNUSED) { + + size_t off = mangle_getOffSet(run); + size_t len = mangle_getLen(run->dynfile->size - off); - /* Use a temp buf, as Insert/Inflate can change source bytes */ - uint8_t* tmpbuf = (uint8_t*)util_Malloc(len); - defer { - free(tmpbuf); - }; - memmove(tmpbuf, &run->dynfile->data[off], len); + /* Use a temp buf, as Insert/Inflate can change source bytes */ + uint8_t *tmpbuf = (uint8_t *)util_Malloc(len); + defer { + + free(tmpbuf); + + }; + + memmove(tmpbuf, &run->dynfile->data[off], len); + + mangle_UseValue(run, tmpbuf, len, printable); - mangle_UseValue(run, tmpbuf, len, printable); } -static void mangle_Bytes(run_t* run, bool printable) { - uint16_t buf; - if (printable) { - util_rndBufPrintable((uint8_t*)&buf, sizeof(buf)); - } else { - buf = util_rnd64(); - } +static void mangle_Bytes(run_t *run, bool printable) { + + uint16_t buf; + if (printable) { + + util_rndBufPrintable((uint8_t *)&buf, sizeof(buf)); + + } else { + + buf = util_rnd64(); + + } + + /* Overwrite with random 1-2-byte values */ + size_t toCopy = util_rndGet(1, 2); + mangle_UseValue(run, (const uint8_t *)&buf, toCopy, printable); - /* Overwrite with random 1-2-byte values */ - size_t toCopy = util_rndGet(1, 2); - mangle_UseValue(run, (const uint8_t*)&buf, toCopy, printable); } -static void mangle_ByteRepeat(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - size_t destOff = off + 1; - size_t maxSz = run->dynfile->size - destOff; +static void mangle_ByteRepeat(run_t *run, bool printable) { - /* No space to repeat */ - if (!maxSz) { - mangle_Bytes(run, printable); - return; - } + size_t off = mangle_getOffSet(run); + size_t destOff = off + 1; + size_t maxSz = run->dynfile->size - destOff; + + /* No space to repeat */ + if (!maxSz) { + + mangle_Bytes(run, printable); + return; + + } + + size_t len = mangle_getLen(maxSz); + if (util_rnd64() & 0x1) { + + len = mangle_Inflate(run, destOff, len, printable); + + } + + memset(&run->dynfile->data[destOff], run->dynfile->data[off], len); - size_t len = mangle_getLen(maxSz); - if (util_rnd64() & 0x1) { - len = mangle_Inflate(run, destOff, len, printable); - } - memset(&run->dynfile->data[destOff], run->dynfile->data[off], len); } -static void mangle_Bit(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7)); - if (printable) { - util_turnToPrintable(&(run->dynfile->data[off]), 1); - } +static void mangle_Bit(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7)); + if (printable) { util_turnToPrintable(&(run->dynfile->data[off]), 1); } + } static const struct { - const uint8_t val[8]; - const size_t size; + + const uint8_t val[8]; + const size_t size; + } mangleMagicVals[] = { + /* 1B - No endianness */ {"\x00\x00\x00\x00\x00\x00\x00\x00", 1}, {"\x01\x00\x00\x00\x00\x00\x00\x00", 1}, @@ -472,436 +514,543 @@ static const struct { {"\x00\x00\x00\x00\x00\x00\x00\x80", 8}, {"\x01\x00\x00\x00\x00\x00\x00\x80", 8}, {"\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8}, + }; -static void mangle_Magic(run_t* run, bool printable) { - uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1); - mangle_UseValue(run, mangleMagicVals[choice].val, mangleMagicVals[choice].size, printable); +static void mangle_Magic(run_t *run, bool printable) { + + uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1); + mangle_UseValue(run, mangleMagicVals[choice].val, + mangleMagicVals[choice].size, printable); + } -static void mangle_StaticDict(run_t* run, bool printable) { - if (run->global->mutate.dictionaryCnt == 0) { - mangle_Bytes(run, printable); - return; - } - uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1); - mangle_UseValue(run, run->global->mutate.dictionary[choice].val, - run->global->mutate.dictionary[choice].len, printable); +static void mangle_StaticDict(run_t *run, bool printable) { + + if (run->global->mutate.dictionaryCnt == 0) { + + mangle_Bytes(run, printable); + return; + + } + + uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1); + mangle_UseValue(run, run->global->mutate.dictionary[choice].val, + run->global->mutate.dictionary[choice].len, printable); + } -static inline const uint8_t* mangle_FeedbackDict(run_t* run, size_t* len) { - if (!run->global->feedback.cmpFeedback) { - return NULL; - } - cmpfeedback_t* cmpf = run->global->feedback.cmpFeedbackMap; - uint32_t cnt = ATOMIC_GET(cmpf->cnt); - if (cnt == 0) { - return NULL; - } - if (cnt > ARRAYSIZE(cmpf->valArr)) { - cnt = ARRAYSIZE(cmpf->valArr); - } - uint32_t choice = util_rndGet(0, cnt - 1); - *len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len); - if (*len == 0) { - return NULL; - } - return cmpf->valArr[choice].val; +static inline const uint8_t *mangle_FeedbackDict(run_t *run, size_t *len) { + + if (!run->global->feedback.cmpFeedback) { return NULL; } + cmpfeedback_t *cmpf = run->global->feedback.cmpFeedbackMap; + uint32_t cnt = ATOMIC_GET(cmpf->cnt); + if (cnt == 0) { return NULL; } + if (cnt > ARRAYSIZE(cmpf->valArr)) { cnt = ARRAYSIZE(cmpf->valArr); } + uint32_t choice = util_rndGet(0, cnt - 1); + *len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len); + if (*len == 0) { return NULL; } + return cmpf->valArr[choice].val; + } -static void mangle_ConstFeedbackDict(run_t* run, bool printable) { - size_t len; - const uint8_t* val = mangle_FeedbackDict(run, &len); - if (val == NULL) { - mangle_Bytes(run, printable); - return; - } - mangle_UseValue(run, val, len, printable); +static void mangle_ConstFeedbackDict(run_t *run, bool printable) { + + size_t len; + const uint8_t *val = mangle_FeedbackDict(run, &len); + if (val == NULL) { + + mangle_Bytes(run, printable); + return; + + } + + mangle_UseValue(run, val, len, printable); + } -static void mangle_MemSet(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - size_t len = mangle_getLen(run->dynfile->size - off); - int val = printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX); +static void mangle_MemSet(run_t *run, bool printable) { - if (util_rnd64() & 1) { - len = mangle_Inflate(run, off, len, printable); - } + size_t off = mangle_getOffSet(run); + size_t len = mangle_getLen(run->dynfile->size - off); + int val = + printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX); + + if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); } + + memset(&run->dynfile->data[off], val, len); - memset(&run->dynfile->data[off], val, len); } -static void mangle_MemClr(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - size_t len = mangle_getLen(run->dynfile->size - off); - int val = printable ? ' ' : 0; +static void mangle_MemClr(run_t *run, bool printable) { - if (util_rnd64() & 1) { - len = mangle_Inflate(run, off, len, printable); - } + size_t off = mangle_getOffSet(run); + size_t len = mangle_getLen(run->dynfile->size - off); + int val = printable ? ' ' : 0; + + if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); } + + memset(&run->dynfile->data[off], val, len); - memset(&run->dynfile->data[off], val, len); } -static void mangle_RandomBuf(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - size_t len = mangle_getLen(run->dynfile->size - off); +static void mangle_RandomBuf(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + size_t len = mangle_getLen(run->dynfile->size - off); + + if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); } + + if (printable) { + + util_rndBufPrintable(&run->dynfile->data[off], len); + + } else { + + util_rndBuf(&run->dynfile->data[off], len); + + } + +} + +static inline void mangle_AddSubWithRange(run_t *run, size_t off, size_t varLen, + uint64_t range, bool printable) { + + int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range; + + switch (varLen) { + + case 1: { + + run->dynfile->data[off] += delta; + break; - if (util_rnd64() & 1) { - len = mangle_Inflate(run, off, len, printable); } - if (printable) { - util_rndBufPrintable(&run->dynfile->data[off], len); - } else { - util_rndBuf(&run->dynfile->data[off], len); + case 2: { + + int16_t val; + memcpy(&val, &run->dynfile->data[off], sizeof(val)); + if (util_rnd64() & 0x1) { + + val += delta; + + } else { + + /* Foreign endianess */ + val = __builtin_bswap16(val); + val += delta; + val = __builtin_bswap16(val); + + } + + mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable); + break; + } -} -static inline void mangle_AddSubWithRange( - run_t* run, size_t off, size_t varLen, uint64_t range, bool printable) { - int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range; - - switch (varLen) { - case 1: { - run->dynfile->data[off] += delta; - break; - } - case 2: { - int16_t val; - memcpy(&val, &run->dynfile->data[off], sizeof(val)); - if (util_rnd64() & 0x1) { - val += delta; - } else { - /* Foreign endianess */ - val = __builtin_bswap16(val); - val += delta; - val = __builtin_bswap16(val); - } - mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable); - break; - } - case 4: { - int32_t val; - memcpy(&val, &run->dynfile->data[off], sizeof(val)); - if (util_rnd64() & 0x1) { - val += delta; - } else { - /* Foreign endianess */ - val = __builtin_bswap32(val); - val += delta; - val = __builtin_bswap32(val); - } - mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable); - break; - } - case 8: { - int64_t val; - memcpy(&val, &run->dynfile->data[off], sizeof(val)); - if (util_rnd64() & 0x1) { - val += delta; - } else { - /* Foreign endianess */ - val = __builtin_bswap64(val); - val += delta; - val = __builtin_bswap64(val); - } - mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable); - break; - } - default: { - LOG_F("Unknown variable length size: %zu", varLen); - } + case 4: { + + int32_t val; + memcpy(&val, &run->dynfile->data[off], sizeof(val)); + if (util_rnd64() & 0x1) { + + val += delta; + + } else { + + /* Foreign endianess */ + val = __builtin_bswap32(val); + val += delta; + val = __builtin_bswap32(val); + + } + + mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable); + break; + } -} -static void mangle_AddSub(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); + case 8: { + + int64_t val; + memcpy(&val, &run->dynfile->data[off], sizeof(val)); + if (util_rnd64() & 0x1) { + + val += delta; + + } else { + + /* Foreign endianess */ + val = __builtin_bswap64(val); + val += delta; + val = __builtin_bswap64(val); + + } + + mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable); + break; - /* 1,2,4,8 */ - size_t varLen = 1U << util_rndGet(0, 3); - if ((run->dynfile->size - off) < varLen) { - varLen = 1; } - uint64_t range; - switch (varLen) { - case 1: - range = 16; - break; - case 2: - range = 4096; - break; - case 4: - range = 1048576; - break; - case 8: - range = 268435456; - break; - default: - LOG_F("Invalid operand size: %zu", varLen); + default: { + + LOG_F("Unknown variable length size: %zu", varLen); + } - mangle_AddSubWithRange(run, off, varLen, range, printable); + } + } -static void mangle_IncByte(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - if (printable) { - run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32; - } else { - run->dynfile->data[off] += (uint8_t)1UL; - } +static void mangle_AddSub(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + + /* 1,2,4,8 */ + size_t varLen = 1U << util_rndGet(0, 3); + if ((run->dynfile->size - off) < varLen) { varLen = 1; } + + uint64_t range; + switch (varLen) { + + case 1: + range = 16; + break; + case 2: + range = 4096; + break; + case 4: + range = 1048576; + break; + case 8: + range = 268435456; + break; + default: + LOG_F("Invalid operand size: %zu", varLen); + + } + + mangle_AddSubWithRange(run, off, varLen, range, printable); + } -static void mangle_DecByte(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - if (printable) { - run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32; - } else { - run->dynfile->data[off] -= (uint8_t)1UL; - } +static void mangle_IncByte(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + if (printable) { + + run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32; + + } else { + + run->dynfile->data[off] += (uint8_t)1UL; + + } + } -static void mangle_NegByte(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - if (printable) { - run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32; - } else { - run->dynfile->data[off] = ~(run->dynfile->data[off]); - } +static void mangle_DecByte(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + if (printable) { + + run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32; + + } else { + + run->dynfile->data[off] -= (uint8_t)1UL; + + } + } -static void mangle_Expand(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); - size_t len; - if (util_rnd64() % 16) { - len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off)); - } else { - len = mangle_getLen(run->global->mutate.maxInputSz - off); - } +static void mangle_NegByte(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + if (printable) { + + run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32; + + } else { + + run->dynfile->data[off] = ~(run->dynfile->data[off]); + + } - mangle_Inflate(run, off, len, printable); } -static void mangle_Shrink(run_t* run, bool printable HF_ATTR_UNUSED) { - if (run->dynfile->size <= 2U) { - return; - } +static void mangle_Expand(run_t *run, bool printable) { - size_t off_start = mangle_getOffSet(run); - size_t len = mangle_LenLeft(run, off_start); - if (len == 0) { - return; - } - if (util_rnd64() % 16) { - len = mangle_getLen(HF_MIN(16, len)); - } else { - len = mangle_getLen(len); - } - size_t off_end = off_start + len; - size_t len_to_move = run->dynfile->size - off_end; + size_t off = mangle_getOffSet(run); + size_t len; + if (util_rnd64() % 16) { + + len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off)); + + } else { + + len = mangle_getLen(run->global->mutate.maxInputSz - off); + + } + + mangle_Inflate(run, off, len, printable); - mangle_Move(run, off_end, off_start, len_to_move); - input_setSize(run, run->dynfile->size - len); } -static void mangle_ASCIINum(run_t* run, bool printable) { - size_t len = util_rndGet(2, 8); - char buf[20]; - snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64()); +static void mangle_Shrink(run_t *run, bool printable HF_ATTR_UNUSED) { + + if (run->dynfile->size <= 2U) { return; } + + size_t off_start = mangle_getOffSet(run); + size_t len = mangle_LenLeft(run, off_start); + if (len == 0) { return; } + if (util_rnd64() % 16) { + + len = mangle_getLen(HF_MIN(16, len)); + + } else { + + len = mangle_getLen(len); + + } + + size_t off_end = off_start + len; + size_t len_to_move = run->dynfile->size - off_end; + + mangle_Move(run, off_end, off_start, len_to_move); + input_setSize(run, run->dynfile->size - len); - mangle_UseValue(run, (const uint8_t*)buf, len, printable); } -static void mangle_ASCIINumChange(run_t* run, bool printable) { - size_t off = mangle_getOffSet(run); +static void mangle_ASCIINum(run_t *run, bool printable) { - /* Find a digit */ - for (; off < run->dynfile->size; off++) { - if (isdigit(run->dynfile->data[off])) { - break; - } - } - size_t left = run->dynfile->size - off; - if (left == 0) { - return; - } + size_t len = util_rndGet(2, 8); - size_t len = 0; - uint64_t val = 0; - /* 20 is maximum lenght of a string representing a 64-bit unsigned value */ - for (len = 0; (len < 20) && (len < left); len++) { - char c = run->dynfile->data[off + len]; - if (!isdigit(c)) { - break; - } - val *= 10; - val += (c - '0'); - } + char buf[20]; + snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64()); - switch (util_rndGet(0, 7)) { - case 0: - val++; - break; - case 1: - val--; - break; - case 2: - val *= 2; - break; - case 3: - val /= 2; - break; - case 4: - val = util_rnd64(); - break; - case 5: - val += util_rndGet(1, 256); - break; - case 6: - val -= util_rndGet(1, 256); - break; - case 7: - val = ~(val); - break; - default: - LOG_F("Invalid choice"); - }; - - char buf[20]; - snprintf(buf, sizeof(buf), "%-19" PRIu64, val); - - mangle_UseValueAt(run, off, (const uint8_t*)buf, len, printable); -} - -static void mangle_Splice(run_t* run, bool printable) { - if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) { - mangle_Bytes(run, printable); - return; - } + mangle_UseValue(run, (const uint8_t *)buf, len, printable); - size_t sz = 0; - const uint8_t* buf = input_getRandomInputAsBuf(run, &sz); - if (!buf) { - LOG_E("input_getRandomInputAsBuf() returned no input"); - mangle_Bytes(run, printable); - return; - } - if (!sz) { - mangle_Bytes(run, printable); - return; - } +} - size_t remoteOff = mangle_getLen(sz) - 1; - size_t len = mangle_getLen(sz - remoteOff); - mangle_UseValue(run, &buf[remoteOff], len, printable); -} - -static void mangle_Resize(run_t* run, bool printable) { - ssize_t oldsz = run->dynfile->size; - ssize_t newsz = 0; - - uint64_t choice = util_rndGet(0, 32); - switch (choice) { - case 0: /* Set new size arbitrarily */ - newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz); - break; - case 1 ... 4: /* Increase size by a small value */ - newsz = oldsz + (ssize_t)util_rndGet(0, 8); - break; - case 5: /* Increase size by a larger value */ - newsz = oldsz + (ssize_t)util_rndGet(9, 128); - break; - case 6 ... 9: /* Decrease size by a small value */ - newsz = oldsz - (ssize_t)util_rndGet(0, 8); - break; - case 10: /* Decrease size by a larger value */ - newsz = oldsz - (ssize_t)util_rndGet(9, 128); - break; - case 11 ... 32: /* Do nothing */ - newsz = oldsz; - break; - default: - LOG_F("Illegal value from util_rndGet: %" PRIu64, choice); - break; - } - if (newsz < 1) { - newsz = 1; - } - if (newsz > (ssize_t)run->global->mutate.maxInputSz) { - newsz = run->global->mutate.maxInputSz; - } +static void mangle_ASCIINumChange(run_t *run, bool printable) { + + size_t off = mangle_getOffSet(run); + + /* Find a digit */ + for (; off < run->dynfile->size; off++) { + + if (isdigit(run->dynfile->data[off])) { break; } + + } + + size_t left = run->dynfile->size - off; + if (left == 0) { return; } + + size_t len = 0; + uint64_t val = 0; + /* 20 is maximum lenght of a string representing a 64-bit unsigned value */ + for (len = 0; (len < 20) && (len < left); len++) { + + char c = run->dynfile->data[off + len]; + if (!isdigit(c)) { break; } + val *= 10; + val += (c - '0'); + + } + + switch (util_rndGet(0, 7)) { + + case 0: + val++; + break; + case 1: + val--; + break; + case 2: + val *= 2; + break; + case 3: + val /= 2; + break; + case 4: + val = util_rnd64(); + break; + case 5: + val += util_rndGet(1, 256); + break; + case 6: + val -= util_rndGet(1, 256); + break; + case 7: + val = ~(val); + break; + default: + LOG_F("Invalid choice"); + + }; + + char buf[20]; + snprintf(buf, sizeof(buf), "%-19" PRIu64, val); + + mangle_UseValueAt(run, off, (const uint8_t *)buf, len, printable); - input_setSize(run, (size_t)newsz); - if (newsz > oldsz) { - if (printable) { - memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz); - } - } } -void mangle_mangleContent(run_t* run, int speed_factor) { - static void (*const mangleFuncs[])(run_t * run, bool printable) = { - mangle_Shrink, - mangle_Expand, - mangle_Bit, - mangle_IncByte, - mangle_DecByte, - mangle_NegByte, - mangle_AddSub, - mangle_MemSet, - mangle_MemClr, - mangle_MemSwap, - mangle_MemCopy, - mangle_Bytes, - mangle_ASCIINum, - mangle_ASCIINumChange, - mangle_ByteRepeat, - mangle_Magic, - mangle_StaticDict, - mangle_ConstFeedbackDict, - mangle_RandomBuf, - mangle_Splice, - }; - - if (run->mutationsPerRun == 0U) { - return; - } - if (run->dynfile->size == 0U) { - mangle_Resize(run, /* printable= */ run->global->cfg.only_printable); +static void mangle_Splice(run_t *run, bool printable) { + + if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) { + + mangle_Bytes(run, printable); + return; + + } + + size_t sz = 0; + const uint8_t *buf = input_getRandomInputAsBuf(run, &sz); + if (!buf) { + + LOG_E("input_getRandomInputAsBuf() returned no input"); + mangle_Bytes(run, printable); + return; + + } + + if (!sz) { + + mangle_Bytes(run, printable); + return; + + } + + size_t remoteOff = mangle_getLen(sz) - 1; + size_t len = mangle_getLen(sz - remoteOff); + mangle_UseValue(run, &buf[remoteOff], len, printable); + +} + +static void mangle_Resize(run_t *run, bool printable) { + + ssize_t oldsz = run->dynfile->size; + ssize_t newsz = 0; + + uint64_t choice = util_rndGet(0, 32); + switch (choice) { + + case 0: /* Set new size arbitrarily */ + newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz); + break; + case 1 ... 4: /* Increase size by a small value */ + newsz = oldsz + (ssize_t)util_rndGet(0, 8); + break; + case 5: /* Increase size by a larger value */ + newsz = oldsz + (ssize_t)util_rndGet(9, 128); + break; + case 6 ... 9: /* Decrease size by a small value */ + newsz = oldsz - (ssize_t)util_rndGet(0, 8); + break; + case 10: /* Decrease size by a larger value */ + newsz = oldsz - (ssize_t)util_rndGet(9, 128); + break; + case 11 ... 32: /* Do nothing */ + newsz = oldsz; + break; + default: + LOG_F("Illegal value from util_rndGet: %" PRIu64, choice); + break; + + } + + if (newsz < 1) { newsz = 1; } + if (newsz > (ssize_t)run->global->mutate.maxInputSz) { + + newsz = run->global->mutate.maxInputSz; + + } + + input_setSize(run, (size_t)newsz); + if (newsz > oldsz) { + + if (printable) { memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz); } + + } + +} + +void mangle_mangleContent(run_t *run, int speed_factor) { + + static void (*const mangleFuncs[])(run_t * run, bool printable) = { + + mangle_Shrink, mangle_Expand, mangle_Bit, + mangle_IncByte, mangle_DecByte, mangle_NegByte, + mangle_AddSub, mangle_MemSet, mangle_MemClr, + mangle_MemSwap, mangle_MemCopy, mangle_Bytes, + mangle_ASCIINum, mangle_ASCIINumChange, mangle_ByteRepeat, + mangle_Magic, mangle_StaticDict, mangle_ConstFeedbackDict, + mangle_RandomBuf, mangle_Splice, + + }; + + if (run->mutationsPerRun == 0U) { return; } + if (run->dynfile->size == 0U) { + + mangle_Resize(run, /* printable= */ run->global->cfg.only_printable); + + } + + uint64_t changesCnt = run->global->mutate.mutationsPerRun; + + if (speed_factor < 5) { + + changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun); + + } else if (speed_factor < 10) { + + changesCnt = run->global->mutate.mutationsPerRun; + + } else { + + changesCnt = HF_MIN(speed_factor, 10); + changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5)); + + } + + /* If last coverage acquisition was more than 5 secs ago, use splicing more + * frequently */ + if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) { + + if (util_rnd64() & 0x1) { + + mangle_Splice(run, run->global->cfg.only_printable); + } - uint64_t changesCnt = run->global->mutate.mutationsPerRun; + } + + for (uint64_t x = 0; x < changesCnt; x++) { + + if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) { + + /* + * mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback + * dictionary exists. If so, give it 50% chance of being used among all + * mangling functions. + */ + mangle_ConstFeedbackDict( + run, /* printable= */ run->global->cfg.only_printable); - if (speed_factor < 5) { - changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun); - } else if (speed_factor < 10) { - changesCnt = run->global->mutate.mutationsPerRun; } else { - changesCnt = HF_MIN(speed_factor, 10); - changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5)); - } - /* If last coverage acquisition was more than 5 secs ago, use splicing more frequently */ - if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) { - if (util_rnd64() & 0x1) { - mangle_Splice(run, run->global->cfg.only_printable); - } - } + uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1); + mangleFuncs[choice](run, + /* printable= */ run->global->cfg.only_printable); - for (uint64_t x = 0; x < changesCnt; x++) { - if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) { - /* - * mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback dictionary - * exists. If so, give it 50% chance of being used among all mangling functions. - */ - mangle_ConstFeedbackDict(run, /* printable= */ run->global->cfg.only_printable); - } else { - uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1); - mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable); - } } - wmb(); + } + + wmb(); + } + diff --git a/custom_mutators/radamsa/custom_mutator_helpers.h b/custom_mutators/radamsa/custom_mutator_helpers.h deleted file mode 120000 index f7532ef9..00000000 --- a/custom_mutators/radamsa/custom_mutator_helpers.h +++ /dev/null @@ -1 +0,0 @@ -../examples/custom_mutator_helpers.h \ No newline at end of file diff --git a/custom_mutators/radamsa/radamsa-mutator.c b/custom_mutators/radamsa/radamsa-mutator.c index 624ace3d..466bb5c3 100644 --- a/custom_mutators/radamsa/radamsa-mutator.c +++ b/custom_mutators/radamsa/radamsa-mutator.c @@ -1,6 +1,5 @@ // This simple example just creates random buffer <= 100 filled with 'A' // needs -I /path/to/AFLplusplus/include -//#include "custom_mutator_helpers.h" #include <stdint.h> #include <stdlib.h> @@ -8,19 +7,17 @@ #include <stdio.h> #include "radamsa.h" -#include "custom_mutator_helpers.h" +#include "afl-fuzz.h" typedef struct my_mutator { - afl_t *afl; - - u8 *mutator_buf; - + afl_state_t *afl; + u8 *mutator_buf; unsigned int seed; } my_mutator_t; -my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) { +my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { srand(seed); my_mutator_t *data = calloc(1, sizeof(my_mutator_t)); diff --git a/docs/Changelog.md b/docs/Changelog.md index f33acff9..20b915fa 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -5,10 +5,19 @@ ### Version ++4.07a (dev) - afl-fuzz: + - reverse reading the seeds only on restarts (increases performance) - new env `AFL_POST_PROCESS_KEEP_ORIGINAL` to keep the orignal - data before post process on finds + data before post process on finds (for atnwalk custom mutator) + - new env `AFL_IGNORE_PROBLEMS_COVERAGE` to ignore coverage from + loaded libs after forkserver initialization (required by Mozilla) + - afl-cc: + - new env `AFL_LLVM_LTO_SKIPINIT` to support the AFL++ based WASM + (https://github.com/fgsect/WAFL) project - afl-showmap: - added custom mutator post_process and send support + - add `-I filelist` option, an alternative to `-i in_dir` + - afl-cmin + afl-cmin.bash: + - `-T threads` parallel task support, can be a huge speedup! - a new grammar custom mutator atnwalk was submitted by @voidptr127 ! diff --git a/docs/FAQ.md b/docs/FAQ.md index 4a9080f8..76350c79 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -229,7 +229,8 @@ If you find an interesting or important question missing, submit it via If this is not a viable option, you can set `AFL_IGNORE_PROBLEMS=1` but then the existing map will be used also for the newly loaded libraries, which allows it to work, however, the efficiency of the fuzzing will be partially - degraded. + degraded. Note that there is additionally `AFL_IGNORE_PROBLEMS_COVERAGE` to + additionally tell AFL++ to ignore any coverage from the late loaded libaries. </p></details> <details> diff --git a/docs/env_variables.md b/docs/env_variables.md index c5995d13..b1f23159 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -156,7 +156,7 @@ Available options: - LTO - LTO instrumentation - NATIVE - clang's original pcguard based instrumentation - NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16) - - PCGUARD - our own pcgard based instrumentation (default) + - PCGUARD - our own pcguard based instrumentation (default) #### CMPLOG @@ -240,7 +240,9 @@ combined. the default `0x10000`. A value of 0 or empty sets the map address to be dynamic (the original AFL way, which is slower). - `AFL_LLVM_MAP_DYNAMIC` sets the shared memory address to be dynamic. - + - `AFL_LLVM_LTO_SKIPINIT` skips adding initialization code. Some global vars + (e.g. the highest location ID) are not injected. Needed to instrument with + [WAFL](https://github.com/fgsect/WAFL.git). For more information, see [instrumentation/README.lto.md](../instrumentation/README.lto.md). @@ -404,7 +406,8 @@ checks or alter some of the more exotic semantics of the tool: - If afl-fuzz encounters an incorrect fuzzing setup during a fuzzing session (not at startup), it will terminate. If you do not want this, then you can - set `AFL_IGNORE_PROBLEMS`. + set `AFL_IGNORE_PROBLEMS`. If you additionally want to also ignore coverage + from late loaded libraries, you can set `AFL_IGNORE_PROBLEMS_COVERAGE`. - When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the fuzzer to import test cases from other instances before doing anything else. diff --git a/include/envs.h b/include/envs.h index 23599b26..fe5ee0e3 100644 --- a/include/envs.h +++ b/include/envs.h @@ -106,6 +106,7 @@ static char *afl_environment_variables[] = { "AFL_HARDEN", "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES", "AFL_IGNORE_PROBLEMS", + "AFL_IGNORE_PROBLEMS_COVERAGE", "AFL_IGNORE_TIMEOUTS", "AFL_IGNORE_UNKNOWN_ENVS", "AFL_IMPORT_FIRST", @@ -160,8 +161,9 @@ static char *afl_environment_variables[] = { "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", "AFL_TRY_AFFINITY", - "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", + "AFL_LLVM_LTO_SKIPINIT" + "AFL_LLVM_LTO_STARTID", "AFL_NO_ARITH", "AFL_NO_AUTODICT", "AFL_NO_BUILTIN", diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index e41f19b6..42583f9e 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1005,7 +1005,8 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( // afl++ START if (dFile.is_open()) dFile.close(); - if (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr) { + if (!getenv("AFL_LLVM_LTO_SKIPINIT") && + (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr)) { // yes we could create our own function, insert it into ctors ... // but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index e0e40983..0912e52b 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1563,17 +1563,27 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { "[-] FATAL: forkserver is already up, but an instrumented dlopen() " "library loaded afterwards. You must AFL_PRELOAD such libraries to " "be able to fuzz them or LD_PRELOAD to run outside of afl-fuzz.\n" - "To ignore this set AFL_IGNORE_PROBLEMS=1 but this will be bad for " - "coverage.\n"); + "To ignore this set AFL_IGNORE_PROBLEMS=1 but this will lead to " + "ambiguous coverage data.\n" + "In addition, you can set AFL_IGNORE_PROBLEMS_COVERAGE=1 to " + "ignore the additional coverage instead (use with caution!).\n"); abort(); } else { + u8 ignore_dso_after_fs = !!getenv("AFL_IGNORE_PROBLEMS_COVERAGE"); + if (__afl_debug && ignore_dso_after_fs) { + + fprintf(stderr, "Ignoring coverage from dynamically loaded code\n"); + + } + static u32 offset = 5; while (start < stop) { - if (likely(inst_ratio == 100) || R(100) < inst_ratio) { + if (!ignore_dso_after_fs && + (likely(inst_ratio == 100) || R(100) < inst_ratio)) { *(start++) = offset; diff --git a/src/afl-cc.c b/src/afl-cc.c index 7f15ad76..d1001187 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -2099,6 +2099,8 @@ int main(int argc, char **argv, char **envp) { "bb\n" " AFL_REAL_LD: use this lld linker instead of the compiled in " "path\n" + " AFL_LLVM_LTO_SKIPINIT: don't inject initialization code " + "(used in WAFL mode)\n" "If anything fails - be sure to read README.lto.md!\n"); #endif diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 01d1e82e..bd591c8f 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -718,10 +718,21 @@ void read_testcases(afl_state_t *afl, u8 *directory) { if (nl_cnt) { - i = nl_cnt; + u32 done = 0; + + if (unlikely(afl->in_place_resume)) { + + i = nl_cnt; + + } else { + + i = 0; + + } + do { - --i; + if (unlikely(afl->in_place_resume)) { --i; } struct stat st; u8 dfn[PATH_MAX]; @@ -745,7 +756,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) { free(nl[i]); /* not tracked */ read_testcases(afl, fn2); ck_free(fn2); - continue; + goto next_entry; } @@ -754,7 +765,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) { if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { ck_free(fn2); - continue; + goto next_entry; } @@ -801,18 +812,18 @@ void read_testcases(afl_state_t *afl, u8 *directory) { } - /* - if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { + next_entry: + if (unlikely(afl->in_place_resume)) { - u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, - HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE; - afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1; + if (unlikely(i == 0)) { done = 1; } - } + } else { + + if (unlikely(++i >= (u32)nl_cnt)) { done = 1; } - */ + } - } while (i > 0); + } while (!done); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index ebdbb3fa..71d2afd8 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -259,6 +259,8 @@ static void usage(u8 *argv0, int more_help) { "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n" "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n" "AFL_IGNORE_PROBLEMS: do not abort fuzzing if an incorrect setup is detected\n" + "AFL_IGNORE_PROBLEMS_COVERAGE: if set in addition to AFL_IGNORE_PROBLEMS - also\n" + " ignore those libs for coverage\n" "AFL_IGNORE_TIMEOUTS: do not process or save any timeouts\n" "AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n" "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n" diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 0b9fc211..d0e01cb1 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -69,7 +69,9 @@ static afl_state_t *afl; static char *stdin_file; /* stdin file */ static u8 *in_dir = NULL, /* input folder */ - *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */ + *out_file = NULL, /* output file or directory */ + *at_file = NULL, /* Substitution string for @@ */ + *in_filelist = NULL; /* input file list */ static u8 outfile[PATH_MAX]; @@ -878,6 +880,103 @@ u32 execute_testcases(u8 *dir) { } +u32 execute_testcases_filelist(u8 *fn) { + + u32 done = 0; + u8 buf[4096]; + u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX]; + FILE *f; + + if (!be_quiet) { ACTF("Reading from '%s'...", fn); } + + if ((f = fopen(fn, "r")) == NULL) { FATAL("could not open '%s'", fn); } + + while (fgets(buf, sizeof(buf), f) != NULL) { + + struct stat st; + u8 *fn2 = buf, *fn3; + + while (*fn2 == ' ') { + + ++fn2; + + } + + while (*fn2 && + (fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' || + fn2[strlen(fn2) - 1] == ' ')) { + + fn2[strlen(fn2) - 1] = 0; + + } + + if (debug) { printf("Getting coverage for '%s'\n", fn2); } + + if (!*fn2) { continue; } + + if (lstat(fn2, &st) || access(fn2, R_OK)) { + + WARNF("Unable to access '%s'", fn2); + continue; + + } + + ++done; + + if (!S_ISREG(st.st_mode) || !st.st_size) { continue; } + + if ((fn3 = strrchr(fn2, '/'))) { + + ++fn3; + + } else { + + fn3 = fn2; + + } + + if (st.st_size > MAX_FILE && !be_quiet && !quiet_mode) { + + WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", 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)); + + } + + if (!collect_coverage) { + + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, fn3); + + } + + if (read_file(fn2)) { + + if (wait_for_gdb) { + + fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid); + fprintf(stderr, "exec: kill -CONT %d\n", getpid()); + kill(0, SIGSTOP); + + } + + showmap_run_target_forkserver(fsrv, in_data, in_len); + ck_free(in_data); + + if (child_crashed && debug) { WARNF("crashed: %s", fn2); } + + if (collect_coverage) + analyze_results(fsrv); + else + tcnt = write_results_to_file(fsrv, outfile); + + } + + } + + return done; + +} + /* Show banner. */ static void show_banner(void) { @@ -920,6 +1019,7 @@ static void usage(u8 *argv0) { " With -C, -o is a file, without -C it must be a " "directory\n" " and each bitmap will be written there individually.\n" + " -I filelist - alternatively to -i, -I is a list of files\n" " -C - collect coverage, writes all edges to -o and gives a " "summary\n" " Must be combined with -i.\n" @@ -932,7 +1032,7 @@ static void usage(u8 *argv0) { "This tool displays raw tuple data captured by AFL instrumentation.\n" "For additional help, consult %s/README.md.\n\n" - "If you use -i mode, then custom mutator post_process send send " + "If you use -i/-I mode, then custom mutator post_process send send " "functionality\n" "is supported.\n\n" @@ -994,7 +1094,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) { + while ((opt = getopt(argc, argv, "+i:I:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) { switch (opt) { @@ -1012,6 +1112,11 @@ int main(int argc, char **argv_orig, char **envp) { in_dir = optarg; break; + case 'I': + if (in_filelist) { FATAL("Multiple -I options not supported"); } + in_filelist = optarg; + break; + case 'o': if (out_file) { FATAL("Multiple -o options not supported"); } @@ -1234,10 +1339,12 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !out_file) { usage(argv[0]); } - if (in_dir) { + if (in_dir && in_filelist) { FATAL("you can only specify either -i or -I"); } + + if (in_dir || in_filelist) { if (!out_file && !collect_coverage) - FATAL("for -i you need to specify either -C and/or -o"); + FATAL("for -i/-I you need to specify either -C and/or -o"); } @@ -1294,7 +1401,7 @@ int main(int argc, char **argv_orig, char **envp) { } - if (in_dir) { + if (in_dir || in_filelist) { /* If we don't have a file name chosen yet, use a safe default. */ u8 *use_dir = "."; @@ -1400,7 +1507,7 @@ int main(int argc, char **argv_orig, char **envp) { } #ifdef __linux__ - if (!fsrv->nyx_mode && in_dir) { + if (!fsrv->nyx_mode && (in_dir || in_filelist)) { (void)check_binary_signatures(fsrv->target_path); @@ -1483,7 +1590,7 @@ int main(int argc, char **argv_orig, char **envp) { } - if (in_dir) { + if (in_dir || in_filelist) { afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY); afl->afl_env.afl_custom_mutator_library = @@ -1496,33 +1603,46 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_CUSTOM_MUTATOR_LIBRARY") || getenv("AFL_PYTHON_MODULE")) { WARNF( - "Custom mutator environment detected, this is only supported in -i " - "mode!\n"); + "Custom mutator environment detected, this is only supported in " + "-i/-I mode!\n"); } } - if (in_dir) { + if (in_dir || in_filelist) { DIR *dir_in, *dir_out = NULL; + u8 *dn = NULL; if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } - // if a queue subdirectory exists switch to that - u8 *dn = alloc_printf("%s/queue", in_dir); - if ((dir_in = opendir(dn)) != NULL) { + if (in_filelist) { + + if (!be_quiet) ACTF("Reading from file list '%s'...", in_filelist); + + } else { + + // if a queue subdirectory exists switch to that + dn = alloc_printf("%s/queue", in_dir); + + if ((dir_in = opendir(dn)) != NULL) { + + closedir(dir_in); + in_dir = dn; + + } else { + + ck_free(dn); - closedir(dir_in); - in_dir = dn; + } - } else + if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir); - ck_free(dn); - if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir); + } if (!collect_coverage) { @@ -1576,9 +1696,21 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - if (execute_testcases(in_dir) == 0) { + if (in_dir) { + + if (execute_testcases(in_dir) == 0) { + + FATAL("could not read input testcases from %s", in_dir); + + } + + } else { - FATAL("could not read input testcases from %s", in_dir); + if (execute_testcases_filelist(in_filelist) == 0) { + + FATAL("could not read input testcases from %s", in_filelist); + + } } |