diff options
32 files changed, 705 insertions, 194 deletions
diff --git a/Dockerfile b/Dockerfile index 522e801a..bdfa1c56 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ # -# This Dockerfile for AFLplusplus uses Ubuntu 20.04 focal and -# installs LLVM 11 from llvm.org for afl-clang-lto support :-) +# This Dockerfile for AFLplusplus uses Ubuntu 22.04 jammy and +# installs LLVM 14 for afl-clang-lto support :-) # -FROM ubuntu:20.04 AS aflplusplus +FROM ubuntu:22.04 AS aflplusplus LABEL "maintainer"="afl++ team <afl@aflplus.plus>" LABEL "about"="AFLplusplus docker image" @@ -29,20 +29,21 @@ RUN apt-get update && \ gnuplot-nox \ && rm -rf /var/lib/apt/lists/* -RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main" >> /etc/apt/sources.list && \ - wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - +# TODO: reactivate in timely manner +#RUN echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" >> /etc/apt/sources.list && \ +# wget -qO - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - -RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu focal main" >> /etc/apt/sources.list && \ +RUN echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu jammy main" >> /etc/apt/sources.list && \ apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 1E9377A2BA9EF27F RUN apt-get update && apt-get full-upgrade -y && \ apt-get -y install --no-install-suggests --no-install-recommends \ - gcc-10 g++-10 gcc-10-plugin-dev gdb lcov \ - clang-12 clang-tools-12 libc++1-12 libc++-12-dev \ - libc++abi1-12 libc++abi-12-dev libclang1-12 libclang-12-dev \ - libclang-common-12-dev libclang-cpp12 libclang-cpp12-dev liblld-12 \ - liblld-12-dev liblldb-12 liblldb-12-dev libllvm12 libomp-12-dev \ - libomp5-12 lld-12 lldb-12 llvm-12 llvm-12-dev llvm-12-runtime llvm-12-tools + gcc-12 g++-12 gcc-12-plugin-dev gdb lcov \ + clang-14 clang-tools-14 libc++1-14 libc++-14-dev \ + libc++abi1-14 libc++abi-14-dev libclang1-14 libclang-14-dev \ + libclang-common-14-dev libclang-cpp14 libclang-cpp14-dev liblld-14 \ + liblld-14-dev liblldb-14 liblldb-14-dev libllvm14 libomp-14-dev \ + libomp5-14 lld-14 lldb-14 llvm-14 llvm-14-dev llvm-14-runtime llvm-14-tools # arm64 doesn't have gcc-multilib, and it's only used for -m32 support on x86 ARG TARGETPLATFORM @@ -52,10 +53,10 @@ RUN [ "$TARGETPLATFORM" = "linux/amd64" ] && \ RUN rm -rf /var/lib/apt/lists/* -RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 0 -RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0 +RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 0 +RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 0 -ENV LLVM_CONFIG=llvm-config-12 +ENV LLVM_CONFIG=llvm-config-14 ENV AFL_SKIP_CPUFREQ=1 ENV AFL_TRY_AFFINITY=1 ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 @@ -66,7 +67,7 @@ RUN cd /afl-cov && make install && cd .. COPY . /AFLplusplus WORKDIR /AFLplusplus -RUN export CC=gcc-10 && export CXX=g++-10 && make clean && \ +RUN export CC=gcc-12 && export CXX=g++-12 && make clean && \ make distrib && make install && make clean RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc' diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 685964b7..538ca4a2 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -407,7 +407,7 @@ ifeq "$(LLVM_LTO)" "1" $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ endif -./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc +./SanitizerCoverageLTO.so: instrumentation/SanitizerCoverageLTO.so.cc instrumentation/afl-llvm-common.o ifeq "$(LLVM_LTO)" "1" $(CXX) $(CLANG_CPPFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o $(CLANG_BIN) $(CFLAGS_SAFE) $(CPPFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c instrumentation/afl-llvm-rt-lto.o.c -o ./afl-llvm-rt-lto.o diff --git a/docs/Changelog.md b/docs/Changelog.md index a841cca3..b6271a22 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -26,10 +26,16 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. - "saved timeouts" was wrong information, timeouts are still thrown away by default even if they have new coverage (hangs are always kept), unless AFL_KEEP_TIMEOUTS are set + - AFL never implemented auto token inserts (but user token inserts, + user token overwrite and auto token overwrite), added now! + - Mopt fix to always select the correct algorithm + - fix effector map calculation (deterministic mode) + - fix custom mutator post_process functionality - document and auto-activate pizza mode on condition - afl-cc: - converted all passed to use the new llvm pass manager for llvm 11+ - AFL++ PCGUARD mode is not available for 10.0.1 anymore (11+ only) + - trying to stay on top on all these #$&ยง!! changes in llvm 15 ... - frida_mode: - update to new frida release, handles now c++ throw/catch - unicorn_mode: diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index 0b5f52cb..014dcca5 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -116,7 +116,7 @@ ifndef OS $(error "Operating system unsupported") endif -GUM_DEVKIT_VERSION=15.1.15 +GUM_DEVKIT_VERSION=15.1.22 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)" diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c index 2bc8f8aa..fab9eee2 100644 --- a/frida_mode/src/instrument/instrument_arm64.c +++ b/frida_mode/src/instrument/instrument_arm64.c @@ -157,11 +157,13 @@ static gboolean instrument_is_deterministic(const cs_insn *from_insn) { } static void instrument_coverage_switch(GumStalkerObserver *self, + gpointer from_address, gpointer start_address, const cs_insn * from_insn, gpointer * target) { UNUSED_PARAMETER(self); + UNUSED_PARAMETER(from_address); UNUSED_PARAMETER(start_address); gsize fixup_offset; diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c index f02c971e..a764b054 100644 --- a/frida_mode/src/instrument/instrument_x64.c +++ b/frida_mode/src/instrument/instrument_x64.c @@ -172,12 +172,13 @@ void instrument_coverage_optimize_init(void) { } static void instrument_coverage_switch(GumStalkerObserver *self, + gpointer from_address, gpointer start_address, const cs_insn * from_insn, gpointer * target) { UNUSED_PARAMETER(self); - UNUSED_PARAMETER(start_address); + UNUSED_PARAMETER(from_address); cs_x86 * x86; cs_x86_op *op; diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c index 6a899248..1baa98ca 100644 --- a/frida_mode/src/instrument/instrument_x86.c +++ b/frida_mode/src/instrument/instrument_x86.c @@ -84,11 +84,13 @@ gboolean instrument_is_coverage_optimize_supported(void) { } static void instrument_coverage_switch(GumStalkerObserver *self, + gpointer from_address, gpointer start_address, const cs_insn * from_insn, gpointer * target) { UNUSED_PARAMETER(self); + UNUSED_PARAMETER(from_address); UNUSED_PARAMETER(start_address); cs_x86 * x86; diff --git a/frida_mode/src/module.c b/frida_mode/src/module.c index 65b394cd..60e69fec 100644 --- a/frida_mode/src/module.c +++ b/frida_mode/src/module.c @@ -42,7 +42,7 @@ gboolean found_range(const GumRangeDetails *details, gpointer user_data) { } -#if defined(__linux__) +#if defined(__linux__) && !defined(__ANDROID__) static int on_dlclose(void *handle) { GArray * ranges = NULL; @@ -95,7 +95,7 @@ void module_init(void) { FOKF(cBLU "Module" cRST " - " cYEL " [%c]", handle_dlclose ? 'X' : ' '); -#if defined(__linux__) +#if defined(__linux__) && !defined(__ANDROID__) if (!handle_dlclose) { return; } page_size = gum_query_page_size(); diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c index fa0288cc..59bfecc2 100644 --- a/frida_mode/src/prefetch.c +++ b/frida_mode/src/prefetch.c @@ -32,6 +32,8 @@ gboolean prefetch_backpatch = TRUE; static prefetch_data_t *prefetch_data = NULL; static int prefetch_shm_id = -1; +static GHashTable *cant_prefetch = NULL; + static void gum_afl_stalker_backpatcher_notify(GumStalkerObserver *self, const GumBackpatch *backpatch, gsize size) { @@ -40,6 +42,18 @@ static void gum_afl_stalker_backpatcher_notify(GumStalkerObserver *self, if (!entry_run) { return; } gsize remaining = sizeof(prefetch_data->backpatch_data) - prefetch_data->backpatch_size; + + gpointer from = gum_stalker_backpatch_get_from(backpatch); + gpointer to = gum_stalker_backpatch_get_to(backpatch); + + /* Stop reporting patches which can't be prefetched */ + if (g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(from)) || + g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(to))) { + + return; + + } + if (sizeof(gsize) + size > remaining) { return; } gsize *dst_backpatch_size = @@ -68,6 +82,9 @@ void prefetch_write(void *addr) { /* Bail if we aren't initialized */ if (prefetch_data == NULL) return; + /* Stop reporting blocks which can't be prefetched */ + if (g_hash_table_contains(cant_prefetch, GSIZE_TO_POINTER(addr))) { return; } + /* * Our shared memory IPC is large enough for about 1000 entries, we can fine * tune this if we need to. But if we have more new blocks that this in a @@ -84,6 +101,38 @@ void prefetch_write(void *addr) { } +typedef struct { + + GumAddress address; + gboolean executable; + +} check_executable_t; + +static gboolean prefetch_find_executable(const GumRangeDetails *details, + gpointer user_data) { + + check_executable_t *ctx = (check_executable_t *)user_data; + if (GUM_MEMORY_RANGE_INCLUDES(details->range, ctx->address)) { + + ctx->executable = TRUE; + return FALSE; + + } + + return TRUE; + +} + +static gboolean prefetch_is_executable(void *address) { + + check_executable_t ctx = {.address = GUM_ADDRESS(address), + .executable = FALSE}; + gum_process_enumerate_ranges(GUM_PAGE_EXECUTE, prefetch_find_executable, + &ctx); + return ctx.executable; + +} + static void prefetch_read_blocks(void) { GumStalker *stalker = stalker_get(); @@ -92,7 +141,24 @@ static void prefetch_read_blocks(void) { for (size_t i = 0; i < prefetch_data->count; i++) { void *addr = prefetch_data->entry[i]; - gum_stalker_prefetch(stalker, addr, 1); + + if (prefetch_is_executable(addr)) { + + gum_stalker_prefetch(stalker, addr, 1); + + } else { + + /* + * If our child process creates a new executable mapping, e.g. by + * dynamically loading a new DSO, then this won't appear in our parent + * process' memory map and hence we can't prefetch it. Add it to a + * hashtable which the child will inherit on the next fork to prevent the + * child from keep reporting it and exhausting the shared memory buffers + * used to pass new blocks from the child back to the parent. + */ + g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(addr)); + + } } @@ -125,7 +191,36 @@ static void prefetch_read_patches(void) { } backpatch = (GumBackpatch *)&prefetch_data->backpatch_data[offset]; - gum_stalker_prefetch_backpatch(stalker, backpatch); + + gpointer from = gum_stalker_backpatch_get_from(backpatch); + gpointer to = gum_stalker_backpatch_get_to(backpatch); + + /* + * If our child process creates a new executable mapping, e.g. by + * dynamically loading a new DSO, then this won't appear in our parent + * process' memory map and hence we can't prefetch it. Add it to a + * hashtable which the child will inherit on the next fork to prevent the + * child from keep reporting it and exhausting the shared memory buffers + * used to pass new blocks from the child back to the parent. + */ + if (!prefetch_is_executable(from)) { + + g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(from)); + + } + + if (!prefetch_is_executable(to)) { + + g_hash_table_add(cant_prefetch, GSIZE_TO_POINTER(to)); + + } + + if (prefetch_is_executable(from) && prefetch_is_executable(to)) { + + gum_stalker_prefetch_backpatch(stalker, backpatch); + + } + offset += size; } @@ -215,6 +310,13 @@ void prefetch_init(void) { prefetch_hook_fork(); + cant_prefetch = g_hash_table_new(g_direct_hash, g_direct_equal); + if (cant_prefetch == NULL) { + + FFATAL("Failed to g_hash_table_new, errno: %d", errno); + + } + if (!prefetch_backpatch) { return; } GumStalkerObserver * observer = stalker_get_observer(); diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c index 80e4e707..ddc17b81 100644 --- a/frida_mode/src/stalker.c +++ b/frida_mode/src/stalker.c @@ -131,6 +131,8 @@ void stalker_init(void) { } + gum_stalker_activate_experimental_unwind_support(); + #if defined(__x86_64__) || defined(__i386__) stalker = g_object_new(GUM_TYPE_STALKER, "ic-entries", stalker_ic_entries, "adjacent-blocks", stalker_adjacent_blocks, NULL); diff --git a/frida_mode/test/dynamic/GNUmakefile b/frida_mode/test/dynamic/GNUmakefile new file mode 100644 index 00000000..f43416f7 --- /dev/null +++ b/frida_mode/test/dynamic/GNUmakefile @@ -0,0 +1,76 @@ +PWD:=$(shell pwd)/ +ROOT:=$(PWD)../../../ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in +AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)dummy.dat + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +TESTINSTLIB:=$(BUILD_DIR)testinstrlib.so +TESTINSTLIBSRC:=$(PWD)testinstrlib.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so + +ADDR_BIN:=$(ROOT)frida_mode/build/addr +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + +AFL_FRIDA_BASE_ADDR:=$(shell $(ADDR_BIN)) +AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) testinstr $(AFL_FRIDA_BASE_ADDR)) + +CFLAGS+=-D_GNU_SOURCE=1 +LDFLAGS+=-ldl + +.PHONY: all clean qemu frida + +all: $(TESTINSTBIN) $(TESTINSTLIB) + make -C $(ROOT)frida_mode/ + +$(BUILD_DIR): + mkdir -p $@ + +$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) + dd if=/dev/zero bs=1048576 count=1 of=$@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTLIB): $(TESTINSTLIBSRC) | $(BUILD_DIR) + $(CC) \ + $(CFLAGS) \ + -shared \ + -o $@ \ + $(LDFLAGS) \ + $< + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) \ + $(CFLAGS) \ + -o $@ \ + $< \ + $(LDFLAGS) \ + -Wl,-rpath,'$$ORIGIN' + +clean: + rm -rf $(BUILD_DIR) + + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) $(AFLPP_DRIVER_DUMMY_INPUT) + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) $(AFLPP_DRIVER_DUMMY_INPUT) + diff --git a/frida_mode/test/dynamic/Makefile b/frida_mode/test/dynamic/Makefile new file mode 100644 index 00000000..f843af19 --- /dev/null +++ b/frida_mode/test/dynamic/Makefile @@ -0,0 +1,19 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +qemu: + @gmake qemu + +frida: + @gmake frida + +debug: + @gmake debug diff --git a/frida_mode/test/dynamic/testinstr.c b/frida_mode/test/dynamic/testinstr.c new file mode 100644 index 00000000..ad26d060 --- /dev/null +++ b/frida_mode/test/dynamic/testinstr.c @@ -0,0 +1,98 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2022 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ +#include <dlfcn.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +typedef void (*fntestinstrlib)(char *buf, int len); + +void testinstr(char *buf, int len) { + void *lib = dlopen("testinstrlib.so", RTLD_NOW); + if (lib == NULL) { + puts("Library not found"); + abort(); + } + + fntestinstrlib fn = (fntestinstrlib)(dlsym(lib, "testinstrlib")); + if (fn == NULL) { + puts("Function not found"); + abort(); + } + + fn(buf, len); +} + +int main(int argc, char **argv) { + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + file = argv[1]; + printf("file: %s\n", file); + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + perror("open"); + break; + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + perror("lseek (SEEK_END)"); + break; + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + perror("lseek (SEEK_SET)"); + break; + } + + printf("len: %ld\n", len); + + buf = malloc(len); + if (buf == NULL) { + perror("malloc"); + break; + } + + n_read = read(fd, buf, len); + if (n_read != len) { + perror("read"); + break; + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + testinstr(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; +} diff --git a/frida_mode/test/dynamic/testinstrlib.c b/frida_mode/test/dynamic/testinstrlib.c new file mode 100644 index 00000000..987cbf91 --- /dev/null +++ b/frida_mode/test/dynamic/testinstrlib.c @@ -0,0 +1,14 @@ +#include <stdio.h> + +void testinstrlib(char *buf, int len) { + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); +} diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 8bb61e22..9992e841 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -230,12 +230,13 @@ enum { /* 12 */ STAGE_EXTRAS_UO, /* 13 */ STAGE_EXTRAS_UI, /* 14 */ STAGE_EXTRAS_AO, - /* 15 */ STAGE_HAVOC, - /* 16 */ STAGE_SPLICE, - /* 17 */ STAGE_PYTHON, - /* 18 */ STAGE_CUSTOM_MUTATOR, - /* 19 */ STAGE_COLORIZATION, - /* 20 */ STAGE_ITS, + /* 15 */ STAGE_EXTRAS_AI, + /* 16 */ STAGE_HAVOC, + /* 17 */ STAGE_SPLICE, + /* 18 */ STAGE_PYTHON, + /* 19 */ STAGE_CUSTOM_MUTATOR, + /* 20 */ STAGE_COLORIZATION, + /* 21 */ STAGE_ITS, STAGE_NUM_MAX @@ -1098,7 +1099,7 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen); /* Run */ void sync_fuzzers(afl_state_t *); -u32 write_to_testcase(afl_state_t *, void *, u32, u32); +u32 write_to_testcase(afl_state_t *, void **, u32, u32); u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8); u8 trim_case(afl_state_t *, struct queue_entry *, u8 *); u8 common_fuzz_stuff(afl_state_t *, u8 *, u32); diff --git a/include/debug.h b/include/debug.h index e2ee16a8..c2f20f0f 100644 --- a/include/debug.h +++ b/include/debug.h @@ -388,6 +388,8 @@ static inline const char *colorfilter(const char *x) { \ } while (1); \ \ + \ + \ } while (0) #define ck_read(fd, buf, len, fn) \ diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index f80b1a1e..408353b3 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -313,13 +313,25 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module & M, std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd( Module &M, const char *Section, Type *Ty) { - GlobalVariable *SecStart = new GlobalVariable( - M, Ty->getPointerElementType(), false, - GlobalVariable::ExternalWeakLinkage, nullptr, getSectionStart(Section)); + GlobalVariable *SecStart = + new GlobalVariable(M, +#if LLVM_VERSION_MAJOR >= 15 + Ty, +#else + Ty->getPointerElementType(), +#endif + false, GlobalVariable::ExternalWeakLinkage, nullptr, + getSectionStart(Section)); SecStart->setVisibility(GlobalValue::HiddenVisibility); - GlobalVariable *SecEnd = new GlobalVariable( - M, Ty->getPointerElementType(), false, - GlobalVariable::ExternalWeakLinkage, nullptr, getSectionEnd(Section)); + GlobalVariable *SecEnd = + new GlobalVariable(M, +#if LLVM_VERSION_MAJOR >= 15 + Ty, +#else + Ty->getPointerElementType(), +#endif + false, GlobalVariable::ExternalWeakLinkage, nullptr, + getSectionEnd(Section)); SecEnd->setVisibility(GlobalValue::HiddenVisibility); IRBuilder<> IRB(M.getContext()); if (!TargetTriple.isOSBinFormatCOFF()) diff --git a/nyx_mode/LIBNYX_VERSION b/nyx_mode/LIBNYX_VERSION index 65e119c9..00165a63 100644 --- a/nyx_mode/LIBNYX_VERSION +++ b/nyx_mode/LIBNYX_VERSION @@ -1 +1 @@ -8a77c71 +acaf7f6 diff --git a/nyx_mode/PACKER_VERSION b/nyx_mode/PACKER_VERSION index d67dee20..a8ebe13a 100644 --- a/nyx_mode/PACKER_VERSION +++ b/nyx_mode/PACKER_VERSION @@ -1 +1 @@ -5d143ee +86b159b diff --git a/nyx_mode/QEMU-Nyx b/nyx_mode/QEMU-Nyx -Subproject c08e4ac94244a9739b4484b3010abc06b372923 +Subproject 5c8cf793ec615b0df5fa722878c8f6906ad7936 diff --git a/nyx_mode/QEMU_NYX_VERSION b/nyx_mode/QEMU_NYX_VERSION index 2d9ee5e3..f5888136 100644 --- a/nyx_mode/QEMU_NYX_VERSION +++ b/nyx_mode/QEMU_NYX_VERSION @@ -1 +1 @@ -c08e4ac942 +5c8cf793ec diff --git a/nyx_mode/libnyx b/nyx_mode/libnyx -Subproject 8a77c71dc8a8c0b73abd8fb9c22e30d565184ef +Subproject acaf7f6346eeb5f1e2cf043543316909fca4365 diff --git a/nyx_mode/packer b/nyx_mode/packer -Subproject 5d143eee4e4dcd12a1fc5d6786dd8da25cbb995 +Subproject 86b159bafc0b2ba8feeaa8761a45b6201d34084 diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 7c2b35d6..26e70d81 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -648,7 +648,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (afl->fsrv.exec_tmout < afl->hang_tmout) { u8 new_fault; - len = write_to_testcase(afl, mem, len, 0); + len = write_to_testcase(afl, &mem, len, 0); new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout); classify_counts(&afl->fsrv); diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 7d94085d..258d9ea7 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -49,7 +49,7 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { u8 fault; - write_to_testcase(afl, out_buf, len, 0); + write_to_testcase(afl, (void **)&out_buf, len, 0); fault = fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 05a654c8..6a653a00 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -617,7 +617,7 @@ void read_foreign_testcases(afl_state_t *afl, int first) { } - u32 len = write_to_testcase(afl, mem, st.st_size, 1); + u32 len = write_to_testcase(afl, (void **)&mem, st.st_size, 1); fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); afl->syncing_party = foreign_name; afl->queued_imported += save_if_interesting(afl, mem, len, fault); diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index e78e2dc4..9407adfb 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -428,7 +428,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, if (likely(retlen)) { - retlen = write_to_testcase(afl, retbuf, retlen, 0); + retlen = write_to_testcase(afl, (void **)&retbuf, retlen, 0); fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); ++afl->trim_execs; @@ -460,6 +460,8 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf, } out_len = retlen; + // TODO are we sure that retbuf fits into out_buf if retbuf can actually + // increase in size? memcpy(out_buf, retbuf, retlen); /* Tell the custom mutator that the trimming was successful */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index b28ee80a..19f41ebe 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -373,7 +373,7 @@ u8 fuzz_one_original(afl_state_t *afl) { u32 j; u32 i; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; - u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, prev_cksum; + u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, prev_cksum, _prev_cksum; u32 splice_cycle = 0, perf_score = 100, orig_perf, eff_cnt = 1; u8 ret_val = 1, doing_det = 0; @@ -630,7 +630,14 @@ u8 fuzz_one_original(afl_state_t *afl) { orig_hit_cnt = afl->queued_items + afl->saved_crashes; - prev_cksum = afl->queue_cur->exec_cksum; + /* Get a clean cksum. */ + + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } + + prev_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); + _prev_cksum = prev_cksum; + + /* Now flip bits. */ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { @@ -716,7 +723,7 @@ u8 fuzz_one_original(afl_state_t *afl) { /* Continue collecting string, but only if the bit flip actually made any difference - we don't want no-op tokens. */ - if (cksum != afl->queue_cur->exec_cksum) { + if (cksum != _prev_cksum) { if (a_len < MAX_AUTO_EXTRA) { @@ -839,6 +846,7 @@ u8 fuzz_one_original(afl_state_t *afl) { afl->stage_max = len; orig_hit_cnt = new_hit_cnt; + prev_cksum = _prev_cksum; for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { @@ -871,11 +879,11 @@ u8 fuzz_one_original(afl_state_t *afl) { } else { - cksum = ~afl->queue_cur->exec_cksum; + cksum = ~prev_cksum; } - if (cksum != afl->queue_cur->exec_cksum) { + if (cksum != prev_cksum) { eff_map[EFF_APOS(afl->stage_cur)] = 1; ++eff_cnt; @@ -1779,6 +1787,62 @@ skip_user_extras: afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt; afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max; + /* Insertion of auto extras. */ + + afl->stage_name = "auto extras (insert)"; + afl->stage_short = "ext_AI"; + afl->stage_cur = 0; + afl->stage_max = afl->a_extras_cnt * (len + 1); + + orig_hit_cnt = new_hit_cnt; + + ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE); + if (unlikely(!ex_tmp)) { PFATAL("alloc"); } + + for (i = 0; i <= (u32)len; ++i) { + + afl->stage_cur_byte = i; + + for (j = 0; j < afl->a_extras_cnt; ++j) { + + if (len + afl->a_extras[j].len > MAX_FILE) { + + --afl->stage_max; + continue; + + } + + /* Insert token */ + memcpy(ex_tmp + i, afl->a_extras[j].data, afl->a_extras[j].len); + + /* Copy tail */ + memcpy(ex_tmp + i + afl->a_extras[j].len, out_buf + i, len - i); + +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s AUTO_EXTRAS_insert-%u-%u", afl->queue_cur->fname, i, j); +#endif + + if (common_fuzz_stuff(afl, ex_tmp, len + afl->a_extras[j].len)) { + + goto abandon_entry; + + } + + ++afl->stage_cur; + + } + + /* Copy head */ + ex_tmp[i] = out_buf[i]; + + } + + new_hit_cnt = afl->queued_items + afl->saved_crashes; + + afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt; + afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max; + skip_extras: /* If we made this to here without jumping to havoc_stage or abandon_entry, @@ -1905,11 +1969,7 @@ custom_mutator_stage: } - /* `(afl->)out_buf` may have been changed by the call to custom_fuzz - */ - /* TODO: Only do this when `mutated_buf` == `out_buf`? Branch vs - * Memcpy. - */ + /* out_buf may have been changed by the call to custom_fuzz */ memcpy(out_buf, in_buf, len); } @@ -2994,7 +3054,8 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { u32 i; u32 j; u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0; - u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, cur_ms_lv, prev_cksum; + u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, cur_ms_lv, prev_cksum, + _prev_cksum; u32 splice_cycle = 0, perf_score = 100, orig_perf, eff_cnt = 1; u8 ret_val = 1, doing_det = 0; @@ -3238,7 +3299,14 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { orig_hit_cnt = afl->queued_items + afl->saved_crashes; - prev_cksum = afl->queue_cur->exec_cksum; + /* Get a clean cksum. */ + + if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; } + + prev_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); + _prev_cksum = prev_cksum; + + /* Now flip bits. */ for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { @@ -3323,7 +3391,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { /* Continue collecting string, but only if the bit flip actually made any difference - we don't want no-op tokens. */ - if (cksum != afl->queue_cur->exec_cksum) { + if (cksum != _prev_cksum) { if (a_len < MAX_AUTO_EXTRA) { @@ -3444,6 +3512,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { afl->stage_max = len; orig_hit_cnt = new_hit_cnt; + prev_cksum = _prev_cksum; for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { @@ -3475,11 +3544,11 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { } else { - cksum = ~afl->queue_cur->exec_cksum; + cksum = ~prev_cksum; } - if (cksum != afl->queue_cur->exec_cksum) { + if (cksum != prev_cksum) { eff_map[EFF_APOS(afl->stage_cur)] = 1; ++eff_cnt; @@ -4367,6 +4436,62 @@ skip_user_extras: afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt; afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max; + /* Insertion of auto extras. */ + + afl->stage_name = "auto extras (insert)"; + afl->stage_short = "ext_AI"; + afl->stage_cur = 0; + afl->stage_max = afl->a_extras_cnt * (len + 1); + + orig_hit_cnt = new_hit_cnt; + + ex_tmp = afl_realloc(AFL_BUF_PARAM(ex), len + MAX_DICT_FILE); + if (unlikely(!ex_tmp)) { PFATAL("alloc"); } + + for (i = 0; i <= (u32)len; ++i) { + + afl->stage_cur_byte = i; + + for (j = 0; j < afl->a_extras_cnt; ++j) { + + if (len + afl->a_extras[j].len > MAX_FILE) { + + --afl->stage_max; + continue; + + } + + /* Insert token */ + memcpy(ex_tmp + i, afl->a_extras[j].data, afl->a_extras[j].len); + + /* Copy tail */ + memcpy(ex_tmp + i + afl->a_extras[j].len, out_buf + i, len - i); + +#ifdef INTROSPECTION + snprintf(afl->mutation, sizeof(afl->mutation), + "%s MOPT_AUTO_EXTRAS_insert-%u-%u", afl->queue_cur->fname, i, j); +#endif + + if (common_fuzz_stuff(afl, ex_tmp, len + afl->a_extras[j].len)) { + + goto abandon_entry; + + } + + ++afl->stage_cur; + + } + + /* Copy head */ + ex_tmp[i] = out_buf[i]; + + } /* for i = 0; i <= len */ + + new_hit_cnt = afl->queued_items + afl->saved_crashes; + + afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt; + afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max; + skip_extras: /* If we made this to here without jumping to havoc_stage or abandon_entry, @@ -4464,14 +4589,14 @@ pacemaker_fuzzing: havoc_queued = afl->queued_items; - u32 r_max; + u32 r_max, r; - r_max = 15 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0); + r_max = 16 + ((afl->extras_cnt + afl->a_extras_cnt) ? 2 : 0); if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) { /* add expensive havoc cases here, they are activated after a full - cycle without finds happened */ + cycle without any finds happened */ ++r_max; @@ -4497,7 +4622,7 @@ pacemaker_fuzzing: for (i = 0; i < use_stacking; ++i) { - switch (select_algorithm(afl, r_max)) { + switch (r = (select_algorithm(afl, r_max))) { case 0: /* Flip a single bit somewhere. Spooky! */ @@ -4914,192 +5039,196 @@ pacemaker_fuzzing: } /* case 15 */ + default: { + /* Values 16 and 17 can be selected only if there are any extras present in the dictionaries. */ - case 16: { + r -= 16; + + if (r == 0 && (afl->extras_cnt || afl->a_extras_cnt)) { - /* Overwrite bytes with an extra. */ + /* Overwrite bytes with an extra. */ - if (!afl->extras_cnt || - (afl->a_extras_cnt && rand_below(afl, 2))) { + if (!afl->extras_cnt || + (afl->a_extras_cnt && rand_below(afl, 2))) { - /* No user-specified extras or odds in our favor. Let's use an - auto-detected one. */ + /* No user-specified extras or odds in our favor. Let's use an + auto-detected one. */ - u32 use_extra = rand_below(afl, afl->a_extras_cnt); - u32 extra_len = afl->a_extras[use_extra].len; + u32 use_extra = rand_below(afl, afl->a_extras_cnt); + u32 extra_len = afl->a_extras[use_extra].len; - if (extra_len > (u32)temp_len) break; + if (extra_len > (u32)temp_len) break; - u32 insert_at = rand_below(afl, temp_len - extra_len + 1); + u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len); + strcat(afl->mutation, afl->m_tmp); #endif - memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, - extra_len); + memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, + extra_len); - } else { + } else { - /* No auto extras or odds in our favor. Use the dictionary. */ + /* No auto extras or odds in our favor. Use the dictionary. */ - u32 use_extra = rand_below(afl, afl->extras_cnt); - u32 extra_len = afl->extras[use_extra].len; + u32 use_extra = rand_below(afl, afl->extras_cnt); + u32 extra_len = afl->extras[use_extra].len; - if (extra_len > (u32)temp_len) break; + if (extra_len > (u32)temp_len) break; - u32 insert_at = rand_below(afl, temp_len - extra_len + 1); + u32 insert_at = rand_below(afl, temp_len - extra_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " EXTRA_OVERWRITE-%u-%u", insert_at, extra_len); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " EXTRA_OVERWRITE-%u-%u", insert_at, extra_len); + strcat(afl->mutation, afl->m_tmp); #endif - memcpy(out_buf + insert_at, afl->extras[use_extra].data, - extra_len); + memcpy(out_buf + insert_at, afl->extras[use_extra].data, + extra_len); - } + } - MOpt_globals.cycles_v2[STAGE_OverWriteExtra]++; + MOpt_globals.cycles_v2[STAGE_OverWriteExtra]++; - break; + break; - } + } /* Insert an extra. */ - case 17: { + else if (r == 1 && (afl->extras_cnt || afl->a_extras_cnt)) { - u32 use_extra, extra_len, - insert_at = rand_below(afl, temp_len + 1); - u8 *ptr; + u32 use_extra, extra_len, + insert_at = rand_below(afl, temp_len + 1); + u8 *ptr; - /* Insert an extra. Do the same dice-rolling stuff as for the - previous case. */ + /* Insert an extra. Do the same dice-rolling stuff as for the + previous case. */ - if (!afl->extras_cnt || - (afl->a_extras_cnt && rand_below(afl, 2))) { + if (!afl->extras_cnt || + (afl->a_extras_cnt && rand_below(afl, 2))) { - use_extra = rand_below(afl, afl->a_extras_cnt); - extra_len = afl->a_extras[use_extra].len; - ptr = afl->a_extras[use_extra].data; + use_extra = rand_below(afl, afl->a_extras_cnt); + extra_len = afl->a_extras[use_extra].len; + ptr = afl->a_extras[use_extra].data; #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len); + strcat(afl->mutation, afl->m_tmp); #endif - } else { + } else { - use_extra = rand_below(afl, afl->extras_cnt); - extra_len = afl->extras[use_extra].len; - ptr = afl->extras[use_extra].data; + use_extra = rand_below(afl, afl->extras_cnt); + extra_len = afl->extras[use_extra].len; + ptr = afl->extras[use_extra].data; #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_INSERT-%u-%u", - insert_at, extra_len); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " EXTRA_INSERT-%u-%u", insert_at, extra_len); + strcat(afl->mutation, afl->m_tmp); #endif - } - - if (temp_len + extra_len >= MAX_FILE) break; + } - out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len); - if (unlikely(!out_buf)) { PFATAL("alloc"); } + if (temp_len + extra_len >= MAX_FILE) break; - /* Tail */ - memmove(out_buf + insert_at + extra_len, out_buf + insert_at, - temp_len - insert_at); + out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len); + if (unlikely(!out_buf)) { PFATAL("alloc"); } - /* Inserted part */ - memcpy(out_buf + insert_at, ptr, extra_len); + /* Tail */ + memmove(out_buf + insert_at + extra_len, out_buf + insert_at, + temp_len - insert_at); - temp_len += extra_len; - MOpt_globals.cycles_v2[STAGE_InsertExtra]++; - break; + /* Inserted part */ + memcpy(out_buf + insert_at, ptr, extra_len); - } + temp_len += extra_len; + MOpt_globals.cycles_v2[STAGE_InsertExtra]++; + break; - default: { + } else { - if (unlikely(afl->ready_for_splicing_count < 2)) break; + if (unlikely(afl->ready_for_splicing_count < 2)) break; - u32 tid; - do { + u32 tid; + do { - tid = rand_below(afl, afl->queued_items); + tid = rand_below(afl, afl->queued_items); - } while (tid == afl->current_entry || + } while (tid == afl->current_entry || - afl->queue_buf[tid]->len < 4); + afl->queue_buf[tid]->len < 4); - /* Get the testcase for splicing. */ - struct queue_entry *target = afl->queue_buf[tid]; - u32 new_len = target->len; - u8 * new_buf = queue_testcase_get(afl, target); + /* Get the testcase for splicing. */ + struct queue_entry *target = afl->queue_buf[tid]; + u32 new_len = target->len; + u8 * new_buf = queue_testcase_get(afl, target); - if ((temp_len >= 2 && rand_below(afl, 2)) || - temp_len + HAVOC_BLK_XL >= MAX_FILE) { + if ((temp_len >= 2 && rand_below(afl, 2)) || + temp_len + HAVOC_BLK_XL >= MAX_FILE) { - /* overwrite mode */ + /* overwrite mode */ - u32 copy_from, copy_to, copy_len; + u32 copy_from, copy_to, copy_len; - copy_len = choose_block_len(afl, new_len - 1); - if (copy_len > temp_len) copy_len = temp_len; + copy_len = choose_block_len(afl, new_len - 1); + if (copy_len > temp_len) copy_len = temp_len; - copy_from = rand_below(afl, new_len - copy_len + 1); - copy_to = rand_below(afl, temp_len - copy_len + 1); + copy_from = rand_below(afl, new_len - copy_len + 1); + copy_to = rand_below(afl, temp_len - copy_len + 1); #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to, - copy_len, target->fname); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to, + copy_len, target->fname); + strcat(afl->mutation, afl->m_tmp); #endif - memmove(out_buf + copy_to, new_buf + copy_from, copy_len); + memmove(out_buf + copy_to, new_buf + copy_from, copy_len); - } else { + } else { - /* insert mode */ + /* insert mode */ - u32 clone_from, clone_to, clone_len; + u32 clone_from, clone_to, clone_len; - clone_len = choose_block_len(afl, new_len); - clone_from = rand_below(afl, new_len - clone_len + 1); - clone_to = rand_below(afl, temp_len + 1); + clone_len = choose_block_len(afl, new_len); + clone_from = rand_below(afl, new_len - clone_len + 1); + clone_to = rand_below(afl, temp_len + 1); - u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), - temp_len + clone_len + 1); - if (unlikely(!temp_buf)) { PFATAL("alloc"); } + u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), + temp_len + clone_len + 1); + if (unlikely(!temp_buf)) { PFATAL("alloc"); } #ifdef INTROSPECTION - snprintf(afl->m_tmp, sizeof(afl->m_tmp), - " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to, - clone_len, target->fname); - strcat(afl->mutation, afl->m_tmp); + snprintf(afl->m_tmp, sizeof(afl->m_tmp), + " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to, + clone_len, target->fname); + strcat(afl->mutation, afl->m_tmp); #endif - /* Head */ + /* Head */ - memcpy(temp_buf, out_buf, clone_to); + memcpy(temp_buf, out_buf, clone_to); - /* Inserted part */ + /* Inserted part */ - memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); + memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len); - /* Tail */ - memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, - temp_len - clone_to); + /* Tail */ + memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to, + temp_len - clone_to); - out_buf = temp_buf; - afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); - temp_len += clone_len; + out_buf = temp_buf; + afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); + temp_len += clone_len; - } + } - MOpt_globals.cycles_v2[STAGE_Splice]++; - break; + MOpt_globals.cycles_v2[STAGE_Splice]++; + break; + + } } // end of default: diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index ffba3475..09e773f0 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -74,7 +74,7 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { rewound and truncated. */ u32 __attribute__((hot)) -write_to_testcase(afl_state_t *afl, void *mem, u32 len, u32 fix) { +write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { #ifdef _AFL_DOCUMENT_MUTATIONS s32 doc_fd; @@ -86,7 +86,7 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len, u32 fix) { if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION)) >= 0) { - if (write(doc_fd, mem, len) != len) + if (write(doc_fd, *mem, len) != len) PFATAL("write to mutation file failed: %s", fn); close(doc_fd); @@ -97,7 +97,7 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len, u32 fix) { if (unlikely(afl->custom_mutators_count)) { ssize_t new_size = len; - u8 * new_mem = mem; + u8 * new_mem = *mem; u8 * new_buf = NULL; LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { @@ -130,8 +130,14 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len, u32 fix) { } + if (new_mem != *mem) { + + *mem = new_mem; + + } + /* everything as planned. use the potentially new data. */ - afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size); + afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size); len = new_size; } else { @@ -147,7 +153,7 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len, u32 fix) { } /* boring uncustom. */ - afl_fsrv_write_to_testcase(&afl->fsrv, mem, len); + afl_fsrv_write_to_testcase(&afl->fsrv, *mem, len); } @@ -370,7 +376,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, /* we need a dummy run if this is LTO + cmplog */ if (unlikely(afl->shm.cmplog_mode)) { - (void)write_to_testcase(afl, use_mem, q->len, 1); + (void)write_to_testcase(afl, (void **)&use_mem, q->len, 1); fault = fuzz_run_target(afl, &afl->fsrv, use_tmout); @@ -413,7 +419,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, u64 cksum; - (void)write_to_testcase(afl, use_mem, q->len, 1); + (void)write_to_testcase(afl, (void **)&use_mem, q->len, 1); fault = fuzz_run_target(afl, &afl->fsrv, use_tmout); @@ -724,7 +730,7 @@ void sync_fuzzers(afl_state_t *afl) { /* See what happens. We rely on save_if_interesting() to catch major errors and save the test case. */ - (void)write_to_testcase(afl, mem, st.st_size, 1); + (void)write_to_testcase(afl, (void **)&mem, st.st_size, 1); fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); @@ -967,7 +973,7 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { u8 fault; - len = write_to_testcase(afl, out_buf, len, 0); + len = write_to_testcase(afl, (void **)&out_buf, len, 0); fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 9737c692..5b237748 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1021,13 +1021,15 @@ void show_stats_normal(afl_state_t *afl) { if (unlikely(!afl->skip_deterministic)) { - sprintf(tmp, "%s/%s, %s/%s, %s/%s", + sprintf(tmp, "%s/%s, %s/%s, %s/%s, %s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_EXTRAS_UO]), u_stringify_int(IB(1), afl->stage_cycles[STAGE_EXTRAS_UO]), u_stringify_int(IB(2), afl->stage_finds[STAGE_EXTRAS_UI]), u_stringify_int(IB(3), afl->stage_cycles[STAGE_EXTRAS_UI]), u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]), - u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO])); + u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO]), + u_stringify_int(IB(6), afl->stage_finds[STAGE_EXTRAS_AI]), + u_stringify_int(IB(7), afl->stage_cycles[STAGE_EXTRAS_AI])); } else if (unlikely(!afl->extras_cnt || afl->custom_only)) { @@ -1839,13 +1841,15 @@ void show_stats_pizza(afl_state_t *afl) { if (unlikely(!afl->skip_deterministic)) { - sprintf(tmp, "%s/%s, %s/%s, %s/%s", + sprintf(tmp, "%s/%s, %s/%s, %s/%s, %s/%s", u_stringify_int(IB(0), afl->stage_finds[STAGE_EXTRAS_UO]), u_stringify_int(IB(1), afl->stage_cycles[STAGE_EXTRAS_UO]), u_stringify_int(IB(2), afl->stage_finds[STAGE_EXTRAS_UI]), u_stringify_int(IB(3), afl->stage_cycles[STAGE_EXTRAS_UI]), u_stringify_int(IB(4), afl->stage_finds[STAGE_EXTRAS_AO]), - u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO])); + u_stringify_int(IB(5), afl->stage_cycles[STAGE_EXTRAS_AO]), + u_stringify_int(IB(6), afl->stage_finds[STAGE_EXTRAS_AI]), + u_stringify_int(IB(7), afl->stage_cycles[STAGE_EXTRAS_AI])); } else if (unlikely(!afl->extras_cnt || afl->custom_only)) { diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c index 8d58bb3e..b48c6fb3 100644 --- a/src/afl-sharedmem.c +++ b/src/afl-sharedmem.c @@ -107,7 +107,7 @@ void afl_shm_deinit(sharedmem_t *shm) { if (shm->cmp_map != NULL) { munmap(shm->cmp_map, shm->map_size); - shm->map = NULL; + shm->cmp_map = NULL; } @@ -153,6 +153,8 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, shm->g_shm_fd = -1; shm->cmplog_g_shm_fd = -1; + const int shmflags = O_RDWR | O_EXCL; + /* ====== generate random file name for multi instance @@ -161,9 +163,39 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, so we do this worse workaround */ snprintf(shm->g_shm_file_path, L_tmpnam, "/afl_%d_%ld", getpid(), random()); + #ifdef SHM_LARGEPAGE_ALLOC_DEFAULT + /* trying to get large memory segment optimised and monitorable separately as + * such */ + static size_t sizes[4] = {(size_t)-1}; + static int psizes = 0; + int i; + if (sizes[0] == (size_t)-1) { psizes = getpagesizes(sizes, 4); } + + /* very unlikely to fail even if the arch supports only two sizes */ + if (likely(psizes > 0)) { + + for (i = psizes - 1; shm->g_shm_fd == -1 && i >= 0; --i) { + + if (sizes[i] == 0 || map_size % sizes[i]) { continue; } + + shm->g_shm_fd = + shm_create_largepage(shm->g_shm_file_path, shmflags, i, + SHM_LARGEPAGE_ALLOC_DEFAULT, DEFAULT_PERMISSION); + + } + + } + + #endif + /* create the shared memory segment as if it was a file */ - shm->g_shm_fd = shm_open(shm->g_shm_file_path, O_CREAT | O_RDWR | O_EXCL, - DEFAULT_PERMISSION); + if (shm->g_shm_fd == -1) { + + shm->g_shm_fd = + shm_open(shm->g_shm_file_path, shmflags | O_CREAT, DEFAULT_PERMISSION); + + } + if (shm->g_shm_fd == -1) { PFATAL("shm_open() failed"); } /* configure the size of the shared memory segment */ diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index cda1d700..77fc69b5 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -09ad7d4784e50ec4ddf590a2c29764e2a7f37442 +c3e15a7d |