diff --git a/.custom-format.py b/.custom-format.py index e787df28..9899ea9d 100755 --- a/.custom-format.py +++ b/.custom-format.py @@ -21,12 +21,15 @@ import os # import re # TODO: for future use import shutil import importlib.metadata +import hashlib # string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use CURRENT_LLVM = os.getenv('LLVM_VERSION', 18) CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "") +FORMAT_CACHE_DIR = '.format-cache' +os.makedirs(FORMAT_CACHE_DIR, exist_ok=True) def check_clang_format_pip_version(): """ @@ -69,6 +72,8 @@ to install via pip.") if CLANG_FORMAT_PIP: CLANG_FORMAT_BIN = shutil.which("clang-format") +CLANG_FORMAT_VERSION = subprocess.check_output([CLANG_FORMAT_BIN, '--version']) + COLUMN_LIMIT = 80 for line in fmt.split("\n"): line = line.split(":") @@ -86,9 +91,10 @@ def custom_format(filename): out = "" for line in src.split("\n"): + define_start = False if line.lstrip().startswith("#"): if line[line.find("#") + 1:].lstrip().startswith("define"): - in_define = True + define_start = True if ( "/*" in line @@ -126,9 +132,7 @@ def custom_format(filename): and last_line.strip() != "" ): line = (" " * define_padding + "\\" if in_define else "") + "\n" + line - - if not line.endswith("\\"): - in_define = False + in_define = (define_start or in_define) and line.endswith("\\") out += line + "\n" last_line = line @@ -136,6 +140,38 @@ def custom_format(filename): return out +def hash_code_and_formatter(code): + hasher = hashlib.sha256() + + hasher.update(code.encode()) + hasher.update(CLANG_FORMAT_VERSION) + with open(__file__, 'rb') as f: + hasher.update(f.read()) + + return hasher.hexdigest() + + +def custom_format_cached(filename): + filename_hash = hashlib.sha256(filename.encode()).hexdigest() + cache_file = os.path.join(FORMAT_CACHE_DIR, filename_hash) + + if os.path.exists(cache_file): + with open(filename) as f: + code = f.read() + code_hash = hash_code_and_formatter(code) + with open(cache_file) as f: + if f.read() == code_hash: + return code + + code = custom_format(filename) + + code_hash = hash_code_and_formatter(code) + with open(cache_file, 'w') as f: + f.write(code_hash) + + return code + + args = sys.argv[1:] if len(args) == 0: print("Usage: ./format.py [-i] ") @@ -151,7 +187,7 @@ if args[0] == "-i": args = args[1:] for filename in args: - code = custom_format(filename) + code = custom_format_cached(filename) if in_place: with open(filename, "w") as f: f.write(code) diff --git a/.github/workflows/rust_custom_mutator.yml b/.github/workflows/rust_custom_mutator.yml index 7c2f0c12..f5c16a1e 100644 --- a/.github/workflows/rust_custom_mutator.yml +++ b/.github/workflows/rust_custom_mutator.yml @@ -18,7 +18,7 @@ jobs: working-directory: custom_mutators/rust strategy: matrix: - os: [ubuntu-22.04, ubuntu-20.04] + os: [ubuntu-22.04] steps: - uses: actions/checkout@v3 - name: Install Rust Toolchain diff --git a/.gitignore b/.gitignore index bc06ef2d..4f25e5e4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.so *.swp .DS_Store +.format-cache .sync_tmp .test .test2 @@ -113,4 +114,4 @@ utils/replay_record/persistent_demo_replay_argparse utils/plot_ui/afl-plot-ui vuln_prog argv_fuzz_demo -argv_fuzz_persistent_demo \ No newline at end of file +argv_fuzz_persistent_demo diff --git a/GNUmakefile b/GNUmakefile index 8e3ec16d..e00ff591 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -473,7 +473,7 @@ ready: @echo "[+] Everything seems to be working, ready to compile. ($(shell $(CC) --version 2>&1|head -n 1))" src/afl-performance.o : $(COMM_HDR) src/afl-performance.c include/hash.h - $(CC) $(CFLAGS) $(CFLAGS_OPT) $(SPECIAL_PERFORMANCE) -Iinclude -c src/afl-performance.c -o src/afl-performance.o + $(CC) $(CFLAGS) $(CFLAGS_FLTO) $(CFLAGS_OPT) $(SPECIAL_PERFORMANCE) -Iinclude -c src/afl-performance.c -o src/afl-performance.o src/afl-common.o : $(COMM_HDR) src/afl-common.c include/common.h $(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-common.c -o src/afl-common.o @@ -490,7 +490,7 @@ ifdef IS_IOS @ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; } endif -afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 +afl-showmap: src/afl-showmap.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) ifdef IS_IOS @ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; } @@ -535,20 +535,20 @@ ifdef IS_IOS endif test/unittests/unit_hash.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_hash.c $(AFL_FUZZ_FILES) src/afl-performance.o - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o + @$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_hash.c -o test/unittests/unit_hash.o unit_hash: test/unittests/unit_hash.o src/afl-performance.o - @$(CC) $(CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + @$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_hash $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_hash ifdef IS_IOS @ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; } endif test/unittests/unit_rand.o : $(COMM_HDR) include/alloc-inl.h test/unittests/unit_rand.c $(AFL_FUZZ_FILES) src/afl-performance.o - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o + @$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -c test/unittests/unit_rand.c -o test/unittests/unit_rand.o unit_rand: test/unittests/unit_rand.o src/afl-common.o src/afl-performance.o - @$(CC) $(CFLAGS) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka + @$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(ASAN_CFLAGS) $(SPECIAL_PERFORMANCE) -Wl,--wrap=exit -Wl,--wrap=printf $^ -o test/unittests/unit_rand $(LDFLAGS) $(ASAN_LDFLAGS) -lcmocka ./test/unittests/unit_rand ifdef IS_IOS @ldid -Sentitlements.plist $@ && echo "[+] Signed $@" || { echo "[-] Failed to sign $@"; } @@ -684,6 +684,7 @@ deepclean: clean rm -rf unicorn_mode/unicornafl rm -rf qemu_mode/qemuafl rm -rf nyx_mode/libnyx nyx_mode/packer nyx_mode/QEMU-Nyx + rm -rf .format-cache ifeq "$(IN_REPO)" "1" git checkout coresight_mode/coresight-trace git checkout unicorn_mode/unicornafl diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 653d3b68..73ec7cf7 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -240,7 +240,7 @@ ifeq "$(LLVM_LTO)" "1" else ifneq "$(shell command -v ld.lld 2>/dev/null)" "" AFL_REAL_LD = $(shell command -v ld.lld) - TMP_LDLDD_VERSION = $(shell $(AFL_REAL_LD) --version | awk '{ print $$2 }') + TMP_LDLDD_VERSION = $(shell $(AFL_REAL_LD) --version | sed -E -ne '/^.*LLD\ ([12]?[0-9]\.[0-9]\.[0-9]).*/s//\1/p') ifeq "$(LLVMVER)" "$(TMP_LDLDD_VERSION)" $(warning ld.lld found in a weird location ($(AFL_REAL_LD)), but its the same version as LLVM so we will allow it) else diff --git a/afl-cmin b/afl-cmin index a88460a8..49e77b58 100755 --- a/afl-cmin +++ b/afl-cmin @@ -432,7 +432,7 @@ BEGIN { } else { stat_format = "-f '%z %N'" # *BSD, MacOS } - cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r) | grep -Ev '^0'" + cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o \\( -type f -a ! -name \"cmdline\" -a ! -name \"fastresume.bin\" -a ! -name \"fuzz_bitmap\" -a ! -name \"fuzzer_setup\" -a ! -name \"fuzzer_stats\" -a ! -name \"plot_data\" -a ! -name \"target_hash\" \\) -exec stat "stat_format" \\{\\} + | sort -k1n -k2r) | grep -Ev '^0'" #cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r" diff --git a/afl-persistent-config b/afl-persistent-config index dede032f..da67bf16 100755 --- a/afl-persistent-config +++ b/afl-persistent-config @@ -121,6 +121,7 @@ kernel.sched_child_runs_first=1 kernel.sched_autogroup_enabled=1 kernel.sched_migration_cost_ns=50000000 kernel.sched_latency_ns=250000000 +vm.swappiness=10 EOF } @@ -129,7 +130,7 @@ EOF if ! grep -E "^$KEY=" /etc/default/grub | grep -E -q 'noibrs pcid nopti'; then echo "Configuring performance boot options" LINE=`grep -E "^$KEY=" /etc/default/grub | sed "s/^$KEY=//" | tr -d '"'` - OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off spec_rstack_overflow=off mds=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off" + OPTIONS="$LINE ibpb=off ibrs=off kpti=off l1tf=off spec_rstack_overflow=off mds=off nokaslr no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off" echo Setting boot options in /etc/default/grub to $KEY=\"$OPTIONS\" sed -i "s|^$KEY=.*|$KEY=\"$OPTIONS\"|" /etc/default/grub fi diff --git a/afl-system-config b/afl-system-config index 7e2cb688..5a194412 100755 --- a/afl-system-config +++ b/afl-system-config @@ -41,6 +41,7 @@ if [ "$PLATFORM" = "Linux" ] ; then sysctl -w kernel.sched_autogroup_enabled=1 sysctl -w kernel.sched_migration_cost_ns=50000000 2>/dev/null sysctl -w kernel.sched_latency_ns=250000000 2>/dev/null + sysctl -w vm.swappiness=10 2>/dev/null echo never > /sys/kernel/mm/transparent_hugepage/enabled test -e /sys/devices/system/cpu/cpufreq/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/scaling_governor test -e /sys/devices/system/cpu/cpufreq/policy0/scaling_governor && echo performance | tee /sys/devices/system/cpu/cpufreq/policy*/scaling_governor @@ -54,7 +55,7 @@ if [ "$PLATFORM" = "Linux" ] ; then echo dmesg | grep -E -q 'noibrs pcid nopti' || { echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this: - echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=0 l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx_async_abort=off arm64.nopauth audit=0 hardened_usercopy=off ssbd=force-off"' + echo ' /etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off spec_rstack_overflow=off mds=off nokaslr no_stf_barrier noibpb noibrs pcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=on pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off srbds=off noexec=off noexec32=off tsx=on tsx=on tsx_async_abort=off mitigations=off audit=0 hardened_usercopy=off ssbd=force-off"' echo } echo If you run fuzzing instances in docker, run them with \"--security-opt seccomp=unconfined\" for more speed. diff --git a/docs/Changelog.md b/docs/Changelog.md index 1802b355..f34d5437 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -6,6 +6,14 @@ ### Version ++4.32a (dev) - Fixed a bug where after a fast restart of a full fuzzed corpus afl-fuzz terminates with "need at least one valid input seed that does not crash" + - Small improvements to afl-*-config + - afl-fuzz: + - memory leak fixes by @kcwu - thanks! + - some more nits and small memory saves thanks to @kcwu + - remove deprecated files from queue/.state + - fix bitmap update function if no current trace is present + - frida_mode: + - fixes for new MacOS + M4 hardware ### Version ++4.31c (release) diff --git a/docs/FAQ.md b/docs/FAQ.md index ca857a5b..cc88cdc6 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -236,7 +236,7 @@ If you find an interesting or important question missing, submit it via [AFLFast](https://github.com/mboehme/aflfast), however, modified to be more effective and several more modes added. - The most effective modes are `-p fast` (default) and `-p explore`. + The most effective modes are `-p explore` (default) and `-p fast`. If you fuzz with several parallel afl-fuzz instances, then it is beneficial to assign a different schedule to each instance, however the majority should diff --git a/docs/afl-fuzz_approach.md b/docs/afl-fuzz_approach.md index 4ebce154..58553fbd 100644 --- a/docs/afl-fuzz_approach.md +++ b/docs/afl-fuzz_approach.md @@ -385,10 +385,6 @@ there are several things to look at: subsequent iterations (e.g., due to incomplete clean-up or reinitialization of the state) and that most of the fuzzing effort goes to waste. -The paths where variable behavior is detected are marked with a matching entry -in the `/queue/.state/variable_behavior/` directory, so you can look -them up easily. - ### CPU load ``` diff --git a/docs/fuzzing_in_depth.md b/docs/fuzzing_in_depth.md index 5e5b8629..fea9ca0b 100644 --- a/docs/fuzzing_in_depth.md +++ b/docs/fuzzing_in_depth.md @@ -247,6 +247,12 @@ CFISAN. You might need to experiment which sanitizers you can combine in a target (which means more instances can be run without a sanitized target, which is more effective). +Note that some sanitizers (MSAN and LSAN) exit with a particular exit code +instead of aborting. afl-fuzz treats these exit codes as a crash when these +sanitizers are enabled. If the target uses these exit codes there could be false +positives among the saved crashes. LSAN uses exit code 23 and MSAN uses exit +code 86. + ### d) Modifying the target If the target has features that make fuzzing more difficult, e.g., checksums, @@ -496,6 +502,8 @@ Note: protection against attacks! So set strong firewall rules and only expose SSH as a network service if you use these (which is highly recommended). +If you execute afl-fuzz in a Docker container, it is recommended to pass [`--cpuset-cpus`](https://docs.docker.com/engine/containers/resource_constraints/#configure-the-default-cfs-scheduler) option with free CPU cores to docker daemon when starting the container, or pass `AFL_NO_AFFINITY` to afl-fuzz. This is due to the fact that AFL++ will bind to a free CPU core by default, while Docker container will prevent AFL++ instance from seeing processes in other containers or host, which leads to all AFL++ instances trying to bind the same CPU core. + If you have an input corpus from [step 2](#2-preparing-the-fuzzing-campaign), then specify this directory with the `-i` option. Otherwise, create a new directory and create a file with any content as test data in there. diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index 545cde4f..4ee2b40a 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -190,12 +190,25 @@ GUM_DEVKIT_VERSION=16.1.11 GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)" -IS_GUM_16_6_PLUS := $(shell VERSION="$(GUM_DEVKIT_VERSION)"; \ - MAJOR=$${VERSION%%.*}; \ - MINOR=$${VERSION#*.}; MINOR=$${MINOR%%.*}; \ - if [ $$MAJOR -gt 16 ] || { [ $$MAJOR -eq 16 ] && [ $$MINOR -ge 6 ]; }; then \ - echo 1; \ - fi) +ifeq ($(OS),macos) + # Extract the major version + GUM_VERSION_MAJOR := $(shell echo "$(GUM_DEVKIT_VERSION)" | sed -E 's/\..*//') + # Extract the minor version (assumes format "MAJOR.MINOR[.PATCH...]") + GUM_VERSION_MINOR := $(shell echo "$(GUM_DEVKIT_VERSION)" | sed -E 's/^[^.]*\.//; s/\..*//') + + # Evaluate the version condition in a separate shell call + IS_GUM_16_6_PLUS := $(shell \ + if (( $(GUM_VERSION_MAJOR) > 16 || ( $(GUM_VERSION_MAJOR) == 16 && $(GUM_VERSION_MINOR) >= 6 ) )); then \ + echo 1; \ + fi) +else + IS_GUM_16_6_PLUS := $(shell VERSION="$(GUM_DEVKIT_VERSION)"; \ + MAJOR=$${VERSION%%.*}; \ + MINOR=$${VERSION#*.}; MINOR=$${MINOR%%.*}; \ + if [ $$MAJOR -gt 16 ] || { [ $$MAJOR -eq 16 ] && [ $$MINOR -ge 6 ]; }; then \ + echo 1; \ + fi) +endif CFLAGS += $(if $(IS_GUM_16_6_PLUS),-DGUM_16_6_PLUS) diff --git a/frida_mode/src/asan/asan.c b/frida_mode/src/asan/asan.c index 66ff7eac..e89c0d62 100644 --- a/frida_mode/src/asan/asan.c +++ b/frida_mode/src/asan/asan.c @@ -28,11 +28,10 @@ void asan_init(void) { } #ifdef GUM_16_6_PLUS -static gboolean asan_exclude_module(GumModule *module, - gpointer user_data) { +static gboolean asan_exclude_module(GumModule *module, gpointer user_data) { - gchar *symbol_name = (gchar *)user_data; - GumAddress address; + gchar *symbol_name = (gchar *)user_data; + GumAddress address; const GumMemoryRange *range = gum_module_get_range(module); address = gum_module_find_export_by_name(module, symbol_name); @@ -41,14 +40,13 @@ static gboolean asan_exclude_module(GumModule *module, /* If the reported address of the symbol is outside of the range of the module * then ignore it */ if (address < range->base_address) { return TRUE; } - if (address > (range->base_address + range->size)) { - return TRUE; - } + if (address > (range->base_address + range->size)) { return TRUE; } - ranges_add_exclude((GumMemoryRange *) range); + ranges_add_exclude((GumMemoryRange *)range); return FALSE; } + #else static gboolean asan_exclude_module(const GumModuleDetails *details, gpointer user_data) { @@ -72,6 +70,7 @@ static gboolean asan_exclude_module(const GumModuleDetails *details, return FALSE; } + #endif void asan_exclude_module_by_symbol(gchar *symbol_name) { @@ -79,3 +78,4 @@ void asan_exclude_module_by_symbol(gchar *symbol_name) { gum_process_enumerate_modules(asan_exclude_module, symbol_name); } + diff --git a/frida_mode/src/lib/lib.c b/frida_mode/src/lib/lib.c index f774333d..c5a1e16e 100644 --- a/frida_mode/src/lib/lib.c +++ b/frida_mode/src/lib/lib.c @@ -39,13 +39,12 @@ typedef struct { static guint64 text_base = 0; static guint64 text_limit = 0; -#ifdef GUM_16_6_PLUS -static gboolean lib_find_exe(GumModule *module, - gpointer user_data) { + #ifdef GUM_16_6_PLUS +static gboolean lib_find_exe(GumModule *module, gpointer user_data) { - lib_details_t *lib_details = (lib_details_t *)user_data; - const gchar *name = gum_module_get_name(module); - const gchar *path = gum_module_get_path(module); + lib_details_t *lib_details = (lib_details_t *)user_data; + const gchar *name = gum_module_get_name(module); + const gchar *path = gum_module_get_path(module); const GumMemoryRange *range = gum_module_get_range(module); strncpy(lib_details->name, name, PATH_MAX); @@ -57,7 +56,8 @@ static gboolean lib_find_exe(GumModule *module, return FALSE; } -#else + + #else static gboolean lib_find_exe(const GumModuleDetails *details, gpointer user_data) { @@ -72,7 +72,8 @@ static gboolean lib_find_exe(const GumModuleDetails *details, return FALSE; } -#endif + + #endif static void lib_validate_hdr(Elf_Ehdr *hdr) { @@ -210,3 +211,4 @@ guint64 lib_get_text_limit(void) { } #endif + diff --git a/frida_mode/src/lib/lib_apple.c b/frida_mode/src/lib/lib_apple.c index 5046c34f..6498f674 100644 --- a/frida_mode/src/lib/lib_apple.c +++ b/frida_mode/src/lib/lib_apple.c @@ -12,16 +12,15 @@ extern void gum_darwin_enumerate_modules(mach_port_t task, static guint64 text_base = 0; static guint64 text_limit = 0; -#ifdef GUM_16_6_PLUS -static gboolean lib_get_main_module(GumModule *module, - gpointer user_data) { + #ifdef GUM_16_6_PLUS +static gboolean lib_get_main_module(GumModule *module, gpointer user_data) { - GumDarwinModule **ret = (GumDarwinModule **)user_data; - const gchar *path = gum_module_get_path(module); + GumDarwinModule **ret = (GumDarwinModule **)user_data; + const gchar *path = gum_module_get_path(module); const GumMemoryRange *range = gum_module_get_range(module); - GumDarwinModule *darwin_module = gum_darwin_module_new_from_memory( - path, mach_task_self(), range->base_address, - GUM_DARWIN_MODULE_FLAGS_NONE, NULL); + GumDarwinModule *darwin_module = gum_darwin_module_new_from_memory( + path, mach_task_self(), range->base_address, GUM_DARWIN_MODULE_FLAGS_NONE, + NULL); FVERBOSE("Found main module: %s", darwin_module->name); @@ -30,7 +29,8 @@ static gboolean lib_get_main_module(GumModule *module, return FALSE; } -#else + + #else static gboolean lib_get_main_module(const GumModuleDetails *details, gpointer user_data) { @@ -46,7 +46,8 @@ static gboolean lib_get_main_module(const GumModuleDetails *details, return FALSE; } -#endif + + #endif gboolean lib_get_text_section(const GumDarwinSectionDetails *details, gpointer user_data) { @@ -105,3 +106,4 @@ guint64 lib_get_text_limit(void) { } #endif + diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c index 74291859..9d14fb6e 100644 --- a/frida_mode/src/prefetch.c +++ b/frida_mode/src/prefetch.c @@ -262,6 +262,7 @@ static int prefetch_on_fork(void) { } static void prefetch_hook_fork(void) { + #ifdef GUM_16_6_PLUS void *fork_addr = GSIZE_TO_POINTER(gum_module_find_global_export_by_name("fork")); @@ -305,3 +306,4 @@ void prefetch_init(void) { iface->notify_backpatch = gum_afl_stalker_backpatcher_notify; } + diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index b2df1930..d238eb10 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -118,9 +118,9 @@ static void convert_address_token(gchar *token, GumMemoryRange *range) { #ifdef GUM_16_6_PLUS static gboolean convert_name_token_for_module(GumModule *module, - gpointer user_data) { + gpointer user_data) { - convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data; + convert_name_ctx_t *ctx = (convert_name_ctx_t *)user_data; const GumMemoryRange *range = gum_module_get_range(module); const gchar *path = gum_module_get_path(module); if (path == NULL) { return true; }; @@ -129,14 +129,15 @@ static gboolean convert_name_token_for_module(GumModule *module, FVERBOSE("Found module - prefix: %s, 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x %s", - ctx->suffix, range->base_address, - range->base_address + range->size, path); + ctx->suffix, range->base_address, range->base_address + range->size, + path); *ctx->range = *range; ctx->done = true; return false; } + #else static gboolean convert_name_token_for_module(const GumModuleDetails *details, gpointer user_data) { @@ -156,6 +157,7 @@ static gboolean convert_name_token_for_module(const GumModuleDetails *details, return false; } + #endif static void convert_name_token(gchar *token, GumMemoryRange *range) { @@ -736,3 +738,4 @@ void ranges_exclude() { } } + diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index a96b4873..4729c321 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -353,6 +353,8 @@ enum { }; +#define FAST_RESUME_VERSION 0x01000000 + /* Python stuff */ #ifdef USE_PYTHON @@ -719,6 +721,8 @@ typedef struct afl_state { struct queue_entry **top_rated; /* Top entries for bitmap bytes */ + u32 **top_rated_candidates; /* Candidate IDs per bitmap index */ + struct extra_data *extras; /* Extra tokens to fuzz with */ u32 extras_cnt; /* Total number of tokens read */ @@ -860,6 +864,8 @@ typedef struct afl_state { struct skipdet_global *skipdet_g; + s64 last_scored_idx; /* Index of the last queue entry re-scored */ + #ifdef INTROSPECTION char mutation[8072]; char m_tmp[4096]; @@ -1182,13 +1188,13 @@ void deinit_py(void *); /* Queue */ void mark_as_det_done(afl_state_t *, struct queue_entry *); -void mark_as_variable(afl_state_t *, struct queue_entry *); -void mark_as_redundant(afl_state_t *, struct queue_entry *, u8); void add_to_queue(afl_state_t *, u8 *, u32, u8); void destroy_queue(afl_state_t *); -void update_bitmap_score(afl_state_t *, struct queue_entry *); +void update_bitmap_score(afl_state_t *, struct queue_entry *, bool); void cull_queue(afl_state_t *); u32 calculate_score(afl_state_t *, struct queue_entry *); +void recalculate_all_scores(afl_state_t *); +void update_bitmap_rescore(afl_state_t *, struct queue_entry *, u32); /* Bitmap */ @@ -1338,7 +1344,6 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) { ck_read(afl->fsrv.dev_urandom_fd, &afl->rand_seed, sizeof(afl->rand_seed), "/dev/urandom"); - // srandom(afl->rand_seed[0]); afl->rand_cnt = (RESEED_RNG / 2) + (afl->rand_seed[1] % RESEED_RNG); } @@ -1452,6 +1457,18 @@ static inline int permissive_create(afl_state_t *afl, const char *fn) { } +static inline void bitmap_set(u8 *map, u32 index) { + + map[index / 8] |= (1u << (index % 8)); + +} + +static inline u8 bitmap_read(u8 *map, u32 index) { + + return (map[index / 8] >> (index % 8)) & 1; + +} + #if TESTCASE_CACHE == 1 #error define of TESTCASE_CACHE must be zero or larger than 1 #endif diff --git a/include/android-ashmem.h b/include/android-ashmem.h index 065c213b..8155d35c 100644 --- a/include/android-ashmem.h +++ b/include/android-ashmem.h @@ -31,7 +31,8 @@ int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) { if (__cmd == IPC_RMID) { int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); - struct ashmem_pin pin = {0, length}; + unsigned int safe_length = length >= 0 ? length : 0; + struct ashmem_pin pin = {0, safe_length}; ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); close(__shmid); diff --git a/include/asanfuzz.h b/include/asanfuzz.h index 693a12b3..c82ae3ae 100644 --- a/include/asanfuzz.h +++ b/include/asanfuzz.h @@ -37,11 +37,12 @@ enum SanitizerAbstraction { - SIMPLIFY_TRACE = 0, // Feed all unique trace to sanitizers, the - // most sensitive - UNIQUE_TRACE, + SIMPLIFY_TRACE = 0, // Feed all simplified trace to sanitizers, moderate + // sensitive and default for SAND. Not missing bugs. + UNIQUE_TRACE, // Feed all unique trace to sanitizers, the most sensitive + // and not missing bugs. COVERAGE_INCREASE // Feed all coverage increasing cases to sanitizers, the - // least sensitive + // least sensitive at a risk of missing ~20% bugs. }; diff --git a/include/config.h b/include/config.h index 5ac0540d..b4c0cb54 100644 --- a/include/config.h +++ b/include/config.h @@ -171,7 +171,8 @@ #define EXEC_TM_ROUND 20U /* 64bit arch MACRO */ -#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__)) +#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \ + (defined(__riscv) && __riscv_xlen == 64)) #define WORD_SIZE_64 1 #endif @@ -200,8 +201,8 @@ /* Maximum number of unique hangs or crashes to record: */ -#define KEEP_UNIQUE_HANG 500U -#define KEEP_UNIQUE_CRASH 10000U +#define KEEP_UNIQUE_HANG 512U +#define KEEP_UNIQUE_CRASH 25600U /* Baseline number of random tweaks during a single 'havoc' stage: */ diff --git a/include/coverage-32.h b/include/coverage-32.h index f5b0056f..e26affb0 100644 --- a/include/coverage-32.h +++ b/include/coverage-32.h @@ -7,9 +7,8 @@ #define _AFL_INTSIZEVAR u32 -u32 skim(const u32 *virgin, const u32 *current, const u32 *current_end); -u32 classify_word(u32 word); -void classify_counts_mem(u32 *mem, u32 size); +u32 skim(const u32 *virgin, const u32 *current, const u32 *current_end); +u32 classify_word(u32 word); inline u32 classify_word(u32 word) { @@ -24,22 +23,6 @@ inline u32 classify_word(u32 word) { } -inline void classify_counts_mem(u32 *mem, u32 size) { - - u32 i = (size >> 2); - - while (i--) { - - /* Optimize for sparse bitmaps. */ - - if (unlikely(*mem)) { *mem = classify_word(*mem); } - - mem++; - - } - -} - void simplify_trace(afl_state_t *afl, u8 *bytes) { u32 *mem = (u32 *)bytes; diff --git a/include/coverage-64.h b/include/coverage-64.h index 22aa37f4..7b854958 100644 --- a/include/coverage-64.h +++ b/include/coverage-64.h @@ -11,9 +11,8 @@ #include #endif -u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end); -u64 classify_word(u64 word); -void classify_counts_mem(u64 *mem, u32 size); +u32 skim(const u64 *virgin, const u64 *current, const u64 *current_end); +u64 classify_word(u64 word); inline u64 classify_word(u64 word) { @@ -79,22 +78,6 @@ inline void classify_counts(afl_forkserver_t *fsrv) { } -inline void classify_counts_mem(u64 *mem, u32 size) { - - u32 i = (size >> 3); - - while (i--) { - - /* Optimize for sparse bitmaps. */ - - if (unlikely(*mem)) { *mem = classify_word(*mem); } - - mem++; - - } - -} - /* Updates the virgin bits, then reflects whether a new count or a new tuple is * seen in ret. */ inline void discover_word(u8 *ret, u64 *current, u64 *virgin) { diff --git a/include/forkserver.h b/include/forkserver.h index caea1848..4f574aa1 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -137,6 +137,8 @@ typedef struct afl_forkserver { u8 last_kill_signal; /* Signal that killed the child */ + u8 last_exit_code; /* Child exit code if counted as a crash */ + bool use_shmem_fuzz; /* use shared mem for test cases */ bool support_shmem_fuzz; /* set by afl-fuzz */ @@ -155,7 +157,7 @@ typedef struct afl_forkserver { bool no_unlink; /* do not unlink cur_input */ - bool uses_asan; /* Target uses ASAN? */ + u8 uses_asan; /* Target uses ASAN/LSAN/MSAN? (bit 0/1/2 respectively) */ bool debug; /* debug mode? */ diff --git a/include/xxhash.h b/include/xxhash.h index 72044177..59abd0e9 100644 --- a/include/xxhash.h +++ b/include/xxhash.h @@ -3169,7 +3169,7 @@ static xxh_u32 XXH32_avalanche(xxh_u32 hash) { */ static XXH_PUREF xxh_u32 XXH32_finalize(xxh_u32 hash, const xxh_u8 *ptr, size_t len, XXH_alignment align) { -\ + #define XXH_PROCESS1 \ do { \ \ diff --git a/qemu_mode/README.deferred_initialization_example.md b/qemu_mode/README.deferred_initialization_example.md index d940d6b5..30fe1932 100644 --- a/qemu_mode/README.deferred_initialization_example.md +++ b/qemu_mode/README.deferred_initialization_example.md @@ -40,7 +40,7 @@ ALPINE_ROOT= FUZZ= sudo systemd-nspawn -D $ALPINE_ROOT --bind=$FUZZ:/fuzz CC=$(which clang) CFLAGS="-g" LDSHARED="clang -shared" python3 -m pip install /fuzz -clang $(python3-config --embed --cflags) $(python3-config --embed --ldflags) -o /fuzz/fuzz_harness /fuzz/fuzz_harness.c +clang $(python3-config --embed --cflags) -o /fuzz/fuzz_harness /fuzz/fuzz_harness.c $(python3-config --embed --ldflags) exit ``` diff --git a/src/afl-cc.c b/src/afl-cc.c index 12a361a8..d91b9194 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -187,9 +187,6 @@ typedef struct aflcc_state { u8 need_aflpplib; int passthrough; - u8 use_stdin; /* dummy */ - u8 *argvnull; /* dummy */ - } aflcc_state_t; void aflcc_state_init(aflcc_state_t *, u8 *argv0); @@ -2033,8 +2030,10 @@ void add_sanitizers(aflcc_state_t *aflcc, char **envp) { } if (getenv("AFL_USE_RTSAN") && !aflcc->have_rtsan) { + insert_param(aflcc, "-fsanitize=realtime"); aflcc->have_rtsan = 1; + } if (getenv("AFL_USE_CFISAN") || aflcc->have_cfisan) { diff --git a/src/afl-common.c b/src/afl-common.c index 892745a7..736c9f3d 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -977,11 +977,10 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) { inline u64 get_cur_time(void) { - struct timeval tv; - struct timezone tz; + struct timeval tv; // TO NOT REPLACE WITH clock_gettime!!! - gettimeofday(&tv, &tz); + gettimeofday(&tv, NULL); return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000); @@ -991,11 +990,10 @@ inline u64 get_cur_time(void) { inline u64 get_cur_time_us(void) { - struct timeval tv; - struct timezone tz; + struct timeval tv; // TO NOT REPLACE WITH clock_gettime!!! - gettimeofday(&tv, &tz); + gettimeofday(&tv, NULL); return (tv.tv_sec * 1000000ULL) + tv.tv_usec; @@ -1006,7 +1004,7 @@ inline u64 get_cur_time_us(void) { Will return buf for convenience. */ u8 *stringify_int(u8 *buf, size_t len, u64 val) { -\ + #define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \ do { \ \ @@ -1170,7 +1168,7 @@ u8 *stringify_time_diff(u8 *buf, size_t len, u64 cur_ms, u64 event_ms) { Will return buf for convenience. */ u8 *u_stringify_int(u8 *buf, u64 val) { -\ + #define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) \ do { \ \ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 328f818d..3fc86b3b 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -258,7 +258,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->last_run_timed_out = false; fsrv->debug = false; fsrv->uses_crash_exitcode = false; - fsrv->uses_asan = false; + fsrv->uses_asan = 0; #ifdef __AFL_CODE_COVERAGE fsrv->persistent_trace_bits = NULL; @@ -2087,17 +2087,19 @@ fsrv_run_result_t __attribute__((hot)) afl_fsrv_run_target( /* Did we crash? In a normal case, (abort) WIFSIGNALED(child_status) will be set. - MSAN in uses_asan mode uses a special exit code as it doesn't support + MSAN & LSAN in uses_asan mode use special exit codes as they doesn't support abort_on_error. On top, a user may specify a custom AFL_CRASH_EXITCODE. - Handle all three cases here. */ + Handle all four cases here. */ if (unlikely( /* A normal crash/abort */ (WIFSIGNALED(fsrv->child_status)) || - /* special handling for msan and lsan */ - (fsrv->uses_asan && - (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR || - WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) || + /* special handling for msan */ + ((fsrv->uses_asan & 4) && + WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) || + /* special handling for lsan */ + ((fsrv->uses_asan & 2) && + WEXITSTATUS(fsrv->child_status) == LSAN_ERROR) || /* the custom crash_exitcode was returned by the target */ (fsrv->uses_crash_exitcode && WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) { @@ -2106,6 +2108,10 @@ fsrv_run_result_t __attribute__((hot)) afl_fsrv_run_target( fsrv->last_kill_signal = WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0; + /* For a special exit code, set last_exit_code to non-zero */ + fsrv->last_exit_code = + WIFSIGNALED(fsrv->child_status) ? 0 : WEXITSTATUS(fsrv->child_status); + #ifdef AFL_PERSISTENT_RECORD if (unlikely(fsrv->persistent_record)) { diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index bd3378f9..6a754a40 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -462,18 +462,6 @@ void write_crash_readme(afl_state_t *afl) { } -static inline void bitmap_set(u8 *map, u32 index) { - - map[index / 8] |= (1u << (index % 8)); - -} - -static inline u8 bitmap_read(u8 *map, u32 index) { - - return (map[index / 8] >> (index % 8)) & 1; - -} - /* Check if the result of an execve() during routine fuzzing is interesting, save or queue the input test case for further analysis if so. Returns 1 if entry is saved, 0 otherwise. */ @@ -481,6 +469,8 @@ static inline u8 bitmap_read(u8 *map, u32 index) { u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { + u8 classified = 0; + if (unlikely(len == 0)) { return 0; } if (unlikely(fault == FSRV_RUN_TMOUT && afl->afl_env.afl_ignore_timeouts)) { @@ -489,6 +479,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, classify_counts(&afl->fsrv); u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); + classified = 1; // Saturated increment if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF)) @@ -502,8 +493,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, u8 fn[PATH_MAX]; u8 *queue_fn = ""; - u8 new_bits = 0, keeping = 0, res, classified = 0, is_timeout = 0, - need_hash = 1; + u8 new_bits = 0, keeping = 0, res, is_timeout = 0, need_hash = 1; s32 fd; u64 cksum = 0; u32 cksum_simplified = 0, cksum_unique = 0; @@ -520,7 +510,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { classify_counts(&afl->fsrv); - classified = 1; need_hash = 0; cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); @@ -539,8 +528,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, memcpy(afl->san_fsrvs[0].trace_bits, afl->fsrv.trace_bits, afl->fsrv.map_size); - classify_counts_mem((_AFL_INTSIZEVAR *)afl->san_fsrvs[0].trace_bits, - afl->fsrv.map_size); simplify_trace(afl, afl->san_fsrvs[0].trace_bits); // Note: Original SAND implementation used XXHASH32 @@ -569,6 +556,16 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, if (unlikely(afl->san_binary_length) && likely(afl->san_abstraction == UNIQUE_TRACE)) { + // If schedule is not FAST..RARE, we need to classify counts here + // Note: SAND was evaluated under FAST schedule but should also work + // with other scedules. + if (!classified) { + + classify_counts(&afl->fsrv); + classified = 1; + + } + cksum_unique = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (unlikely(!bitmap_read(afl->n_fuzz_dup, cksum) && @@ -631,7 +628,16 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, /* If we are in coverage increasing abstraction and have fed input to sanitizers, we are sure it has new bits.*/ - new_bits = has_new_bits_unclassified(afl, afl->virgin_bits); + if (classified) { + + /* We could have classified the bits in SAND with UNIQUE_TRACE */ + new_bits = has_new_bits(afl, afl->virgin_bits); + + } else { + + new_bits = has_new_bits_unclassified(afl, afl->virgin_bits); + + } } @@ -646,7 +652,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, afl->san_case_status |= NON_COV_INCREASE_BUG; fault = san_fault; - classified = new_bits; goto may_save_fault; } @@ -654,7 +659,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, } fault = san_fault; - classified = new_bits; save_to_queue: @@ -799,13 +803,6 @@ may_save_fault: if (likely(!afl->non_instrumented_mode)) { - if (unlikely(!classified)) { - - classify_counts(&afl->fsrv); - classified = 1; - - } - simplify_trace(afl, afl->fsrv.trace_bits); if (!has_new_bits(afl, afl->virgin_tmout)) { return keeping; } @@ -939,13 +936,6 @@ may_save_fault: if (likely(!afl->non_instrumented_mode)) { - if (unlikely(!classified)) { - - classify_counts(&afl->fsrv); - classified = 1; - - } - simplify_trace(afl, afl->fsrv.trace_bits); if (!has_new_bits(afl, afl->virgin_crash)) { return keeping; } diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index da996602..09338bb6 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -354,6 +354,7 @@ void load_extras(afl_state_t *afl, u8 *dir) { "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)); + ck_free(fn); continue; } @@ -742,10 +743,8 @@ void save_auto(afl_state_t *afl) { for (i = 0; i < MIN((u32)USE_AUTO_EXTRAS, afl->a_extras_cnt); ++i) { - u8 *fn = alloc_printf( - "%s/queue/.state/auto_extras/auto_%06u%s%s", afl->out_dir, i, - afl->file_extension ? "." : "", - afl->file_extension ? (const char *)afl->file_extension : ""); + u8 *fn = + alloc_printf("%s/queue/.state/auto_extras/auto_%06u", afl->out_dir, i); s32 fd; diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index a89c256b..cf8d319c 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -567,6 +567,7 @@ void read_foreign_testcases(afl_state_t *afl, int first) { } + free(nl); continue; } @@ -593,6 +594,7 @@ void read_foreign_testcases(afl_state_t *afl, int first) { if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) { if (first) PFATAL("Unable to access '%s'", fn2); + ck_free(fn2); continue; } @@ -634,19 +636,16 @@ void read_foreign_testcases(afl_state_t *afl, int first) { // as this could add duplicates of the startup input corpus int fd = open(fn2, O_RDONLY); - if (fd < 0) { + ck_free(fn2); - ck_free(fn2); - continue; - - } + if (fd < 0) { continue; } u8 fault; u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (mem == MAP_FAILED) { - ck_free(fn2); + close(fd); continue; } @@ -668,7 +667,12 @@ void read_foreign_testcases(afl_state_t *afl, int first) { } - afl->foreign_syncs[iter].mtime = mtime_max; + if (mtime_max > afl->foreign_syncs[iter].mtime) { + + afl->foreign_syncs[iter].mtime = mtime_max; + + } + free(nl); /* not tracked */ } @@ -749,8 +753,6 @@ void read_testcases(afl_state_t *afl, u8 *directory) { } - // if (getenv("MYTEST")) afl->in_place_resume = 1; - if (nl_cnt) { u32 done = 0; @@ -1042,6 +1044,47 @@ void perform_dry_run(afl_state_t *afl) { if (afl->crash_mode) { break; } + const u8 *msg_exit_code = ""; + + if (afl->fsrv.uses_asan && !afl->fsrv.last_kill_signal) { + + if ((afl->fsrv.uses_asan & 4) && + afl->fsrv.last_exit_code == MSAN_ERROR) { + + msg_exit_code = + " - The test case terminated with the exit code that is " + "used by MSAN to\n" + " indicate an error. This is counted as a crash by " + "afl-fuzz because you\n" + " have compiled the target with MSAN enabled. This could " + "be a false\n" + " positive if the program returns this exit code under " + "normal operation.\n" + " In that case, either disable MSAN or change the test " + "case or program\n" + " to avoid generating this exit code.\n\n"; + + } else if ((afl->fsrv.uses_asan & 2) && + + afl->fsrv.last_exit_code == LSAN_ERROR) { + + msg_exit_code = + " - The test case terminated with the exit code that is " + "used by LSAN to\n" + " indicate an error. This is counted as a crash by " + "afl-fuzz because you\n" + " have compiled the target with LSAN enabled. This could " + "be a false\n" + " positive if the program returns this exit code under " + "normal operation.\n" + " In that case, either disable LSAN or change the test " + "case or program\n" + " to avoid generating this exit code.\n\n"; + + } + + } + if (afl->fsrv.mem_limit) { u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; @@ -1056,6 +1099,7 @@ void perform_dry_run(afl_state_t *afl) { " so, please remove it. The fuzzer should be seeded with " "interesting\n" " inputs - but not ones that cause an outright crash.\n\n" + "%s" " - The current memory limit (%s) is too low for this " "program, causing\n" @@ -1085,6 +1129,7 @@ void perform_dry_run(afl_state_t *afl) { "other options\n" " fail, poke the Awesome Fuzzing Discord for " "troubleshooting tips.\n", + msg_exit_code, stringify_mem_size(val_buf, sizeof(val_buf), afl->fsrv.mem_limit << 20), afl->fsrv.mem_limit - 1); @@ -1101,6 +1146,7 @@ void perform_dry_run(afl_state_t *afl) { " so, please remove it. The fuzzer should be seeded with " "interesting\n" " inputs - but not ones that cause an outright crash.\n\n" + "%s" " - In QEMU persistent mode the selected address(es) for the " "loop are not\n" @@ -1113,7 +1159,8 @@ void perform_dry_run(afl_state_t *afl) { " - Least likely, there is a horrible bug in the fuzzer. If " "other options\n" " fail, poke the Awesome Fuzzing Discord for " - "troubleshooting tips.\n"); + "troubleshooting tips.\n", + msg_exit_code); } @@ -2180,10 +2227,17 @@ int check_main_node_exists(afl_state_t *afl) { fn = alloc_printf("%s/%s/is_main_node", afl->sync_dir, sd_ent->d_name); int res = access(fn, F_OK); free(fn); - if (res == 0) return 1; + if (res == 0) { + + closedir(sd); + return 1; + + } } + closedir(sd); + return 0; } @@ -2267,18 +2321,6 @@ void setup_dirs_fds(afl_state_t *afl) { if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); - /* The set of paths currently deemed redundant. */ - - tmp = alloc_printf("%s/queue/.state/redundant_edges/", afl->out_dir); - if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } - ck_free(tmp); - - /* The set of paths showing variable behavior. */ - - tmp = alloc_printf("%s/queue/.state/variable_behavior/", afl->out_dir); - if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } - ck_free(tmp); - /* Sync directory for keeping track of cooperating fuzzers. */ if (afl->sync_id) { @@ -2601,7 +2643,7 @@ void check_cpu_governor(afl_state_t *afl) { " afl-fuzz. To keep things moving, run these commands as root:\n\n" " cd /sys/devices/system/cpu\n" - " echo performance | tee cpu*/cpufreq/scaling_governor\n\n" + " echo performance | sudo tee cpu*/cpufreq/scaling_governor\n\n" " You can later go back to the original state by replacing " "'performance'\n" @@ -3118,11 +3160,23 @@ void check_binary(afl_state_t *afl, u8 *fname) { } - if (afl_memmem(f_data, f_len, "__asan_init", 11) || - afl_memmem(f_data, f_len, "__msan_init", 11) || - afl_memmem(f_data, f_len, "__lsan_init", 11)) { + afl->fsrv.uses_asan = 0; - afl->fsrv.uses_asan = 1; + if (afl_memmem(f_data, f_len, "__asan_init", 11)) { + + afl->fsrv.uses_asan |= 1; + + } + + if (afl_memmem(f_data, f_len, "__lsan_init", 11)) { + + afl->fsrv.uses_asan |= 2; + + } + + if (afl_memmem(f_data, f_len, "__msan_init", 11)) { + + afl->fsrv.uses_asan |= 4; } diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index dbc23ac6..7c7a4b9f 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -636,7 +636,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, q->len = out_len; memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size); - update_bitmap_score(afl, q); + update_bitmap_score(afl, q, true); } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 36127964..1cc8f6e4 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -634,7 +634,7 @@ u8 fuzz_one_original(afl_state_t *afl) { afl->stage_cur_byte = afl->stage_cur >> 3; - if (!skip_eff_map[afl->stage_cur_byte]) continue; + if (!bitmap_read(skip_eff_map, afl->stage_cur_byte)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -754,7 +754,7 @@ u8 fuzz_one_original(afl_state_t *afl) { afl->stage_cur_byte = afl->stage_cur >> 3; - if (!skip_eff_map[afl->stage_cur_byte]) continue; + if (!bitmap_read(skip_eff_map, afl->stage_cur_byte)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -793,7 +793,7 @@ u8 fuzz_one_original(afl_state_t *afl) { afl->stage_cur_byte = afl->stage_cur >> 3; - if (!skip_eff_map[afl->stage_cur_byte]) continue; + if (!bitmap_read(skip_eff_map, afl->stage_cur_byte)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -837,7 +837,7 @@ u8 fuzz_one_original(afl_state_t *afl) { afl->stage_cur_byte = afl->stage_cur; - if (!skip_eff_map[afl->stage_cur_byte]) continue; + if (!bitmap_read(skip_eff_map, afl->stage_cur_byte)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -858,7 +858,7 @@ u8 fuzz_one_original(afl_state_t *afl) { for (i = 0; i < len; i++) { - if (skip_eff_map[i]) afl->blocks_eff_select += 1; + if (bitmap_read(skip_eff_map, i)) afl->blocks_eff_select += 1; } @@ -887,7 +887,7 @@ u8 fuzz_one_original(afl_state_t *afl) { /* Let's consult the effector map... */ - if (!skip_eff_map[i]) continue; + if (!bitmap_read(skip_eff_map, i)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -930,7 +930,7 @@ u8 fuzz_one_original(afl_state_t *afl) { /* Let's consult the effector map... */ - if (!skip_eff_map[i]) continue; + if (!bitmap_read(skip_eff_map, i)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -983,7 +983,7 @@ skip_bitflip: /* Let's consult the effector map... */ - if (!skip_eff_map[i]) continue; + if (!bitmap_read(skip_eff_map, i)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -1067,7 +1067,7 @@ skip_bitflip: /* Let's consult the effector map... */ - if (!skip_eff_map[i]) continue; + if (!bitmap_read(skip_eff_map, i)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -1197,7 +1197,7 @@ skip_bitflip: /* Let's consult the effector map... */ - if (!skip_eff_map[i]) continue; + if (!bitmap_read(skip_eff_map, i)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -1331,7 +1331,7 @@ skip_arith: /* Let's consult the effector map... */ - if (!skip_eff_map[i]) continue; + if (!bitmap_read(skip_eff_map, i)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -1391,7 +1391,7 @@ skip_arith: /* Let's consult the effector map... */ - if (!skip_eff_map[i]) continue; + if (!bitmap_read(skip_eff_map, i)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -1479,7 +1479,7 @@ skip_arith: /* Let's consult the effector map... */ - if (!skip_eff_map[i]) continue; + if (!bitmap_read(skip_eff_map, i)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -1573,7 +1573,7 @@ skip_interest: u32 last_len = 0; - if (!skip_eff_map[i]) continue; + if (!bitmap_read(skip_eff_map, i)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -1642,7 +1642,7 @@ skip_interest: for (i = 0; i <= (u32)len; ++i) { - if (!skip_eff_map[i % len]) continue; + if (!bitmap_read(skip_eff_map, i % len)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -1708,7 +1708,7 @@ skip_user_extras: u32 last_len = 0; - if (!skip_eff_map[i]) continue; + if (!bitmap_read(skip_eff_map, i)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } @@ -1768,7 +1768,7 @@ skip_user_extras: for (i = 0; i <= (u32)len; ++i) { - if (!skip_eff_map[i % len]) continue; + if (!bitmap_read(skip_eff_map, i % len)) continue; if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; } diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 4d68c4c4..faec406d 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -440,30 +440,6 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) { } -/* Mark as variable. Create symlinks if possible to make it easier to examine - the files. */ - -void mark_as_variable(afl_state_t *afl, struct queue_entry *q) { - - char fn[PATH_MAX]; - char ldest[PATH_MAX]; - - char *fn_name = strrchr((char *)q->fname, '/') + 1; - - sprintf(ldest, "../../%s", fn_name); - sprintf(fn, "%s/queue/.state/variable_behavior/%s", afl->out_dir, fn_name); - - if (symlink(ldest, fn)) { - - s32 fd = permissive_create(afl, fn); - if (fd >= 0) { close(fd); } - - } - - q->var_behavior = 1; - -} - /* Mark / unmark as redundant (edge-only). This is not used for restoring state, but may be useful for post-processing datasets. */ @@ -471,8 +447,6 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { if (likely(state == q->fs_redundant)) { return; } - char fn[PATH_MAX]; - q->fs_redundant = state; if (likely(q->fs_redundant)) { @@ -486,22 +460,9 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { } - sprintf(fn, "%s/queue/.state/redundant_edges/%s", afl->out_dir, - strrchr((char *)q->fname, '/') + 1); - if (state) { - s32 fd; - if (unlikely(afl->afl_env.afl_disable_redundant)) { q->disabled = 1; } - fd = permissive_create(afl, fn); - if (fd >= 0) { close(fd); } - - } else { - - if (unlink(fn)) { /*PFATAL("Unable to remove '%s'", fn);*/ - - } } @@ -805,6 +766,7 @@ void destroy_queue(afl_state_t *afl) { for (i = 0; i < afl->queued_items; i++) { q = afl->queue_buf[i]; + ck_free(q->testcase_buf); ck_free(q->fname); ck_free(q->trace_mini); if (q->skipdet_e) { @@ -833,7 +795,8 @@ void destroy_queue(afl_state_t *afl) { previous contender, or if the contender has a more favorable speed x size factor. */ -void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { +void update_bitmap_score(afl_state_t *afl, struct queue_entry *q, + bool have_trace) { u32 i; u64 fav_factor; @@ -863,75 +826,80 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { } - /* 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 < afl->fsrv.map_size; ++i) { + if (have_trace) { - if (afl->fsrv.trace_bits[i]) { + /* 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 < afl->fsrv.map_size; ++i) { - if (afl->top_rated[i]) { + if (afl->fsrv.trace_bits[i]) { - /* Faster-executing or smaller test cases are favored. */ - u64 top_rated_fav_factor; - u64 top_rated_fuzz_p2; + if (afl->top_rated[i]) { - if (unlikely(afl->schedule >= FAST && afl->schedule < RARE)) { + /* Faster-executing or smaller test cases are favored. */ + u64 top_rated_fav_factor; + u64 top_rated_fuzz_p2; - top_rated_fuzz_p2 = 0; // Skip the fuzz_p2 comparison + if (unlikely(afl->schedule >= FAST && afl->schedule < RARE)) { - } else if (unlikely(afl->schedule == RARE)) { + top_rated_fuzz_p2 = 0; // Skip the fuzz_p2 comparison - top_rated_fuzz_p2 = - next_pow2(afl->n_fuzz[afl->top_rated[i]->n_fuzz_entry]); + } else if (unlikely(afl->schedule == RARE)) { - } else { + top_rated_fuzz_p2 = + next_pow2(afl->n_fuzz[afl->top_rated[i]->n_fuzz_entry]); - top_rated_fuzz_p2 = afl->top_rated[i]->fuzz_level; + } else { + + top_rated_fuzz_p2 = afl->top_rated[i]->fuzz_level; + + } + + if (unlikely(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 (likely(fuzz_p2 > top_rated_fuzz_p2)) { continue; } + + if (likely(fav_factor > top_rated_fav_factor)) { continue; } + + /* Looks like we're going to win. Decrease ref count for the + previous winner, discard its afl->fsrv.trace_bits[] if necessary. + */ + + if (!--afl->top_rated[i]->tc_ref) { + + ck_free(afl->top_rated[i]->trace_mini); + afl->top_rated[i]->trace_mini = NULL; + + } } - if (unlikely(afl->schedule >= RARE) || unlikely(afl->fixed_seed)) { + /* Insert ourselves as the new winner. */ - top_rated_fav_factor = afl->top_rated[i]->len << 2; + afl->top_rated[i] = q; + ++q->tc_ref; - } else { + if (!q->trace_mini) { - top_rated_fav_factor = - afl->top_rated[i]->exec_us * afl->top_rated[i]->len; + u32 len = ((afl->fsrv.map_size + 7) >> 3); + q->trace_mini = (u8 *)ck_alloc(len); + minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits); } - if (likely(fuzz_p2 > top_rated_fuzz_p2)) { continue; } - - if (likely(fav_factor > top_rated_fav_factor)) { continue; } - - /* Looks like we're going to win. Decrease ref count for the - previous winner, discard its afl->fsrv.trace_bits[] if necessary. */ - - if (!--afl->top_rated[i]->tc_ref) { - - ck_free(afl->top_rated[i]->trace_mini); - afl->top_rated[i]->trace_mini = NULL; - - } + afl->score_changed = 1; } - /* Insert ourselves as the new winner. */ - - afl->top_rated[i] = q; - ++q->tc_ref; - - if (!q->trace_mini) { - - u32 len = (afl->fsrv.map_size >> 3); - q->trace_mini = (u8 *)ck_alloc(len); - minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits); - - } - - afl->score_changed = 1; - } } @@ -1025,6 +993,186 @@ void cull_queue(afl_state_t *afl) { } +/* Re-selects top_rated[] entries based on the current fuzzing schedule. + Each queued entry is executed once to collect trace_bits, and potential + candidates for each bitmap index are stored. + + The candidate list format is [count][id1][id2]... as a u32 array, + where 'count' indicates how many queue IDs hit that index. */ + +void recalculate_all_scores(afl_state_t *afl) { + + u8 *in_buf; + u32 i; + u32 j; + + for (i = afl->last_scored_idx + 1; i < afl->queued_items; i++) { + + if (likely(!afl->queue_buf[i]->disabled)) { + + in_buf = queue_testcase_get(afl, afl->queue_buf[i]); + (void)write_to_testcase(afl, (void **)&in_buf, afl->queue_buf[i]->len, 1); + (void)fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); + + for (j = 0; j < afl->fsrv.map_size; ++j) { + + if (afl->fsrv.trace_bits[j]) { + + u32 *candidate_ids = afl->top_rated_candidates[j]; + u32 id = afl->queue_buf[i]->id; + + if (!candidate_ids) { + + // first candidate: [count][id] + candidate_ids = ck_alloc(sizeof(u32) * 2); + candidate_ids[0] = 1; // count = 1 + candidate_ids[1] = id; // first ID + + } else { + + u32 count = candidate_ids[0]; + + candidate_ids = + ck_realloc(candidate_ids, sizeof(u32) * (count + 2)); + candidate_ids[0] = count + 1; // increment the count + candidate_ids[count + 1] = id; // append the new ID to the end + + // fprintf(stderr, "enroll candidate[%u][%u] %u\n", i, j, id); + + } + + afl->top_rated_candidates[j] = candidate_ids; + + } + + } + + } + + afl->last_scored_idx = i; + + } + + for (i = 0; i < afl->fsrv.map_size; ++i) { + + u32 *candidate_ids = afl->top_rated_candidates[i]; + if (candidate_ids) { + + u32 count = candidate_ids[0]; + + for (u32 k = 0; k < count; k++) { + + u32 id = candidate_ids[k + 1]; + struct queue_entry *entry = afl->queue_buf[id]; + update_bitmap_rescore(afl, entry, i); + + } + + } + + } + +} + +/* Re-evaluates top-rated entries without checking trace_bits. + Unlike update_bitmap_score(), this function assumes the trace + information is already known and only compares entries */ + +void update_bitmap_rescore(afl_state_t *afl, struct queue_entry *q, u32 index) { + + u32 i = index; + u64 fav_factor; + u64 fuzz_p2; + + if (unlikely(afl->schedule >= FAST && afl->schedule < RARE)) { + + fuzz_p2 = 0; // Skip the fuzz_p2 comparison + + } else if (unlikely(afl->schedule == RARE)) { + + fuzz_p2 = next_pow2(afl->n_fuzz[q->n_fuzz_entry]); + + } else { + + fuzz_p2 = q->fuzz_level; + + } + + if (unlikely(afl->schedule >= RARE) || unlikely(afl->fixed_seed)) { + + fav_factor = q->len << 2; + + } else { + + fav_factor = q->exec_us * q->len; + + } + + if (afl->top_rated[i]) { + + /* Faster-executing or smaller test cases are favored. */ + u64 top_rated_fav_factor; + u64 top_rated_fuzz_p2; + + if (unlikely(afl->schedule >= FAST && afl->schedule < RARE)) { + + top_rated_fuzz_p2 = 0; // Skip the fuzz_p2 comparison + + } else if (unlikely(afl->schedule == RARE)) { + + top_rated_fuzz_p2 = + next_pow2(afl->n_fuzz[afl->top_rated[i]->n_fuzz_entry]); + + } else { + + top_rated_fuzz_p2 = afl->top_rated[i]->fuzz_level; + + } + + if (unlikely(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 (likely(fuzz_p2 > top_rated_fuzz_p2)) { return; } + + if (likely(fav_factor > top_rated_fav_factor)) { return; } + + /* Looks like we're going to win. Decrease ref count for the + previous winner, discard its afl->fsrv.trace_bits[] if necessary. */ + + if (!--afl->top_rated[i]->tc_ref) { + + ck_free(afl->top_rated[i]->trace_mini); + afl->top_rated[i]->trace_mini = NULL; + + } + + } + + /* Insert ourselves as the new winner. */ + + afl->top_rated[i] = q; + ++q->tc_ref; + + if (!q->trace_mini) { + + u32 len = (afl->fsrv.map_size >> 3); + q->trace_mini = (u8 *)ck_alloc(len); + minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits); + + } + + afl->score_changed = 1; + +} + /* Calculate case desirability score to adjust the length of havoc fuzzing. A helper function for fuzz_one(). Maybe some of these constants should go into config.h. */ @@ -1330,7 +1478,7 @@ inline void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q, // only realloc if necessary or useful // (a custom trim can make the testcase larger) - if (unlikely(len > old_len || len < old_len + 1024)) { + if (unlikely(len > old_len || len + 1024 < old_len)) { afl->q_testcase_cache_size += len - old_len; q->testcase_buf = (u8 *)realloc(q->testcase_buf, len); @@ -1364,7 +1512,7 @@ inline void queue_testcase_retake_mem(afl_state_t *afl, struct queue_entry *q, if (likely(in != q->testcase_buf)) { // only realloc if we save memory - if (unlikely(len < old_len + 1024)) { + if (unlikely(len + 1024 < old_len)) { u8 *ptr = (u8 *)realloc(q->testcase_buf, len); diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index c40af235..e6fb3ac6 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -592,11 +592,11 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, // note: from_queue seems to only be set during initialization if (afl->afl_env.afl_no_ui || from_queue) { - WARNF("instability detected during calibration"); + WARNF("instability detected during calibration: %s", q->fname); } else if (afl->debug) { - DEBUGF("instability detected during calibration\n"); + DEBUGF("instability detected during calibration: %s\n", q->fname); } @@ -652,7 +652,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, afl->total_bitmap_size += q->bitmap_size; ++afl->total_bitmap_entries; - update_bitmap_score(afl, q); + update_bitmap_score(afl, q, true); /* If this case didn't result in new output from the instrumentation, tell parent. This is a non-critical problem, but something to warn the user @@ -682,12 +682,7 @@ abort_calibration: afl->var_byte_count = count_bytes(afl, afl->var_bytes); - if (!q->var_behavior) { - - mark_as_variable(afl, q); - ++afl->queued_variable; - - } + if (!q->var_behavior) { ++afl->queued_variable; } } @@ -872,7 +867,14 @@ void sync_fuzzers(afl_state_t *afl) { fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); - if (afl->stop_soon) { goto close_sync; } + if (afl->stop_soon) { + + munmap(mem, st.st_size); + close(fd); + + goto close_sync; + + } afl->syncing_party = sd_ent->d_name; afl->queued_imported += save_if_interesting(afl, mem, new_len, fault); @@ -1166,7 +1168,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { queue_testcase_retake_mem(afl, q, in_buf, q->len, orig_len); memcpy(afl->fsrv.trace_bits, afl->clean_trace, afl->fsrv.map_size); - update_bitmap_score(afl, q); + update_bitmap_score(afl, q, true); } diff --git a/src/afl-fuzz-skipdet.c b/src/afl-fuzz-skipdet.c index 8a927292..2197c101 100644 --- a/src/afl-fuzz-skipdet.c +++ b/src/afl-fuzz-skipdet.c @@ -154,7 +154,7 @@ u8 skip_deterministic_stage(afl_state_t *afl, u8 *orig_buf, u8 *out_buf, flip_range(out_buf, pos, flip_block_size); - if (common_fuzz_stuff(afl, out_buf, len)) return 0; + if (common_fuzz_stuff(afl, out_buf, len)) { return 0; } flip_range(out_buf, pos, flip_block_size); @@ -237,26 +237,26 @@ u8 skip_deterministic_stage(afl_state_t *afl, u8 *orig_buf, u8 *out_buf, if (!skip_eff_map) { - skip_eff_map = (u8 *)ck_alloc(sizeof(u8) * len); + skip_eff_map = (u8 *)ck_alloc(sizeof(u8) * (len + 7) / 8); afl->queue_cur->skipdet_e->skip_eff_map = skip_eff_map; } else { - memset(skip_eff_map, 0, sizeof(u8) * len); + memset(skip_eff_map, 0, sizeof(u8) * (len + 7) / 8); } /* restore the starting point */ if (!done_inf_map) { - done_inf_map = (u8 *)ck_alloc(sizeof(u8) * len); + done_inf_map = (u8 *)ck_alloc(sizeof(u8) * (len + 7) / 8); afl->queue_cur->skipdet_e->done_inf_map = done_inf_map; } else { for (afl->stage_cur = 0; afl->stage_cur < len; afl->stage_cur++) { - if (done_inf_map[afl->stage_cur] == 0) break; + if (bitmap_read(done_inf_map, afl->stage_cur) == 0) break; } @@ -278,7 +278,13 @@ u8 skip_deterministic_stage(afl_state_t *afl, u8 *orig_buf, u8 *out_buf, non_eff_bytes = (u8 *)ck_alloc(sizeof(u8) * len); // clean exec cksum - if (common_fuzz_stuff(afl, out_buf, len)) { return 0; } + if (common_fuzz_stuff(afl, out_buf, len)) { + + ck_free(non_eff_bytes); + return 0; + + } + prev_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); } @@ -294,7 +300,7 @@ u8 skip_deterministic_stage(afl_state_t *afl, u8 *orig_buf, u8 *out_buf, afl->stage_cur_byte = afl->stage_cur; if (!inf_eff_map[afl->stage_cur_byte] || - skip_eff_map[afl->stage_cur_byte]) + bitmap_read(skip_eff_map, afl->stage_cur_byte)) continue; if (is_det_timeout(before_det_time, 1)) { goto cleanup_skipdet; } @@ -311,7 +317,12 @@ u8 skip_deterministic_stage(afl_state_t *afl, u8 *orig_buf, u8 *out_buf, before_skip_inf = afl->queued_items; - if (common_fuzz_stuff(afl, out_buf, len)) { return 0; } + if (common_fuzz_stuff(afl, out_buf, len)) { + + ck_free(non_eff_bytes); + return 0; + + } out_buf[afl->stage_cur_byte] = orig; @@ -328,7 +339,7 @@ u8 skip_deterministic_stage(afl_state_t *afl, u8 *orig_buf, u8 *out_buf, if (afl->queued_items != before_skip_inf) { - skip_eff_map[afl->stage_cur_byte] = 1; + bitmap_set(skip_eff_map, afl->stage_cur_byte); afl->queue_cur->skipdet_e->quick_eff_bytes += 1; if (afl->stage_max < MAXIMUM_QUICK_EFF_EXECS) { afl->stage_max *= 2; } @@ -338,7 +349,7 @@ u8 skip_deterministic_stage(afl_state_t *afl, u8 *orig_buf, u8 *out_buf, } - done_inf_map[afl->stage_cur_byte] = 1; + bitmap_set(done_inf_map, afl->stage_cur_byte); } @@ -364,7 +375,7 @@ cleanup_skipdet: while (i < len) { // assume DWORD size, from i - 3 -> i + 3 - if (skip_eff_map[i]) { + if (bitmap_read(skip_eff_map, i)) { u32 fill_length = (i + 3 < len) ? 7 : len - i + 2; memset(nearby_bytes + i - 3, 1, fill_length); @@ -378,7 +389,7 @@ cleanup_skipdet: for (i = 0; i < len; i++) { - if (nearby_bytes[i] && !non_eff_bytes[i]) skip_eff_map[i] = 1; + if (nearby_bytes[i] && !non_eff_bytes[i]) bitmap_set(skip_eff_map, i); } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 11554369..67a3f31d 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -106,6 +106,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->switch_fuzz_mode = STRATEGY_SWITCH_TIME * 1000; afl->q_testcase_max_cache_size = TESTCASE_CACHE_SIZE * 1048576UL; afl->q_testcase_max_cache_entries = 64 * 1024; + afl->last_scored_idx = -1; #ifdef HAVE_AFFINITY afl->cpu_aff = -1; /* Selected CPU core */ @@ -738,6 +739,21 @@ void afl_state_deinit(afl_state_t *afl) { if (afl->pass_stats) { ck_free(afl->pass_stats); } if (afl->orig_cmp_map) { ck_free(afl->orig_cmp_map); } if (afl->cmplog_binary) { ck_free(afl->cmplog_binary); } + if (afl->cycle_schedules) { + + for (u32 i = 0; i < afl->fsrv.map_size; i++) { + + if (afl->top_rated_candidates[i]) { + + ck_free(afl->top_rated_candidates[i]); + + } + + } + + ck_free(afl->top_rated_candidates); + + } afl_free(afl->queue_buf); afl_free(afl->out_buf); @@ -746,6 +762,8 @@ void afl_state_deinit(afl_state_t *afl) { afl_free(afl->in_buf); afl_free(afl->in_scratch_buf); afl_free(afl->ex_buf); + afl_free(afl->alias_table); + afl_free(afl->alias_probability); ck_free(afl->virgin_bits); ck_free(afl->virgin_tmout); @@ -757,6 +775,11 @@ void afl_state_deinit(afl_state_t *afl) { ck_free(afl->first_trace); ck_free(afl->map_tmp_buf); + ck_free(afl->skipdet_g->inf_prof); + ck_free(afl->skipdet_g->virgin_det_bits); + ck_free(afl->skipdet_g); + ck_free(afl->havoc_prof); + list_remove(&afl_states, afl); } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 20da0434..8c13cd65 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -604,6 +604,8 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, void plot_profile_data(afl_state_t *afl, struct queue_entry *q) { + if (afl->skip_deterministic) { return; } + u64 current_ms = get_cur_time() - afl->start_time; u32 current_edges = count_non_255_bytes(afl, afl->virgin_bits); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index fbd5b389..871c3cea 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1750,8 +1750,27 @@ int main(int argc, char **argv_orig, char **envp) { } - afl->n_fuzz_dup = ck_alloc(N_FUZZ_SIZE_BITMAP * sizeof(u8)); - afl->simplified_n_fuzz = ck_alloc(N_FUZZ_SIZE_BITMAP * sizeof(u8)); + if (afl->cycle_schedules) { + + afl->top_rated_candidates = ck_alloc(map_size * sizeof(u32)); + + } + + if (afl->san_binary_length) { + + if (afl->san_abstraction == UNIQUE_TRACE) { + + afl->n_fuzz_dup = ck_alloc(N_FUZZ_SIZE_BITMAP * sizeof(u8)); + + } + + if (afl->san_abstraction == SIMPLIFY_TRACE) { + + afl->simplified_n_fuzz = ck_alloc(N_FUZZ_SIZE_BITMAP * sizeof(u8)); + + } + + } if (get_afl_env("AFL_NO_FORKSRV")) { afl->no_forkserver = 1; } if (get_afl_env("AFL_NO_CPU_RED")) { afl->no_cpu_meter_red = 1; } @@ -1759,16 +1778,7 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_SHUFFLE_QUEUE")) { afl->shuffle_queue = 1; } if (get_afl_env("AFL_EXPAND_HAVOC_NOW")) { afl->expand_havoc = 1; } - if (afl->afl_env.afl_autoresume) { - - afl->autoresume = 1; - if (afl->in_place_resume) { - - SAYF("AFL_AUTORESUME has no effect for '-i -'"); - - } - - } + if (afl->afl_env.afl_autoresume) { afl->autoresume = 1; } if (afl->afl_env.afl_hang_tmout) { @@ -2326,8 +2336,8 @@ int main(int argc, char **argv_orig, char **envp) { u8 ver_string[8]; u64 *ver = (u64 *)ver_string; - u64 expect_ver = - afl->shm.cmplog_mode + (sizeof(struct queue_entry) << 1); + u64 expect_ver = FAST_RESUME_VERSION + afl->shm.cmplog_mode + + (sizeof(struct queue_entry) << 1); if (NZLIBREAD(fr_fd, ver_string, sizeof(ver_string)) != sizeof(ver_string)) @@ -2605,7 +2615,7 @@ int main(int argc, char **argv_orig, char **envp) { } else { - WARNF("Unknown abstraction: %s, fallback to unique trace.\n", + WARNF("Unknown abstraction: %s, fallback to simplified trace.\n", san_abstraction); afl->san_abstraction = SIMPLIFY_TRACE; @@ -2843,7 +2853,7 @@ int main(int argc, char **argv_orig, char **envp) { u8 *o_end = (u8 *)&(afl->queue_buf[0]->mother); u32 r = 8 + afl->fsrv.map_size * 4; u32 q_len = o_end - o_start; - u32 m_len = (afl->fsrv.map_size >> 3); + u32 m_len = ((afl->fsrv.map_size + 7) >> 3); struct queue_entry *q; for (u32 i = 0; i < afl->queued_items; i++) { @@ -2866,7 +2876,7 @@ int main(int argc, char **argv_orig, char **envp) { afl->total_bitmap_size += q->bitmap_size; ++afl->total_bitmap_entries; - update_bitmap_score(afl, q); + update_bitmap_score(afl, q, false); if (q->was_fuzzed) { --afl->pending_not_fuzzed; } @@ -3236,15 +3246,7 @@ int main(int argc, char **argv_orig, char **envp) { } // we must recalculate the scores of all queue entries - for (u32 i = 0; i < afl->queued_items; i++) { - - if (likely(!afl->queue_buf[i]->disabled)) { - - update_bitmap_score(afl, afl->queue_buf[i]); - - } - - } + recalculate_all_scores(afl); } @@ -3546,7 +3548,8 @@ stop_fuzzing: u8 ver_string[8]; u32 w = 0; u64 *ver = (u64 *)ver_string; - *ver = afl->shm.cmplog_mode + (sizeof(struct queue_entry) << 1); + *ver = FAST_RESUME_VERSION + afl->shm.cmplog_mode + + (sizeof(struct queue_entry) << 1); ZLIBWRITE(fr_fd, ver_string, sizeof(ver_string), "ver_string"); ZLIBWRITE(fr_fd, afl->virgin_bits, afl->fsrv.map_size, "virgin_bits"); @@ -3559,7 +3562,7 @@ stop_fuzzing: u8 *o_start = (u8 *)&(afl->queue_buf[0]->colorized); u8 *o_end = (u8 *)&(afl->queue_buf[0]->mother); u32 q_len = o_end - o_start; - u32 m_len = (afl->fsrv.map_size >> 3); + u32 m_len = ((afl->fsrv.map_size + 7) >> 3); struct queue_entry *q; afl->pending_not_fuzzed = afl->queued_items; @@ -3626,6 +3629,10 @@ stop_fuzzing: } + ck_free(afl->n_fuzz); + ck_free(afl->n_fuzz_dup); + ck_free(afl->simplified_n_fuzz); + if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); } ck_free(afl->fsrv.target_path); ck_free(afl->fsrv.out_file); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 6cd89779..77765fba 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -159,10 +159,11 @@ void show_stats(afl_state_t *afl) { } -void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { +void update_bitmap_score(afl_state_t *afl, struct queue_entry *q, bool x) { (void)afl; (void)q; + (void)x; } diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c index 6cf62dab..0c56c816 100644 --- a/utils/aflpp_driver/aflpp_driver.c +++ b/utils/aflpp_driver/aflpp_driver.c @@ -106,12 +106,16 @@ __attribute__((weak)) void __asan_unpoison_memory_region( __attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size); // Notify AFL about persistent mode. -static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; -int __afl_persistent_loop(unsigned int); +__attribute__((section(".rodata"), used, + retain)) static const char AFL_PERSISTENT[] = + "##SIG_AFL_PERSISTENT##"; +int __afl_persistent_loop(unsigned int); // Notify AFL about deferred forkserver. -static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; -void __afl_manual_init(); +__attribute__((section(".rodata"), used, + retain)) static const char AFL_DEFER_FORKSVR[] = + "##SIG_AFL_DEFER_FORKSRV##"; +void __afl_manual_init(); // Use this optionally defined function to output sanitizer messages even if // user asks to close stderr. @@ -350,11 +354,6 @@ __attribute__((weak)) int LLVMFuzzerRunDriver( // Do any other expensive one-time initialization here. - uint8_t dummy_input[64] = {0}; - memcpy(dummy_input, (void *)AFL_PERSISTENT, sizeof(AFL_PERSISTENT)); - memcpy(dummy_input + 32, (void *)AFL_DEFER_FORKSVR, - sizeof(AFL_DEFER_FORKSVR)); - int N = INT_MAX; if (!in_afl && argc == 2 && !strcmp(argv[1], "-")) { diff --git a/utils/qbdi_mode/template.cpp b/utils/qbdi_mode/template.cpp index 3630ae3f..903a1ea1 100755 --- a/utils/qbdi_mode/template.cpp +++ b/utils/qbdi_mode/template.cpp @@ -11,12 +11,12 @@ #include #ifdef __ANDROID__ - #include "../include/android-ashmem.h" + #include "../../include/android-ashmem.h" #endif #include #include -#include "../config.h" +#include "../../config.h" #include @@ -80,8 +80,8 @@ static void afl_forkserver() { while (1) { - int status; - u32 was_killed; + int status; + unsigned int was_killed; // wait for afl-fuzz if (read(FORKSRV_FD, &was_killed, 4) != 4) exit(2);