From 13cc3409c0c21e4ecc112173f0c570b92024a12c Mon Sep 17 00:00:00 2001 From: Cameron Bytheway Date: Tue, 11 Jun 2024 10:03:22 -0600 Subject: [PATCH] honggfuzz: update to 2.6 --- lib/bolero-honggfuzz/Cargo.toml | 2 +- lib/bolero-honggfuzz/build.rs | 1 + lib/bolero-honggfuzz/honggfuzz/Android.mk | 8 +- lib/bolero-honggfuzz/honggfuzz/Makefile | 62 ++- lib/bolero-honggfuzz/honggfuzz/arch.h | 2 + lib/bolero-honggfuzz/honggfuzz/cmdline.c | 21 + lib/bolero-honggfuzz/honggfuzz/display.c | 8 +- lib/bolero-honggfuzz/honggfuzz/fuzz.c | 75 +++- lib/bolero-honggfuzz/honggfuzz/honggfuzz.c | 35 +- lib/bolero-honggfuzz/honggfuzz/honggfuzz.h | 14 +- lib/bolero-honggfuzz/honggfuzz/input.c | 146 ++++++- lib/bolero-honggfuzz/honggfuzz/input.h | 3 + .../honggfuzz/libhfcommon/files.c | 4 +- .../honggfuzz/libhfcommon/log.c | 8 + .../honggfuzz/libhfcommon/ns.c | 3 +- .../honggfuzz/libhfcommon/util.c | 8 +- .../honggfuzz/libhfcommon/util.h | 39 +- .../honggfuzz/libhfnetdriver/netdriver.c | 8 +- .../honggfuzz/libhfuzz/fetch.c | 2 +- .../honggfuzz/libhfuzz/instrument.c | 66 ++- .../honggfuzz/libhfuzz/memorycmp.c | 54 +++ lib/bolero-honggfuzz/honggfuzz/linux/arch.c | 3 + lib/bolero-honggfuzz/honggfuzz/linux/bfd.c | 34 +- lib/bolero-honggfuzz/honggfuzz/linux/perf.c | 5 +- lib/bolero-honggfuzz/honggfuzz/linux/pt.c | 2 +- lib/bolero-honggfuzz/honggfuzz/linux/trace.c | 317 +++++++++----- lib/bolero-honggfuzz/honggfuzz/mac/arch.c | 11 + lib/bolero-honggfuzz/honggfuzz/mangle.c | 29 +- lib/bolero-honggfuzz/honggfuzz/netbsd/arch.c | 3 + lib/bolero-honggfuzz/honggfuzz/netbsd/trace.c | 4 +- lib/bolero-honggfuzz/honggfuzz/posix/arch.c | 37 ++ lib/bolero-honggfuzz/honggfuzz/sanitizers.c | 2 +- .../android/patches/libunwind.patch | 406 ------------------ .../android/scripts/compile-capstone.sh | 57 +-- .../scripts/compile-libBlocksRuntime.sh | 31 +- .../android/scripts/compile-libunwind.sh | 88 +--- lib/bolero-honggfuzz/update.sh | 2 +- tests/src/cargo_bolero.rs | 10 +- 38 files changed, 824 insertions(+), 786 deletions(-) delete mode 100644 lib/bolero-honggfuzz/honggfuzz/third_party/android/patches/libunwind.patch diff --git a/lib/bolero-honggfuzz/Cargo.toml b/lib/bolero-honggfuzz/Cargo.toml index 0e0d8caf..c8d6e2ca 100644 --- a/lib/bolero-honggfuzz/Cargo.toml +++ b/lib/bolero-honggfuzz/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bolero-honggfuzz" -version = "0.11.0" +version = "0.11.2" authors = ["Cameron Bytheway "] description = "honggfuzz plugin for bolero" homepage = "https://github.com/camshaft/bolero" diff --git a/lib/bolero-honggfuzz/build.rs b/lib/bolero-honggfuzz/build.rs index 9ca360e3..1b3045f7 100644 --- a/lib/bolero-honggfuzz/build.rs +++ b/lib/bolero-honggfuzz/build.rs @@ -20,6 +20,7 @@ fn build(target: &str, file: &str, lib: &str) -> String { let status = Command::new(MAKE_COMMAND) .args(["-C", "honggfuzz", target, "libhfcommon/libhfcommon.a"]) + .env("CFLAGS", "-O3 -mtune=native -funroll-loops -fPIE") .status() .unwrap(); assert!(status.success()); diff --git a/lib/bolero-honggfuzz/honggfuzz/Android.mk b/lib/bolero-honggfuzz/honggfuzz/Android.mk index e7be0f2f..c334fb5a 100644 --- a/lib/bolero-honggfuzz/honggfuzz/Android.mk +++ b/lib/bolero-honggfuzz/honggfuzz/Android.mk @@ -137,7 +137,7 @@ COMMON_CFLAGS := -std=c11 \ -Wall -Wextra -Wno-initializer-overrides -Wno-override-init \ -Wno-atomic-alignment -Wno-unknown-warning-option \ -Werror -funroll-loops -O2 \ - -Wframe-larger-than=1048576 -Wno-format-truncation \ + -Wno-format-truncation \ ifneq (,$(findstring clang,$(NDK_TOOLCHAIN))) COMMON_CFLAGS += -fblocks -fno-sanitize=address,undefined,memory,thread -fsanitize-coverage=0 @@ -146,7 +146,7 @@ endif # libhfcommon module include $(CLEAR_VARS) -LOCAL_MODULE := common +LOCAL_MODULE := hfcommon LOCAL_SRC_FILES := $(wildcard libhfcommon/*.c) LOCAL_CFLAGS := -D_HF_ARCH_${ARCH} $(COMMON_CFLAGS) LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBS) @@ -175,8 +175,8 @@ include $(CLEAR_VARS) LOCAL_MODULE := honggfuzz LOCAL_SRC_FILES := $(wildcard *.c) LOCAL_CFLAGS := $(COMMON_CFLAGS) -LOCAL_LDFLAGS := -lm -latomic -LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBS) common +LOCAL_LDFLAGS := -lm -latomic -lz +LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBS) hfcommon ifeq ($(ANDROID_WITH_PTRACE),true) LOCAL_STATIC_LIBRARIES += libunwind-arch \ diff --git a/lib/bolero-honggfuzz/honggfuzz/Makefile b/lib/bolero-honggfuzz/honggfuzz/Makefile index d38ebc85..df8c9e7a 100644 --- a/lib/bolero-honggfuzz/honggfuzz/Makefile +++ b/lib/bolero-honggfuzz/honggfuzz/Makefile @@ -27,7 +27,7 @@ BIN := honggfuzz HFUZZ_CC_BIN := hfuzz_cc/hfuzz-cc HFUZZ_CC_SRCS := hfuzz_cc/hfuzz-cc.c COMMON_CFLAGS := -std=c11 -I/usr/local/include -D_GNU_SOURCE -Wall -Wextra -Werror -Wno-format-truncation -Wno-override-init -I. -COMMON_LDFLAGS := -pthread -lm +COMMON_LDFLAGS := -pthread -L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lm COMMON_SRCS := $(sort $(wildcard *.c)) CFLAGS ?= -O3 -mtune=native -funroll-loops LDFLAGS ?= @@ -36,6 +36,7 @@ GREP_COLOR ?= BUILD_OSSFUZZ_STATIC ?= false # for https://github.com/google/oss-fuzz BUILD_LINUX_NO_BFD ?= false # for users who don't want to use libbfd/binutils +REALOS = $(shell uname -s) OS ?= $(shell uname -s) MARCH ?= $(shell uname -m) KERNEL ?= $(shell uname -r) @@ -82,24 +83,37 @@ else ifeq ($(OS),Darwin) # Figure out which crash reporter to use. CRASHWRANGLER := third_party/mac OS_VERSION := $(shell sw_vers -productVersion) - ifneq (,$(findstring 10.15,$(OS_VERSION))) - CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o - else ifneq (,$(findstring 10.14,$(OS_VERSION))) + OS_MAJOR_VERSION := $(shell echo $(OS_VERSION) | cut -f1 -d.) + OS_MINOR_VERSION := $(shell echo $(OS_VERSION) | cut -f2 -d.) + + ifeq ($(OS_MAJOR_VERSION), 13) CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o - else ifneq (,$(findstring 10.13,$(OS_VERSION))) + else ifeq ($(OS_MAJOR_VERSION), 12) CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o - else ifneq (,$(findstring 10.12,$(OS_VERSION))) + else ifeq ($(OS_MAJOR_VERSION), 11) CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o - else ifneq (,$(findstring 10.11,$(OS_VERSION))) - # El Capitan didn't break compatibility - CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Yosemite.o - else ifneq (,$(findstring 10.10,$(OS_VERSION))) - CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Yosemite.o - else ifneq (,$(findstring 10.9,$(OS_VERSION))) - CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Mavericks.o - else ifneq (,$(findstring 10.8,$(OS_VERSION))) - CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Mountain_Lion.o - else + else ifeq ($(OS_MAJOR_VERSION), 10) + ifeq ($(OS_MINOR_VERSION), 15) + CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o + else ifeq ($(OS_MINOR_VERSION), 14) + CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o + else ifeq ($(OS_MINOR_VERSION), 13) + CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o + else ifeq ($(OS_MINOR_VERSION), 12) + CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Sierra.o + else ifeq ($(OS_MINOR_VERSION), 11) + # El Capitan didn't break compatibility + CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Yosemite.o + else ifeq ($(OS_MINOR_VERSION), 10) + CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Yosemite.o + else ifeq ($(OS_MINOR_VERSION), 9) + CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Mavericks.o + else ifeq ($(OS_MINOR_VERSION), 8) + CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Mountain_Lion.o + endif + endif + + ifeq ($(CRASH_REPORT), ) $(error Unsupported MAC OS X version) endif @@ -121,7 +135,7 @@ else ifeq ($(OS),Darwin) -Wno-embedded-directive ARCH_LDFLAGS := -F/System/Library/PrivateFrameworks -framework CoreSymbolication -framework IOKit \ -F$(SDK_V)/System/Library/Frameworks -F$(SDK_V)/System/Library/PrivateFrameworks \ - -F$(SDK)/System/Library/Frameworks \ + -F$(SDK)/System/Library/Frameworks -F$(SDK)/System/Library/PrivateFrameworks \ -framework Foundation -framework ApplicationServices -framework Symbolication \ -framework CoreServices -framework CrashReporterSupport -framework CoreFoundation \ -framework CommerceKit $(CRASH_REPORT) @@ -150,9 +164,11 @@ else ARCH_CFLAGS += -D_POSIX_C_SOURCE=200809L -D__EXTENSIONS__=1 ARCH_LDFLAGS += -lkstat -lsocket -lnsl endif - ifneq ($(OS),OpenBSD) + ifneq ($(REALOS),OpenBSD) + ifneq ($(REALOS),Darwin) ARCH_LDFLAGS += -lrt endif + endif # OS Posix endif @@ -167,7 +183,7 @@ ifeq ($(COMPILER),clang) ARCH_CFLAGS += -mllvm -inline-threshold=2000 CFLAGS_BLOCKS = -fblocks - ifneq ($(OS),Darwin) + ifneq ($(REALOS),Darwin) ARCH_LDFLAGS += -Wl,-Bstatic -lBlocksRuntime -Wl,-Bdynamic endif endif @@ -202,9 +218,9 @@ ifdef DEBUG endif # Control Android builds -ANDROID_API ?= android-26 # Minimal working version is android-23 +ANDROID_API ?= android-30 # Minimal working version is android-30 (ndk 22) ANDROID_DEBUG_ENABLED ?= false -ANDROID_APP_ABI ?= armeabi-v7a +ANDROID_APP_ABI ?= arm64-v8a ANDROID_SKIP_CLEAN ?= false NDK_BUILD_ARGS := @@ -317,7 +333,7 @@ depend: all .PHONY: android android: $(info ***************************************************************) - $(info * Use Android NDK 20 or newer *) + $(info * Use Android NDK 22 or newer *) $(info ***************************************************************) @ANDROID_API=$(ANDROID_API) ANDROID_NDK_COMPILER_PREFIX=$(ANDROID_NDK_COMPILER_PREFIX) third_party/android/scripts/compile-libunwind.sh \ third_party/android/libunwind $(ANDROID_ARCH_CPU) @@ -415,7 +431,7 @@ libhfcommon/files.o: libhfcommon/common.h libhfcommon/log.h libhfcommon/files.o: libhfcommon/util.h libhfcommon/log.o: libhfcommon/log.h libhfcommon/common.h libhfcommon/util.h libhfcommon/ns.o: libhfcommon/ns.h libhfcommon/common.h libhfcommon/files.h -libhfcommon/ns.o: libhfcommon/common.h libhfcommon/log.h +libhfcommon/ns.o: libhfcommon/common.h libhfcommon/log.h libhfcommon/util.h libhfcommon/util.o: libhfcommon/util.h libhfcommon/common.h libhfcommon/util.o: libhfcommon/files.h libhfcommon/common.h libhfcommon/util.o: libhfcommon/log.h diff --git a/lib/bolero-honggfuzz/honggfuzz/arch.h b/lib/bolero-honggfuzz/honggfuzz/arch.h index 39c5609a..c6402da7 100644 --- a/lib/bolero-honggfuzz/honggfuzz/arch.h +++ b/lib/bolero-honggfuzz/honggfuzz/arch.h @@ -36,6 +36,8 @@ extern pid_t arch_fork(run_t* run); extern void arch_reapChild(run_t* run); +extern void arch_reapKill(void); + extern void arch_prepareParent(run_t* run); extern void arch_prepareParentAfterFork(run_t* run); diff --git a/lib/bolero-honggfuzz/honggfuzz/cmdline.c b/lib/bolero-honggfuzz/honggfuzz/cmdline.c index d2cf1eb4..19a1ad55 100644 --- a/lib/bolero-honggfuzz/honggfuzz/cmdline.c +++ b/lib/bolero-honggfuzz/honggfuzz/cmdline.c @@ -355,6 +355,7 @@ bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) { .runEndTime = 0, .tmOut = 1, .lastCovUpdate = time(NULL), + .exitOnTime = 0, .timeOfLongestUnitUSecs = 0, .tmoutVTALRM = false, }, @@ -500,6 +501,7 @@ bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) { { { "pprocess_cmd", required_argument, NULL, 0x111 }, "External command postprocessing files produced by internal mutators" }, { { "ffmutate_cmd", required_argument, NULL, 0x110 }, "External command mutating files which have effective coverage feedback" }, { { "run_time", required_argument, NULL, 0x109 }, "Number of seconds this fuzzing session will last (default: 0 [no limit])" }, + { { "exit_on_time", required_argument, NULL, 0x10A }, "Stop fuzzing session if no new coverage was found for this number of seconds (default: 0 [no limit])" }, { { "iterations", required_argument, NULL, 'N' }, "Number of fuzzing iterations (default: 0 [no limit])" }, { { "rlimit_as", required_argument, NULL, 0x100 }, "Per process RLIMIT_AS in MiB (default: 0 [default limit])" }, { { "rlimit_rss", required_argument, NULL, 0x101 }, "Per process RLIMIT_RSS in MiB (default: 0 [default limit]). It will also set *SAN's soft_rss_limit_mb" }, @@ -525,6 +527,8 @@ bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) { { { "export_feedback", no_argument, NULL, 0x10E }, "Export the coverage feedback structure as ./hfuzz-feedback" }, { { "const_feedback", required_argument, NULL, 0x112 }, "Use constant integer/string values from fuzzed programs to mangle input files via a dynamic dictionary (default: true)" }, { { "pin_thread_cpu", required_argument, NULL, 0x114 }, "Pin a single execution thread to this many consecutive CPUs (default: 0 = no CPU pinning)" }, + { { "dynamic_input", required_argument, NULL, 0x115 }, "Path to a directory containing the dynamic file corpus" }, + { { "statsfile", required_argument, NULL, 0x116 }, "Stats file" }, #if defined(_HF_ARCH_LINUX) { { "linux_symbols_bl", required_argument, NULL, 0x504 }, "Symbols blocklist filter file (one entry per line)" }, @@ -549,6 +553,9 @@ bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) { { { "netbsd_symbols_al", required_argument, NULL, 0x505 }, "Symbols allowlist filter file (one entry per line)" }, { { "netbsd_addr_low_limit", required_argument, NULL, 0x500 }, "Address limit (from si.si_addr) below which crashes are not reported, (default: 0)" }, #endif // defined(_HF_ARCH_NETBSD) +#if defined(__FreeBSD__) + { { "fbsd_keep_aslr", no_argument, NULL, 0x501 }, "Don't disable ASLR randomization, might be useful with MSAN" }, +#endif { { 0, 0, 0, 0 }, NULL }, }; // clang-format on @@ -685,6 +692,9 @@ bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) { hfuzz->timing.runEndTime = time(NULL) + p; } } break; + case 0x10A: + hfuzz->timing.exitOnTime = atol(optarg); + break; case 'N': hfuzz->mutate.mutationsMax = atol(optarg); break; @@ -796,6 +806,17 @@ bool cmdlineParse(int argc, char* argv[], honggfuzz_t* hfuzz) { hfuzz->arch_netbsd.symsWlFile = optarg; break; #endif /* defined(_HF_ARCH_NETBSD) */ +#if defined(__FreeBSD__) + case 0x501: + hfuzz->arch_linux.disableRandomization = false; + break; +#endif + case 0x115: + hfuzz->io.dynamicInputDir = optarg; + break; + case 0x116: + hfuzz->io.statsFileName = optarg; + break; default: cmdlineHelp(argv[0], custom_opts); return false; diff --git a/lib/bolero-honggfuzz/honggfuzz/display.c b/lib/bolero-honggfuzz/honggfuzz/display.c index 06b0dcec..55961fd0 100644 --- a/lib/bolero-honggfuzz/honggfuzz/display.c +++ b/lib/bolero-honggfuzz/honggfuzz/display.c @@ -114,7 +114,7 @@ static unsigned getCpuUse(int numCpus) { #if defined(__linux__) || defined(__CYGWIN__) FILE* f = fopen("/proc/stat", "re"); - if (f == NULL) { + if (UNLIKELY(f == NULL)) { return 0; } defer { @@ -130,7 +130,7 @@ static unsigned getCpuUse(int numCpus) { long off = 0; size_t cpuDataLen = sizeof(long) * CPUSTATES * numCpus; long* cpuData = malloc(cpuDataLen); - if (cpuData == NULL) { + if (UNLIKELY(cpuData == NULL)) { return 0; } @@ -233,7 +233,7 @@ static unsigned getCpuUse(int numCpus) { prevIdleT = idleT; uint64_t allCycles = userCycles + niceCycles + systemCycles + idleCycles; - if (allCycles == 0) { + if (UNLIKELY(allCycles == 0)) { return 0; } @@ -417,7 +417,7 @@ void display_display(honggfuzz_t* hfuzz) { uint64_t softCntCmp = ATOMIC_GET(hfuzz->feedback.hwCnts.softCntCmp); uint64_t guardNb = ATOMIC_GET(hfuzz->feedback.covFeedbackMap->guardNb); display_put(" edge: " ESC_BOLD "%" _HF_NONMON_SEP PRIu64 ESC_RESET "/" - "%" _HF_NONMON_SEP PRIu64 " [%" PRId64 "%%]", + "%" _HF_NONMON_SEP PRIu64 " [%" PRId64 "%%]", softCntEdge, guardNb, guardNb ? ((softCntEdge * 100) / guardNb) : 0); display_put(" pc: " ESC_BOLD "%" _HF_NONMON_SEP PRIu64 ESC_RESET, softCntPc); display_put(" cmp: " ESC_BOLD "%" _HF_NONMON_SEP PRIu64 ESC_RESET, softCntCmp); diff --git a/lib/bolero-honggfuzz/honggfuzz/fuzz.c b/lib/bolero-honggfuzz/honggfuzz/fuzz.c index 2112c692..398cae34 100644 --- a/lib/bolero-honggfuzz/honggfuzz/fuzz.c +++ b/lib/bolero-honggfuzz/honggfuzz/fuzz.c @@ -178,29 +178,38 @@ static void fuzz_perfFeedback(run_t* run) { if (run->global->feedback.skipFeedbackOnTimeout && run->tmOutSignaled) { return; } + if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) { + return; + } MX_SCOPED_LOCK(&run->global->mutex.feedback); defer { wmb(); }; - uint64_t softNewPC = ATOMIC_GET(run->global->feedback.covFeedbackMap->pidNewPC[run->fuzzNo]); - ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidNewPC[run->fuzzNo]); - uint64_t softCurPC = ATOMIC_GET(run->global->feedback.covFeedbackMap->pidTotalPC[run->fuzzNo]); - ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidTotalPC[run->fuzzNo]); + uint64_t softNewPC = 0; + uint64_t softCurPC = 0; + uint64_t softNewEdge = 0; + uint64_t softCurEdge = 0; + uint64_t softNewCmp = 0; + uint64_t softCurCmp = 0; - uint64_t softNewEdge = - ATOMIC_GET(run->global->feedback.covFeedbackMap->pidNewEdge[run->fuzzNo]); - ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidNewEdge[run->fuzzNo]); - uint64_t softCurEdge = - ATOMIC_GET(run->global->feedback.covFeedbackMap->pidTotalEdge[run->fuzzNo]); - ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidTotalEdge[run->fuzzNo]); + if (run->global->feedback.dynFileMethod & _HF_DYNFILE_SOFT) { + softNewPC = ATOMIC_GET(run->global->feedback.covFeedbackMap->pidNewPC[run->fuzzNo]); + ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidNewPC[run->fuzzNo]); + softCurPC = ATOMIC_GET(run->global->feedback.covFeedbackMap->pidTotalPC[run->fuzzNo]); + ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidTotalPC[run->fuzzNo]); - uint64_t softNewCmp = ATOMIC_GET(run->global->feedback.covFeedbackMap->pidNewCmp[run->fuzzNo]); - ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidNewCmp[run->fuzzNo]); - uint64_t softCurCmp = - ATOMIC_GET(run->global->feedback.covFeedbackMap->pidTotalCmp[run->fuzzNo]); - ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidTotalCmp[run->fuzzNo]); + softNewEdge = ATOMIC_GET(run->global->feedback.covFeedbackMap->pidNewEdge[run->fuzzNo]); + ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidNewEdge[run->fuzzNo]); + softCurEdge = ATOMIC_GET(run->global->feedback.covFeedbackMap->pidTotalEdge[run->fuzzNo]); + ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidTotalEdge[run->fuzzNo]); + + softNewCmp = ATOMIC_GET(run->global->feedback.covFeedbackMap->pidNewCmp[run->fuzzNo]); + ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidNewCmp[run->fuzzNo]); + softCurCmp = ATOMIC_GET(run->global->feedback.covFeedbackMap->pidTotalCmp[run->fuzzNo]); + ATOMIC_CLEAR(run->global->feedback.covFeedbackMap->pidTotalCmp[run->fuzzNo]); + } rmb(); @@ -229,6 +238,37 @@ static void fuzz_perfFeedback(run_t* run) { softNewPC, softNewCmp, run->hwCnts.cpuInstrCnt, run->hwCnts.cpuBranchCnt, run->hwCnts.bbCnt, softCurEdge, softCurPC, softCurCmp); + if (run->global->io.statsFileName) { + const time_t curr_sec = time(NULL); + const time_t elapsed_sec = curr_sec - run->global->timing.timeStart; + size_t curr_exec_cnt = ATOMIC_GET(run->global->cnts.mutationsCnt); + /* + * We increase the mutation counter unconditionally in threads, but if it's + * above hfuzz->mutationsMax we don't really execute the fuzzing loop. + * Therefore at the end of fuzzing, the mutation counter might be higher + * than hfuzz->mutationsMax + */ + if (run->global->mutate.mutationsMax > 0 && + curr_exec_cnt > run->global->mutate.mutationsMax) { + curr_exec_cnt = run->global->mutate.mutationsMax; + } + size_t tot_exec_per_sec = elapsed_sec ? (curr_exec_cnt / elapsed_sec) : 0; + + dprintf(run->global->io.statsFileFd, + "%lu, %lu, %lu, %lu, " + "%" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 "\n", + curr_sec, /* unix_time */ + run->global->timing.lastCovUpdate, /* last_cov_update */ + curr_exec_cnt, /* total_exec */ + tot_exec_per_sec, /* exec_per_sec */ + run->global->cnts.crashesCnt, /* crashes */ + run->global->cnts.uniqueCrashesCnt, /* unique_crashes */ + run->global->cnts.timeoutedCnt, /* hangs */ + run->global->feedback.hwCnts.softCntEdge, /* edge_cov */ + run->global->feedback.hwCnts.softCntPc /* block_cov */ + ); + } + /* Update per-input coverage metrics */ run->dynfile->cov[0] = softCurEdge + softCurPC + run->hwCnts.bbCnt; run->dynfile->cov[1] = softCurCmp; @@ -488,6 +528,9 @@ static void* fuzz_threadNew(void* arg) { .persistentSock = -1, .tmOutSignaled = false, }; + defer { + free(run.dynfile); + }; /* Do not try to handle input files with socketfuzzer */ char mapname[32]; @@ -553,6 +596,8 @@ static void* fuzz_threadNew(void* arg) { } } + arch_reapKill(); + if (run.pid) { kill(run.pid, SIGKILL); } diff --git a/lib/bolero-honggfuzz/honggfuzz/honggfuzz.c b/lib/bolero-honggfuzz/honggfuzz/honggfuzz.c index 0b3edce7..deaace5f 100644 --- a/lib/bolero-honggfuzz/honggfuzz/honggfuzz.c +++ b/lib/bolero-honggfuzz/honggfuzz/honggfuzz.c @@ -23,16 +23,22 @@ */ #include +#include #include #include #include #include #include #include +#include #include #include #include +#if defined(__FreeBSD__) +#include +#endif + #include "cmdline.h" #include "display.h" #include "fuzz.h" @@ -260,6 +266,11 @@ static uint8_t mainThreadLoop(honggfuzz_t* hfuzz) { setupMainThreadTimer(); for (;;) { + if (hfuzz->io.dynamicInputDir) { + LOG_D("Loading files from the dynamic input queue..."); + input_enqueueDynamicInputs(hfuzz); + } + if (hfuzz->display.useScreen) { if (ATOMIC_XCHG(clearWin, false)) { display_clear(); @@ -278,6 +289,12 @@ static uint8_t mainThreadLoop(honggfuzz_t* hfuzz) { LOG_I("Maximum run time reached, terminating"); break; } + if (hfuzz->timing.exitOnTime > 0 && + time(NULL) - ATOMIC_GET(hfuzz->timing.lastCovUpdate) > hfuzz->timing.exitOnTime) { + LOG_I("No new coverage was found for the last %ld seconds, terminating", + hfuzz->timing.exitOnTime); + break; + } pingThreads(hfuzz); pause(); } @@ -303,7 +320,7 @@ static const char* strYesNo(bool yes) { } static const char* getGitVersion() { - static char version[] = "$Id: 380cf14962c64e3fa902d9442b6c6513869116ed $"; + static char version[] = "$Id: ebacfad1f3e0766351149de883b54a16a6017071 $"; if (strlen(version) == 47) { version[45] = '\0'; return &version[5]; @@ -399,6 +416,18 @@ int honggfuzz_main(int argc, char** argv) { sizeof(cmpfeedback_t), hfuzz.io.workDir); } } + /* Stats file. */ + if (hfuzz.io.statsFileName) { + hfuzz.io.statsFileFd = + TEMP_FAILURE_RETRY(open(hfuzz.io.statsFileName, O_CREAT | O_RDWR | O_TRUNC, 0640)); + + if (hfuzz.io.statsFileFd == -1) { + PLOG_F("Couldn't open statsfile open('%s')", hfuzz.io.statsFileName); + } else { + dprintf(hfuzz.io.statsFileFd, "# unix_time, last_cov_update, total_exec, exec_per_sec, " + "crashes, unique_crashes, hangs, edge_cov, block_cov\n"); + } + } setupRLimits(); setupSignalsPreThreads(); @@ -433,6 +462,10 @@ int honggfuzz_main(int argc, char** argv) { if (hfuzz.socketFuzzer.enabled) { cleanupSocketFuzzer(); } + /* Stats file. */ + if (hfuzz.io.statsFileName) { + close(hfuzz.io.statsFileFd); + } printSummary(&hfuzz); diff --git a/lib/bolero-honggfuzz/honggfuzz/honggfuzz.h b/lib/bolero-honggfuzz/honggfuzz/honggfuzz.h index 2b07d6aa..e0926fe3 100644 --- a/lib/bolero-honggfuzz/honggfuzz/honggfuzz.h +++ b/lib/bolero-honggfuzz/honggfuzz/honggfuzz.h @@ -39,7 +39,7 @@ #include "libhfcommon/util.h" #define PROG_NAME "honggfuzz" -#define PROG_VERSION "2.5" +#define PROG_VERSION "2.6" /* Name of the template which will be replaced with the proper name of the file */ #define _HF_FILE_PLACEHOLDER "___FILE___" @@ -153,6 +153,7 @@ struct _dynfile_t { char path[PATH_MAX]; struct _dynfile_t* src; uint32_t refs; + fuzzState_t phase; uint8_t* data; TAILQ_ENTRY(_dynfile_t) pointers; }; @@ -215,7 +216,10 @@ typedef struct { dynfile_t* dynfileqCurrent; dynfile_t* dynfileq2Current; TAILQ_HEAD(dyns_t, _dynfile_t) dynfileq; - bool exportFeedback; + bool exportFeedback; + const char* dynamicInputDir; + const char* statsFileName; + int statsFileFd; } io; struct { int argc; @@ -242,6 +246,7 @@ typedef struct { time_t runEndTime; time_t tmOut; time_t lastCovUpdate; + time_t exitOnTime; int64_t timeOfLongestUnitUSecs; bool tmoutVTALRM; } timing; @@ -370,10 +375,7 @@ typedef struct { int perThreadCovFeedbackFd; unsigned triesLeft; dynfile_t* current; -#if !defined(_HF_ARCH_DARWIN) - timer_t timerId; -#endif // !defined(_HF_ARCH_DARWIN) - hwcnt_t hwCnts; + hwcnt_t hwCnts; struct { /* For Linux code */ diff --git a/lib/bolero-honggfuzz/honggfuzz/input.c b/lib/bolero-honggfuzz/honggfuzz/input.c index 3998235a..a03b6674 100644 --- a/lib/bolero-honggfuzz/honggfuzz/input.c +++ b/lib/bolero-honggfuzz/honggfuzz/input.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -379,6 +380,7 @@ void input_addDynamicInput(run_t* run) { if (run->dynfile->src) { ATOMIC_POST_INC(run->dynfile->src->refs); } + dynfile->phase = fuzz_getState(run->global); input_generateFileName(dynfile, NULL, dynfile->path); MX_SCOPED_RWLOCK_WRITE(&run->global->mutex.dynfileq); @@ -458,11 +460,6 @@ static inline int input_speedFactor(run_t* run, dynfile_t* dynfile) { } static inline int input_skipFactor(run_t* run, dynfile_t* dynfile, int* speed_factor) { - /* - * TODO: measure impact of the skipFactor on the speed of fuzzing. - * It's currently unsure how much it helps, so disable it for now, - * and re-enable once proper test has been conducted - */ int penalty = 0; #if 1 @@ -495,7 +492,7 @@ static inline int input_skipFactor(run_t* run, dynfile_t* dynfile, int* speed_fa { /* Older inputs -> lower chance of being tested */ static const int scaleMap[200] = { - [98 ... 199] = -3, + [98 ... 199] = -20, [91 ... 97] = -2, [81 ... 90] = -1, [71 ... 80] = 0, @@ -503,8 +500,10 @@ static inline int input_skipFactor(run_t* run, dynfile_t* dynfile, int* speed_fa [0 ... 40] = 2, }; - const unsigned percentile = (dynfile->idx * 100) / run->global->io.dynfileqCnt; - penalty += scaleMap[percentile]; + if (dynfile->phase == _HF_STATE_DYNAMIC_MAIN) { + const unsigned percentile = (dynfile->idx * 100) / run->global->io.dynfileqCnt; + penalty += scaleMap[percentile]; + } } #endif @@ -564,6 +563,7 @@ bool input_prepareDynamicInput(run_t* run, bool needs_mangle) { run->dynfile->timeExecUSecs = run->current->timeExecUSecs; run->dynfile->src = run->current; run->dynfile->refs = 0; + run->dynfile->phase = fuzz_getState(run->global); memcpy(run->dynfile->cov, run->current->cov, sizeof(run->dynfile->cov)); snprintf(run->dynfile->path, sizeof(run->dynfile->path), "%s", run->current->path); memcpy(run->dynfile->data, run->current->data, run->current->size); @@ -575,6 +575,127 @@ bool input_prepareDynamicInput(run_t* run, bool needs_mangle) { return true; } +bool input_dynamicQueueGetNext(char fname[PATH_MAX], DIR* dynamicDirPtr, char* dynamicWorkDir) { + static pthread_mutex_t input_mutex = PTHREAD_MUTEX_INITIALIZER; + MX_SCOPED_LOCK(&input_mutex); + + for (;;) { + errno = 0; + struct dirent* entry = readdir(dynamicDirPtr); + if (entry == NULL && errno == EINTR) { + continue; + } + if (entry == NULL && errno != 0) { + PLOG_W("readdir_r('%s')", dynamicWorkDir); + return false; + } + if (entry == NULL) { + return false; + } + char path[PATH_MAX]; + snprintf(path, PATH_MAX, "%s/%s", dynamicWorkDir, entry->d_name); + struct stat st; + if (stat(path, &st) == -1) { + LOG_W("Couldn't stat() the '%s' file", path); + continue; + } + if (!S_ISREG(st.st_mode)) { + LOG_D("'%s' is not a regular file, skipping", path); + continue; + } + + snprintf(fname, PATH_MAX, "%s/%s", dynamicWorkDir, entry->d_name); + return true; + } +} + +void input_enqueueDynamicInputs(honggfuzz_t* hfuzz) { + char dynamicWorkDir[PATH_MAX]; + + snprintf(dynamicWorkDir, sizeof(dynamicWorkDir), "%s", hfuzz->io.dynamicInputDir); + + int dynamicDirFd = TEMP_FAILURE_RETRY(open(dynamicWorkDir, O_DIRECTORY | O_RDONLY | O_CLOEXEC)); + if (dynamicDirFd == -1) { + PLOG_W("open('%s', O_DIRECTORY|O_RDONLY|O_CLOEXEC)", dynamicWorkDir); + return; + } + + DIR* dynamicDirPtr; + if ((dynamicDirPtr = fdopendir(dynamicDirFd)) == NULL) { + PLOG_W("fdopendir(dir='%s', fd=%d)", dynamicWorkDir, dynamicDirFd); + close(dynamicDirFd); + return; + } + + char dynamicInputFileName[PATH_MAX]; + for (;;) { + if (!input_dynamicQueueGetNext(dynamicInputFileName, dynamicDirPtr, dynamicWorkDir)) { + break; + } + + int dynamicFileFd; + if ((dynamicFileFd = open(dynamicInputFileName, O_RDWR)) == -1) { + PLOG_E("Error opening dynamic input file: %s", dynamicInputFileName); + continue; + } + + /* Get file status. */ + struct stat dynamicFileStat; + size_t dynamicFileSz; + + if (fstat(dynamicFileFd, &dynamicFileStat) == -1) { + PLOG_E("Error getting file status: %s", dynamicInputFileName); + close(dynamicFileFd); + continue; + } + + dynamicFileSz = dynamicFileStat.st_size; + + uint8_t* dynamicFile = (uint8_t*)mmap( + NULL, dynamicFileSz, PROT_READ | PROT_WRITE, MAP_SHARED, dynamicFileFd, 0); + + if (dynamicFile == MAP_FAILED) { + PLOG_E("Error mapping dynamic input file: %s", dynamicInputFileName); + close(dynamicFileFd); + continue; + } + + LOG_I("Loading dynamic input file: %s (%lu)", dynamicInputFileName, dynamicFileSz); + + run_t tmp_run; + tmp_run.global = hfuzz; + dynfile_t tmp_dynfile = { + .size = dynamicFileSz, + .cov = {0xff, 0xff, 0xff, 0xff}, + .idx = 0, + .fd = -1, + .timeExecUSecs = 1, + .path = "", + .data = dynamicFile, + }; + tmp_run.timeStartedUSecs = util_timeNowUSecs() - 1; + memcpy(tmp_dynfile.path, dynamicInputFileName, PATH_MAX); + tmp_run.dynfile = &tmp_dynfile; + input_addDynamicInput(&tmp_run); + // input_addDynamicInput(hfuzz, dynamicFile, dynamicFileSz, (uint64_t[4]){0xff, 0xff, 0xff, + // 0xff}, dynamicInputFileName); + + /* Unmap input file. */ + if (munmap((void*)dynamicFile, dynamicFileSz) == -1) { + PLOG_E("Error unmapping input file!"); + } + + /* Close input file. */ + if (close(dynamicFileFd) == -1) { + PLOG_E("Error closing input file!"); + } + + /* Remove enqueued file from the directory. */ + unlink(dynamicInputFileName); + } + closedir(dynamicDirPtr); +} + const uint8_t* input_getRandomInputAsBuf(run_t* run, size_t* len) { if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) { LOG_W( @@ -658,10 +779,11 @@ bool input_prepareStaticFile(run_t* run, bool rewind, bool needs_mangle) { } input_setSize(run, fileSz); - memset(run->dynfile->cov, '\0', sizeof(run->dynfile->cov)); - run->dynfile->idx = 0; - run->dynfile->src = NULL; - run->dynfile->refs = 0; + util_memsetInline(run->dynfile->cov, '\0', sizeof(run->dynfile->cov)); + run->dynfile->idx = 0; + run->dynfile->src = NULL; + run->dynfile->refs = 0; + run->dynfile->phase = fuzz_getState(run->global); if (needs_mangle) { mangle_mangleContent(run, /* slow_factor= */ 0); diff --git a/lib/bolero-honggfuzz/honggfuzz/input.h b/lib/bolero-honggfuzz/honggfuzz/input.h index 3163223b..aa36b2b4 100644 --- a/lib/bolero-honggfuzz/honggfuzz/input.h +++ b/lib/bolero-honggfuzz/honggfuzz/input.h @@ -49,5 +49,8 @@ extern bool input_removeStaticFile(const char* dir, const char* name); extern bool input_prepareExternalFile(run_t* run); extern bool input_postProcessFile(run_t* run, const char* cmd); extern bool input_prepareDynamicFileForMinimization(run_t* run); +extern bool input_dynamicQueueGetNext( + char fname[PATH_MAX], DIR* dynamicDirPtr, char* dynamicWorkDir); +extern void input_enqueueDynamicInputs(honggfuzz_t* hfuzz); #endif /* ifndef _HF_INPUT_H_ */ diff --git a/lib/bolero-honggfuzz/honggfuzz/libhfcommon/files.c b/lib/bolero-honggfuzz/honggfuzz/libhfcommon/files.c index 5a7763ec..9dcf576c 100644 --- a/lib/bolero-honggfuzz/honggfuzz/libhfcommon/files.c +++ b/lib/bolero-honggfuzz/honggfuzz/libhfcommon/files.c @@ -223,11 +223,11 @@ bool files_resetFile(int fd, size_t sz) { #endif /* defined(_HF_ARCH_LINUX) */ /* Fallback mode */ - if (ftruncate(fd, (off_t)0) == -1) { + if (TEMP_FAILURE_RETRY(ftruncate(fd, (off_t)0)) == -1) { PLOG_W("ftruncate(fd=%d, sz=0)", fd); return false; } - if (ftruncate(fd, (off_t)sz) == -1) { + if (TEMP_FAILURE_RETRY(ftruncate(fd, (off_t)sz)) == -1) { PLOG_W("ftruncate(fd=%d, sz=%zu)", fd, sz); return false; } diff --git a/lib/bolero-honggfuzz/honggfuzz/libhfcommon/log.c b/lib/bolero-honggfuzz/honggfuzz/libhfcommon/log.c index 27b3e444..f2e56681 100644 --- a/lib/bolero-honggfuzz/honggfuzz/libhfcommon/log.c +++ b/lib/bolero-honggfuzz/honggfuzz/libhfcommon/log.c @@ -59,6 +59,10 @@ __attribute__((constructor)) static void log_init(void) { hf_log_fd = STDERR_FILENO; } hf_log_fd_isatty = isatty(hf_log_fd); + + if (getenv("NO_COLOR")) { + hf_log_fd_isatty = false; + } } /* @@ -80,6 +84,10 @@ void logInitLogFile(const char* logfile, int fd, enum llevel_t ll) { } hf_log_fd_isatty = (isatty(hf_log_fd) == 1 ? true : false); + + if (getenv("NO_COLOR")) { + hf_log_fd_isatty = false; + } } void logLog(enum llevel_t ll, const char* fn, int ln, bool perr, const char* fmt, ...) { diff --git a/lib/bolero-honggfuzz/honggfuzz/libhfcommon/ns.c b/lib/bolero-honggfuzz/honggfuzz/libhfcommon/ns.c index 55fbaa65..2e71bd6d 100644 --- a/lib/bolero-honggfuzz/honggfuzz/libhfcommon/ns.c +++ b/lib/bolero-honggfuzz/honggfuzz/libhfcommon/ns.c @@ -26,6 +26,7 @@ #include "libhfcommon/common.h" #include "libhfcommon/files.h" #include "libhfcommon/log.h" +#include "libhfcommon/util.h" #if defined(_HF_ARCH_LINUX) @@ -104,7 +105,7 @@ bool nsIfaceUp(const char* ifacename) { } struct ifreq ifr; - memset(&ifr, '\0', sizeof(ifr)); + util_memsetInline(&ifr, '\0', sizeof(ifr)); snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", ifacename); if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) { diff --git a/lib/bolero-honggfuzz/honggfuzz/libhfcommon/util.c b/lib/bolero-honggfuzz/honggfuzz/libhfcommon/util.c index 876391c9..9802e5a7 100644 --- a/lib/bolero-honggfuzz/honggfuzz/libhfcommon/util.c +++ b/lib/bolero-honggfuzz/honggfuzz/libhfcommon/util.c @@ -28,7 +28,7 @@ #include #include #include -#if !defined(_HF_ARCH_DARWIN) && !defined(__CYGWIN__) +#if !defined(_HF_ARCH_DARWIN) && !defined(__CYGWIN__) && !defined(__APPLE__) #include #endif /* !defined(_HF_ARCH_DARWIN) && !defined(__CYGWIN__) */ #include @@ -397,13 +397,13 @@ void util_sleepForMSec(uint64_t msec) { uint64_t util_getUINT32(const uint8_t* buf) { uint32_t r; - memcpy(&r, buf, sizeof(r)); + util_memcpyInline(&r, buf, sizeof(r)); return (uint64_t)r; } uint64_t util_getUINT64(const uint8_t* buf) { uint64_t r; - memcpy(&r, buf, sizeof(r)); + util_memcpyInline(&r, buf, sizeof(r)); return r; } @@ -951,7 +951,7 @@ const char* util_sigName(int signo) { #define _HF_COMMON_BIN_COLLECT_VALS false #endif /* !defined(_HF_COMMON_BIN_COLLECT_VALS) */ -#if !defined(_HF_ARCH_DARWIN) && !defined(__CYGWIN__) +#if !defined(_HF_ARCH_DARWIN) && !defined(__CYGWIN__) && !defined(__APPLE__) static int addrStatic_cb(struct dl_phdr_info* info, size_t size HF_ATTR_UNUSED, void* data) { for (size_t i = 0; i < info->dlpi_phnum; i++) { if (info->dlpi_phdr[i].p_type != PT_LOAD) { diff --git a/lib/bolero-honggfuzz/honggfuzz/libhfcommon/util.h b/lib/bolero-honggfuzz/honggfuzz/libhfcommon/util.h index d7e21009..4ad5f0d6 100644 --- a/lib/bolero-honggfuzz/honggfuzz/libhfcommon/util.h +++ b/lib/bolero-honggfuzz/honggfuzz/libhfcommon/util.h @@ -107,6 +107,35 @@ static void __attribute__((unused)) __clang_cleanup_func(void (^*dfunc)(void)) { #define MX_RWLOCK_WRITE(m) util_mutexRWLockWrite(m, __func__, __LINE__) #define MX_RWLOCK_UNLOCK(m) util_mutexRWUnlock(m, __func__, __LINE__) +#define LIKELY(cond) __builtin_expect(!!(cond), true) +#define UNLIKELY(cond) __builtin_expect(!!(cond), false) + +#if !defined(__has_builtin) +#define __has_builtin(b) 0 +#endif + +#if !__has_builtin(__builtin_memcpy_inline) +#define util_memcpyInline(x, y, s) \ + do { \ + _Static_assert( \ + __builtin_choose_expr(__builtin_constant_p(s), 1, 0), "len must be a constant"); \ + __builtin_memcpy(x, y, s); \ + } while (0) +#else +#define util_memcpyInline(x, y, s) __builtin_memcpy_inline(x, y, s) +#endif + +#if !__has_builtin(__builtin_memset_inline) +#define util_memsetInline(x, y, s) \ + do { \ + _Static_assert( \ + __builtin_choose_expr(__builtin_constant_p(s), 1, 0), "len must be a constant"); \ + __builtin_memset(x, y, s); \ + } while (0) +#else +#define util_memsetInline(x, y, s) __builtin_memset_inline(x, y, s) +#endif + /* Atomics */ #define ATOMIC_GET(x) __atomic_load_n(&(x), __ATOMIC_RELAXED) #define ATOMIC_SET(x, y) __atomic_store_n(&(x), y, __ATOMIC_RELAXED) @@ -165,10 +194,10 @@ typedef enum { extern void util_ParentDeathSigIfAvail(int signo); extern bool util_PinThreadToCPUs(uint32_t startcpu, uint32_t cpucnt); -extern void* util_Malloc(size_t sz); -extern void* util_Calloc(size_t sz); -extern void* util_AllocCopy(const uint8_t* ptr, size_t sz); -extern void* util_MMap(size_t sz); +extern void* util_Malloc(size_t sz) __attribute__((__malloc__)); +extern void* util_Calloc(size_t sz) __attribute__((__malloc__)); +extern void* util_AllocCopy(const uint8_t* ptr, size_t sz) __attribute__((__malloc__)); +extern void* util_MMap(size_t sz) __attribute__((__malloc__)); extern void* util_Realloc(void* ptr, size_t sz); extern uint64_t util_rndGet(uint64_t min, uint64_t max); @@ -177,7 +206,7 @@ extern void util_rndBufPrintable(uint8_t* buf, size_t sz); extern uint64_t util_rnd64(void); extern uint8_t util_rndPrintable(void); -extern char* util_StrDup(const char* s); +extern char* util_StrDup(const char* s) __attribute__((__malloc__)); extern int util_ssnprintf(char* str, size_t size, const char* format, ...) __attribute__((format(printf, 3, 4))); extern int util_vssnprintf(char* str, size_t size, const char* format, va_list ap); diff --git a/lib/bolero-honggfuzz/honggfuzz/libhfnetdriver/netdriver.c b/lib/bolero-honggfuzz/honggfuzz/libhfnetdriver/netdriver.c index b4230c31..3e11f71a 100644 --- a/lib/bolero-honggfuzz/honggfuzz/libhfnetdriver/netdriver.c +++ b/lib/bolero-honggfuzz/honggfuzz/libhfnetdriver/netdriver.c @@ -282,7 +282,7 @@ static const char *netDriver_getSockPath(int argc HF_ATTR_UNUSED, char **argv HF } static __thread char path[PATH_MAX] = {}; - const char * sock_path = getenv(HFND_SOCK_PATH_ENV); + const char *sock_path = getenv(HFND_SOCK_PATH_ENV); /* If it starts with '/' it's an absolute path */ if (sock_path && sock_path[0] == '/') { snprintf(path, sizeof(path), "%s", sock_path); @@ -349,9 +349,9 @@ static bool netDriver_checkIfServerReady(int argc, char **argv) { /* Next, try TCP4 and TCP6 connections to the localhost */ const uint16_t tcp_port = netDriver_getTCPPort(argc, argv); const struct sockaddr_in addr4 = { - .sin_family = PF_INET, - .sin_port = htons(tcp_port), - .sin_addr.s_addr = htonl(INADDR_LOOPBACK), + .sin_family = PF_INET, + .sin_port = htons(tcp_port), + .sin_addr.s_addr = htonl(INADDR_LOOPBACK), }; if (netDriver_connAndAssign((const struct sockaddr *)&addr4, sizeof(addr4), SOCK_STREAM, 0)) { return true; diff --git a/lib/bolero-honggfuzz/honggfuzz/libhfuzz/fetch.c b/lib/bolero-honggfuzz/honggfuzz/libhfuzz/fetch.c index f8f2fd04..46a67d6d 100644 --- a/lib/bolero-honggfuzz/honggfuzz/libhfuzz/fetch.c +++ b/lib/bolero-honggfuzz/honggfuzz/libhfuzz/fetch.c @@ -36,7 +36,7 @@ __attribute__((constructor)) static void init(void) { */ static void fetchSanPoison(const uint8_t* buf, size_t len) { /* MacOS X linker doesn't like those */ -#if defined(_HF_ARCH_DARWIN) +#if defined(_HF_ARCH_DARWIN) || defined(__APPLE__) return; #endif /* defined(_HF_ARCH_DARWIN) */ __attribute__((weak)) extern void __asan_unpoison_memory_region(const void* addr, size_t sz); diff --git a/lib/bolero-honggfuzz/honggfuzz/libhfuzz/instrument.c b/lib/bolero-honggfuzz/honggfuzz/libhfuzz/instrument.c index 0db6e86e..f72f1f7b 100644 --- a/lib/bolero-honggfuzz/honggfuzz/libhfuzz/instrument.c +++ b/lib/bolero-honggfuzz/honggfuzz/libhfuzz/instrument.c @@ -52,7 +52,7 @@ cmpfeedback_t* globalCmpFeedback = NULL; uint32_t my_thread_no = 0; -static int _memcmp(const void* m1, const void* m2, size_t n) { +__attribute__((hot)) static int _memcmp(const void* m1, const void* m2, size_t n) { const unsigned char* s1 = (const unsigned char*)m1; const unsigned char* s2 = (const unsigned char*)m2; @@ -65,9 +65,17 @@ static int _memcmp(const void* m1, const void* m2, size_t n) { return 0; } -int (*libc_memcmp)(const void* s1, const void* s2, size_t n) = _memcmp; +int (*hf_memcmp)(const void* s1, const void* s2, size_t n) = _memcmp; + +static void* getsym(const char* fname, const char* sym) { + if (fname) { + void* dlh = dlopen(fname, RTLD_LAZY); + if (!dlh) { + return NULL; + } + return dlsym(dlh, sym); + } -static void* getsym(const char* sym) { #if defined(RTLD_NEXT) return dlsym(RTLD_NEXT, sym); #else /* defined(RTLD_NEXT) */ @@ -79,16 +87,48 @@ static void* getsym(const char* sym) { #endif /* defined(RTLD_NEXT) */ } +extern int __wrap_memcmp(const void* s1, const void* s2, size_t n) __attribute__((weak)); +extern int __sanitizer_weak_hook_memcmp(const void* s1, const void* s2, size_t n) + __attribute__((weak)); static void initializeLibcFunctions(void) { - libc_memcmp = (int (*)(const void* s1, const void* s2, size_t n))getsym("memcmp"); - if (!libc_memcmp) { - LOG_W("dlsym(memcmp) failed: %s", dlerror()); - libc_memcmp = _memcmp; + /* + * Look for the original "memcmp" function. + * + * First, in standard C libraries, because if an instrumented shared library is loaded, it can + * overshadow the libc's symbol. Next, among the already loaded symbols. + */ + int (*libcso6_memcmp)(const void* s1, const void* s2, size_t n) = + (int (*)(const void* s1, const void* s2, size_t n))getsym("libc.so.6", "memcmp"); + int (*libcso_memcmp)(const void* s1, const void* s2, size_t n) = + (int (*)(const void* s1, const void* s2, size_t n))getsym("libc.so", "memcmp"); + int (*libc_memcmp)(const void* s1, const void* s2, size_t n) = + (int (*)(const void* s1, const void* s2, size_t n))getsym(NULL, "memcmp"); + + if (libcso6_memcmp) { + hf_memcmp = libcso6_memcmp; + } else if (libcso_memcmp) { + hf_memcmp = libcso_memcmp; + } else if (libc_memcmp) { + hf_memcmp = libc_memcmp; + } + + if (hf_memcmp == __wrap_memcmp) { + LOG_W("hf_memcmp==__wrap_memcmp: %p==%p", hf_memcmp, __wrap_memcmp); + hf_memcmp = _memcmp; } - LOG_D("libc_memcmp=%p, (_memcmp=%p, memcmp=%p)", libc_memcmp, _memcmp, memcmp); + if (hf_memcmp == __sanitizer_weak_hook_memcmp) { + LOG_W("hf_memcmp==__sanitizer_weak_hook_memcmp: %p==%p", hf_memcmp, + __sanitizer_weak_hook_memcmp); + hf_memcmp = _memcmp; + } + + LOG_D("hf_memcmp=%p, (_memcmp=%p, memcmp=%p, __wrap_memcmp=%p, " + "__sanitizer_weak_hook_memcmp=%p, libcso6_memcmp=%p, libcso_memcmp=%p, libc_memcmp=%p)", + hf_memcmp, _memcmp, memcmp, __wrap_memcmp, __sanitizer_weak_hook_memcmp, libcso6_memcmp, + libcso_memcmp, libc_memcmp); } -static void* initialzeTryMapHugeTLB(int fd, size_t sz) { +static void* initializeTryMapHugeTLB(int fd, size_t sz) { int initflags = MAP_SHARED; #if defined(MAP_ALIGNED_SUPER) initflags |= MAP_ALIGNED_SUPER; @@ -117,7 +157,7 @@ static void initializeCmpFeedback(void) { (size_t)st.st_size, sizeof(cmpfeedback_t)); return; } - void* ret = initialzeTryMapHugeTLB(_HF_CMP_BITMAP_FD, sizeof(cmpfeedback_t)); + void* ret = initializeTryMapHugeTLB(_HF_CMP_BITMAP_FD, sizeof(cmpfeedback_t)); if (ret == MAP_FAILED) { PLOG_W("mmap(_HF_CMP_BITMAP_FD=%d, size=%zu) of the feedback structure failed", _HF_CMP_BITMAP_FD, sizeof(cmpfeedback_t)); @@ -138,7 +178,7 @@ static bool initializeLocalCovFeedback(void) { return false; } - localCovFeedback = initialzeTryMapHugeTLB(_HF_PERTHREAD_BITMAP_FD, sizeof(feedback_t)); + localCovFeedback = initializeTryMapHugeTLB(_HF_PERTHREAD_BITMAP_FD, sizeof(feedback_t)); if (localCovFeedback == MAP_FAILED) { PLOG_W("mmap(_HF_PERTHREAD_BITMAP_FD=%d, size=%zu) of the local feedback structure failed", _HF_PERTHREAD_BITMAP_FD, sizeof(feedback_t)); @@ -159,7 +199,7 @@ static bool initializeGlobalCovFeedback(void) { return false; } - globalCovFeedback = initialzeTryMapHugeTLB(_HF_COV_BITMAP_FD, sizeof(feedback_t)); + globalCovFeedback = initializeTryMapHugeTLB(_HF_COV_BITMAP_FD, sizeof(feedback_t)); if (globalCovFeedback == MAP_FAILED) { PLOG_W("mmap(_HF_COV_BITMAP_FD=%d, size=%zu) of the feedback structure failed", _HF_COV_BITMAP_FD, sizeof(feedback_t)); @@ -255,7 +295,7 @@ static inline void instrumentAddConstMemInternal(const void* mem, size_t len) { for (uint32_t i = 0; i < curroff; i++) { if ((len == ATOMIC_GET(globalCmpFeedback->valArr[i].len)) && - libc_memcmp(globalCmpFeedback->valArr[i].val, mem, len) == 0) { + hf_memcmp(globalCmpFeedback->valArr[i].val, mem, len) == 0) { return; } } diff --git a/lib/bolero-honggfuzz/honggfuzz/libhfuzz/memorycmp.c b/lib/bolero-honggfuzz/honggfuzz/libhfuzz/memorycmp.c index e779f1e2..a71ee50b 100644 --- a/lib/bolero-honggfuzz/honggfuzz/libhfuzz/memorycmp.c +++ b/lib/bolero-honggfuzz/honggfuzz/libhfuzz/memorycmp.c @@ -196,6 +196,39 @@ static inline char* HF_strcpy(char* dest, const char* src, uintptr_t addr) { return __builtin_memcpy(dest, src, len + 1); } +static inline char* HF_strcat(char* dest, const char* src, uintptr_t addr) { + size_t len = __builtin_strlen(dest); + return HF_strcpy(dest + len, src, addr); +} + +static inline size_t HF_strlcpy(char* dest, const char* src, size_t sz, uintptr_t addr) { + size_t slen = __builtin_strlen(src); + size_t len = sz < slen ? sz : slen; + + if (sz == 0) { + return 0; + } + /* Make space for NUL at the end of the string. + * sz != 0 here + */ + if (len == sz) { + len--; + } + + if (len > 0) { + instrumentUpdateCmpMap(addr, util_Log2(len)); + (void)__builtin_memcpy(dest, src, len); + } + + dest[len] = '\0'; + return len; +} + +static inline size_t HF_strlcat(char* dest, const char* src, size_t sz, uintptr_t addr) { + size_t len = __builtin_strlen(dest); + return HF_strlcpy(dest + len, src, sz, addr); +} + /* Define a weak function x, as well as __wrap_x pointing to x */ #define XVAL(x) x #define HF_WEAK_WRAP(ret, func, ...) \ @@ -290,6 +323,27 @@ void __sanitizer_weak_hook_strcpy( uintptr_t pc, char* dest, const char* src, char* result HF_ATTR_UNUSED) { HF_strcpy(dest, src, pc); } +HF_WEAK_WRAP(char*, strcat, char* dest, const char* src) { + return HF_strcat(dest, src, (uintptr_t)__builtin_return_address(0)); +} +void __sanitizer_weak_hook_strcat( + uintptr_t pc, char* dest, const char* src, char* result HF_ATTR_UNUSED) { + HF_strcat(dest, src, pc); +} +HF_WEAK_WRAP(size_t, strlcpy, char* dest, const char* src, size_t len) { + return HF_strlcpy(dest, src, len, (uintptr_t)__builtin_return_address(0)); +} +void __sanitizer_weak_hook_strlcpy( + uintptr_t pc, char* dest, const char* src, size_t sz, size_t result HF_ATTR_UNUSED) { + HF_strlcpy(dest, src, sz, pc); +} +HF_WEAK_WRAP(size_t, strlcat, char* dest, const char* src, size_t len) { + return HF_strlcat(dest, src, len, (uintptr_t)__builtin_return_address(0)); +} +void __sanitizer_weak_hook_strlcat( + uintptr_t pc, char* dest, const char* src, size_t sz, size_t result HF_ATTR_UNUSED) { + HF_strlcat(dest, src, sz, pc); +} /* * Apache's httpd wrappers diff --git a/lib/bolero-honggfuzz/honggfuzz/linux/arch.c b/lib/bolero-honggfuzz/honggfuzz/linux/arch.c index a7a9ee0d..f5c562d0 100644 --- a/lib/bolero-honggfuzz/honggfuzz/linux/arch.c +++ b/lib/bolero-honggfuzz/honggfuzz/linux/arch.c @@ -275,6 +275,9 @@ void arch_reapChild(run_t* run) { arch_perfAnalyze(run); } +void arch_reapKill(void) { +} + bool arch_archInit(honggfuzz_t* hfuzz) { /* Make %'d work */ setlocale(LC_NUMERIC, "en_US.UTF-8"); diff --git a/lib/bolero-honggfuzz/honggfuzz/linux/bfd.c b/lib/bolero-honggfuzz/honggfuzz/linux/bfd.c index 69f4da59..98fe9dec 100644 --- a/lib/bolero-honggfuzz/honggfuzz/linux/bfd.c +++ b/lib/bolero-honggfuzz/honggfuzz/linux/bfd.c @@ -55,13 +55,14 @@ typedef struct { asymbol** dsyms; } bfd_t; +/* INFO: binutils (libbfd, libopcode) has an unstable public interface. */ /* - * This is probably the only define which was added with binutils 2.29, so we us - * it, do decide which disassembler() prototype from dis-asm.h to use + * This is probably the only define which was added with binutils 2.29, so we use + * it, do decide which disassembler() prototype from dis-asm.h to use. */ #if defined(FOR_EACH_DISASSEMBLER_OPTION) #define _HF_BFD_GE_2_29 -#endif +#endif /* defined(FOR_EACH_DISASSEMBLER_OPTION) */ static pthread_mutex_t arch_bfd_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -197,6 +198,16 @@ static int arch_bfdFPrintF(void* buf, const char* fmt, ...) { return ret; } +static int arch_bfdFPrintFStyled( + void* buf, enum disassembler_style style HF_ATTR_UNUSED, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + int ret = util_vssnprintf(buf, _HF_INSTR_SZ, fmt, args); + va_end(args); + + return ret; +} + void arch_bfdDisasm(pid_t pid, uint8_t* mem, size_t size, char* instr) { MX_SCOPED_LOCK(&arch_bfd_mutex); @@ -227,8 +238,16 @@ void arch_bfdDisasm(pid_t pid, uint8_t* mem, size_t size, char* instr) { return; } - struct disassemble_info info; - init_disassemble_info(&info, instr, arch_bfdFPrintF); + struct disassemble_info info = {}; + + /* + * At some point in time the function init_disassemble_info() started taking 4 arguments instead + * of 3. Add the 4th argument in all cases. Hopefully it'll work will all ABIs, and the 4th + * argument will be discarded if needed. + */ + void (*idi_4_args)(void*, void*, void*, void*) = + (void (*)(void*, void*, void*, void*))init_disassemble_info; + idi_4_args(&info, instr, arch_bfdFPrintF, arch_bfdFPrintFStyled); info.arch = bfd_get_arch(bfdh); info.mach = bfd_get_mach(bfdh); info.buffer = mem; @@ -242,6 +261,11 @@ void arch_bfdDisasm(pid_t pid, uint8_t* mem, size_t size, char* instr) { snprintf(instr, _HF_INSTR_SZ, "[DIS-ASM_FAILURE]"); } + /* disassemble_free_target is available only since bfd/dis-asm 2019 */ + __attribute__((weak)) void disassemble_free_target(struct disassemble_info*); + if (disassemble_free_target) { + disassemble_free_target(&info); + } bfd_close(bfdh); } diff --git a/lib/bolero-honggfuzz/honggfuzz/linux/perf.c b/lib/bolero-honggfuzz/honggfuzz/linux/perf.c index c2a0b9e1..b40474a6 100644 --- a/lib/bolero-honggfuzz/honggfuzz/linux/perf.c +++ b/lib/bolero-honggfuzz/honggfuzz/linux/perf.c @@ -128,9 +128,8 @@ static bool arch_perfCreate(run_t* run, pid_t pid, dynFileMethod_t method, int* LOG_F("Intel PT events are not supported on this platform"); } - struct perf_event_attr pe; - memset(&pe, 0, sizeof(struct perf_event_attr)); - pe.size = sizeof(struct perf_event_attr); + struct perf_event_attr pe = {}; + pe.size = sizeof(struct perf_event_attr); if (run->global->arch_linux.kernelOnly) { pe.exclude_user = 1; } else { diff --git a/lib/bolero-honggfuzz/honggfuzz/linux/pt.c b/lib/bolero-honggfuzz/honggfuzz/linux/pt.c index 869675bb..ff4d0969 100644 --- a/lib/bolero-honggfuzz/honggfuzz/linux/pt.c +++ b/lib/bolero-honggfuzz/honggfuzz/linux/pt.c @@ -44,7 +44,7 @@ struct pt_cpu ptCpu = { void perf_ptInit(void) { FILE* f = fopen("/proc/cpuinfo", "rb"); - if (!f) { + if (UNLIKELY(!f)) { PLOG_E("Couldn't open '/proc/cpuinfo'"); return; } diff --git a/lib/bolero-honggfuzz/honggfuzz/linux/trace.c b/lib/bolero-honggfuzz/honggfuzz/linux/trace.c index fdde321a..4696ba7e 100644 --- a/lib/bolero-honggfuzz/honggfuzz/linux/trace.c +++ b/lib/bolero-honggfuzz/honggfuzz/linux/trace.c @@ -73,10 +73,12 @@ #define MAX_INSTR_SZ 8 #elif defined(__mips__) || defined(__mips64__) #define MAX_INSTR_SZ 8 +#elif defined(__riscv) +#define MAX_INSTR_SZ 4 #endif #if defined(__i386__) || defined(__x86_64__) -struct user_regs_struct_32 { +struct user_regs_32 { uint32_t ebx; uint32_t ecx; uint32_t edx; @@ -96,7 +98,7 @@ struct user_regs_struct_32 { uint16_t ss, __ss; }; -struct user_regs_struct_64 { +struct user_regs_64 { uint64_t r15; uint64_t r14; uint64_t r13; @@ -125,40 +127,50 @@ struct user_regs_struct_64 { uint64_t fs; uint64_t gs; }; -#define HEADERS_STRUCT struct user_regs_struct_64 + +union user_regs_t { + struct user_regs_32 regs32; + struct user_regs_64 regs64; +}; #endif /* defined(__i386__) || defined(__x86_64__) */ #if defined(__arm__) || defined(__aarch64__) -#ifndef ARM_pc -#ifdef __ANDROID__ /* Building with NDK headers */ -#define ARM_pc uregs[15] -#else /* Building with glibc headers */ -#define ARM_pc 15 -#endif -#endif /* ARM_pc */ -#ifndef ARM_cpsr -#ifdef __ANDROID__ /* Building with NDK headers */ -#define ARM_cpsr uregs[16] -#else /* Building with glibc headers */ -#define ARM_cpsr 16 -#endif -#endif /* ARM_cpsr */ -struct user_regs_struct_32 { - uint32_t uregs[18]; +struct user_regs_32 { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t fp; + uint32_t ip; + uint32_t sp; + uint32_t lr; + uint32_t pc; + uint32_t cpsr; + uint32_t ORIG_r0; }; -struct user_regs_struct_64 { +struct user_regs_64 { uint64_t regs[31]; uint64_t sp; uint64_t pc; uint64_t pstate; }; -#define HEADERS_STRUCT struct user_regs_struct_64 + +union user_regs_t { + struct user_regs_32 regs32; + struct user_regs_64 regs64; +}; #endif /* defined(__arm__) || defined(__aarch64__) */ #if defined(__powerpc64__) || defined(__powerpc__) -#define HEADERS_STRUCT struct pt_regs -struct user_regs_struct_32 { +struct user_regs_32 { uint32_t gpr[32]; uint32_t nip; uint32_t msr; @@ -181,7 +193,8 @@ struct user_regs_struct_32 { uint32_t zero2; uint32_t zero3; }; -struct user_regs_struct_64 { + +struct user_regs_64 { uint64_t gpr[32]; uint64_t nip; uint64_t msr; @@ -204,10 +217,16 @@ struct user_regs_struct_64 { uint64_t zero2; uint64_t zero3; }; + +union user_regs_t { + struct user_regs_32 regs32; + struct user_regs_64 regs64; +}; + #endif /* defined(__powerpc64__) || defined(__powerpc__) */ #if defined(__mips__) || defined(__mips64__) -struct user_regs_struct { +struct user_regs_64 { uint64_t regs[32]; uint64_t lo; @@ -217,19 +236,118 @@ struct user_regs_struct { uint64_t cp0_status; uint64_t cp0_cause; }; -#define HEADERS_STRUCT struct user_regs_struct -#endif /* defined(__mips__) || defined(__mips64__) */ -#if defined(__ANDROID__) /* - * Some Android ABIs don't implement PTRACE_GETREGS (e.g. aarch64) + * Despite what mips linux kernel headers/source code says, mips32 uses the same register laytout as + * mips64 only with GETREGS. With GETREGSET(NT_PRSTATUS) the structure size is 180 bytes + * (ELF_NGREG=45 * sizeof(uint32_t)=4 = 180). It also uses 24-byte padding for some, + * not-entierely-clear, reasons. The structure itself is not defined in the kernel, but only through + * how mips_dump_regs32() saves those registers via via MIPS32_EF_* defines. */ -#if defined(PTRACE_GETREGS) -#define PTRACE_GETREGS_AVAILABLE 1 -#else -#define PTRACE_GETREGS_AVAILABLE 0 -#endif /* defined(PTRACE_GETREGS) */ -#endif /* defined(__ANDROID__) */ +struct user_regs_32 { + uint32_t pad0[6]; + + uint32_t regs[32]; + + uint32_t lo; + uint32_t hi; + uint32_t cp0_epc; + uint32_t cp0_badvaddr; + uint32_t cp0_status; + uint32_t cp0_cause; + uint32_t unused0; +}; + +union user_regs_t { + struct user_regs_32 regs32; + struct user_regs_64 regs64; +}; +#endif /* defined(__mips__) || defined(__mips64__) */ + +#if defined(__riscv) +struct user_regs_64 { + uint64_t epc; + uint64_t ra; + uint64_t sp; + uint64_t gp; + uint64_t tp; + uint64_t t0; + uint64_t t1; + uint64_t t2; + uint64_t s0; + uint64_t s1; + uint64_t a0; + uint64_t a1; + uint64_t a2; + uint64_t a3; + uint64_t a4; + uint64_t a5; + uint64_t a6; + uint64_t a7; + uint64_t s2; + uint64_t s3; + uint64_t s4; + uint64_t s5; + uint64_t s6; + uint64_t s7; + uint64_t s8; + uint64_t s9; + uint64_t s10; + uint64_t s11; + uint64_t t3; + uint64_t t4; + uint64_t t5; + uint64_t t6; + uint64_t status; + uint64_t badaddr; + uint64_t cause; + uint64_t orig_a0; +}; + +struct user_regs_32 { + uint32_t epc; + uint32_t ra; + uint32_t sp; + uint32_t gp; + uint32_t tp; + uint32_t t0; + uint32_t t1; + uint32_t t2; + uint32_t s0; + uint32_t s1; + uint32_t a0; + uint32_t a1; + uint32_t a2; + uint32_t a3; + uint32_t a4; + uint32_t a5; + uint32_t a6; + uint32_t a7; + uint32_t s2; + uint32_t s3; + uint32_t s4; + uint32_t s5; + uint32_t s6; + uint32_t s7; + uint32_t s8; + uint32_t s9; + uint32_t s10; + uint32_t s11; + uint32_t t3; + uint32_t t4; + uint32_t t5; + uint32_t t6; + uint32_t status; + uint32_t badaddr; + uint32_t cause; + uint32_t orig_a0; +}; + +union user_regs_t { + struct user_regs_32 regs32; + struct user_regs_64 regs64; +}; +#endif /* defined(__riscv) */ #if defined(__clang__) _Pragma("clang diagnostic push"); @@ -293,7 +411,7 @@ static size_t arch_getProcMem(pid_t pid, uint8_t* buf, size_t len, uint64_t pc) if (process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0) == (ssize_t)len) { return len; } - // Debug if failed since it shouldn't happen very often + /* Debug if failed since it shouldn't happen very often */ PLOG_D("process_vm_readv() failed"); /* @@ -319,18 +437,7 @@ static size_t arch_getProcMem(pid_t pid, uint8_t* buf, size_t len, uint64_t pc) } static size_t arch_getPC(pid_t pid, uint64_t* pc, uint64_t* status_reg HF_ATTR_UNUSED) { -/* - * Some old ARM android kernels are failing with PTRACE_GETREGS to extract - * the correct register values if struct size is bigger than expected. As such the - * 32/64-bit multiplexing trick is not working for them in case PTRACE_GETREGSET - * fails or is not implemented. To cover such cases we explicitly define - * the struct size to 32bit version for arm CPU. - */ -#if defined(__arm__) - struct user_regs_struct_32 regs; -#else - HEADERS_STRUCT regs; -#endif + union user_regs_t regs; const struct iovec pt_iov = { .iov_base = ®s, .iov_len = sizeof(regs), @@ -338,87 +445,54 @@ static size_t arch_getPC(pid_t pid, uint64_t* pc, uint64_t* status_reg HF_ATTR_U if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &pt_iov) == -1L) { PLOG_D("ptrace(PTRACE_GETREGSET) failed"); - -// If PTRACE_GETREGSET fails, try PTRACE_GETREGS if available -#if PTRACE_GETREGS_AVAILABLE - if (ptrace(PTRACE_GETREGS, pid, 0, ®s)) { - PLOG_D("ptrace(PTRACE_GETREGS) failed"); - LOG_W("ptrace PTRACE_GETREGSET & PTRACE_GETREGS failed to extract target registers"); - return 0; - } -#else return 0; -#endif } + #if defined(__i386__) || defined(__x86_64__) - /* - * 32-bit - */ - if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) { - struct user_regs_struct_32* r32 = (struct user_regs_struct_32*)®s; - *pc = r32->eip; - *status_reg = r32->eflags; + /* 32-bit */ + if (pt_iov.iov_len == sizeof(struct user_regs_32)) { + *pc = regs.regs32.eip; + *status_reg = regs.regs32.eflags; return pt_iov.iov_len; } - - /* - * 64-bit - */ - if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) { - struct user_regs_struct_64* r64 = (struct user_regs_struct_64*)®s; - *pc = r64->ip; - *status_reg = r64->flags; + /* 64-bit */ + if (pt_iov.iov_len == sizeof(struct user_regs_64)) { + *pc = regs.regs64.ip; + *status_reg = regs.regs64.flags; return pt_iov.iov_len; } + LOG_W("Unknown registers structure size: '%zd'", pt_iov.iov_len); return 0; #endif /* defined(__i386__) || defined(__x86_64__) */ #if defined(__arm__) || defined(__aarch64__) - /* - * 32-bit - */ - if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) { - struct user_regs_struct_32* r32 = (struct user_regs_struct_32*)®s; -#ifdef __ANDROID__ - *pc = r32->ARM_pc; - *status_reg = r32->ARM_cpsr; -#else - *pc = r32->uregs[ARM_pc]; - *status_reg = r32->uregs[ARM_cpsr]; -#endif + /* 32-bit */ + if (pt_iov.iov_len == sizeof(struct user_regs_32)) { + *pc = regs.regs32.pc; + *status_reg = regs.regs32.cpsr; return pt_iov.iov_len; } - - /* - * 64-bit - */ - if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) { - struct user_regs_struct_64* r64 = (struct user_regs_struct_64*)®s; - *pc = r64->pc; - *status_reg = r64->pstate; + /* 64-bit */ + if (pt_iov.iov_len == sizeof(struct user_regs_64)) { + *pc = regs.regs64.pc; + *status_reg = regs.regs64.pstate; return pt_iov.iov_len; } + LOG_W("Unknown registers structure size: '%zd'", pt_iov.iov_len); return 0; #endif /* defined(__arm__) || defined(__aarch64__) */ #if defined(__powerpc64__) || defined(__powerpc__) - /* - * 32-bit - */ - if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) { - struct user_regs_struct_32* r32 = (struct user_regs_struct_32*)®s; - *pc = r32->nip; + /* 32-bit */ + if (pt_iov.iov_len == sizeof(struct user_regs_32)) { + *pc = regs.regs32.nip; return pt_iov.iov_len; } - - /* - * 64-bit - */ - if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) { - struct user_regs_struct_64* r64 = (struct user_regs_struct_64*)®s; - *pc = r64->nip; + /* 64-bit */ + if (pt_iov.iov_len == sizeof(struct user_regs_64)) { + *pc = regs.regs64.nip; return pt_iov.iov_len; } @@ -427,10 +501,33 @@ static size_t arch_getPC(pid_t pid, uint64_t* pc, uint64_t* status_reg HF_ATTR_U #endif /* defined(__powerpc64__) || defined(__powerpc__) */ #if defined(__mips__) || defined(__mips64__) - *pc = regs.cp0_epc; - return pt_iov.iov_len; + if (pt_iov.iov_len == sizeof(struct user_regs_64)) { + *pc = regs.regs64.cp0_epc; + return pt_iov.iov_len; + } + if (pt_iov.iov_len == sizeof(struct user_regs_32)) { + *pc = regs.regs32.cp0_epc; + return pt_iov.iov_len; + } + + LOG_W("Unknown registers structure size: '%zd'", pt_iov.iov_len); + return 0; #endif /* defined(__mips__) || defined(__mips64__) */ +#if defined(__riscv) + if (pt_iov.iov_len == sizeof(struct user_regs_64)) { + *pc = regs.regs64.epc; + return pt_iov.iov_len; + } + if (pt_iov.iov_len == sizeof(struct user_regs_32)) { + *pc = regs.regs32.epc; + return pt_iov.iov_len; + } + + LOG_W("Unknown registers structure size: '%zd'", pt_iov.iov_len); + return 0; +#endif /* defined(__riscv) */ + LOG_D("Unknown/unsupported CPU architecture"); return 0; } @@ -458,7 +555,7 @@ static void arch_getInstrStr(pid_t pid, uint64_t pc, uint64_t status_reg HF_ATTR cs_arch arch; cs_mode mode; #if defined(__arm__) || defined(__aarch64__) - arch = (pcRegSz == sizeof(struct user_regs_struct_64)) ? CS_ARCH_ARM64 : CS_ARCH_ARM; + arch = (pcRegSz == sizeof(struct user_regs_64)) ? CS_ARCH_ARM64 : CS_ARCH_ARM; if (arch == CS_ARCH_ARM) { mode = (status_reg & 0x20) ? CS_MODE_THUMB : CS_MODE_ARM; } else { @@ -466,7 +563,7 @@ static void arch_getInstrStr(pid_t pid, uint64_t pc, uint64_t status_reg HF_ATTR } #elif defined(__i386__) || defined(__x86_64__) arch = CS_ARCH_X86; - mode = (pcRegSz == sizeof(struct user_regs_struct_64)) ? CS_MODE_64 : CS_MODE_32; + mode = (pcRegSz == sizeof(struct user_regs_64)) ? CS_MODE_64 : CS_MODE_32; #else LOG_E("Unknown/Unsupported Android CPU architecture"); #endif diff --git a/lib/bolero-honggfuzz/honggfuzz/mac/arch.c b/lib/bolero-honggfuzz/honggfuzz/mac/arch.c index 6103b803..533cefde 100644 --- a/lib/bolero-honggfuzz/honggfuzz/mac/arch.c +++ b/lib/bolero-honggfuzz/honggfuzz/mac/arch.c @@ -400,6 +400,9 @@ void arch_reapChild(run_t* run) { } } +void arch_reapKill(void) { +} + void* wait_for_exception() { while (1) { mach_msg_server_once(mach_exc_server, 4096, g_exception_port, MACH_MSG_OPTION_NONE); @@ -696,13 +699,21 @@ kern_return_t catch_mach_exception_raise_state_identity( * Get program counter. * Cast to void* in order to silence the alignment warnings */ +#if defined(__x86_64__) x86_thread_state_t* platform_in_state = ((x86_thread_state_t*)(void*)in_state); +#elif defined(__aarch64__) + arm_thread_state_t* platform_in_state = ((arm_thread_state_t*)(void*)in_state); +#endif /* defined(__x86_64__) */ +#if defined(__x86_64__) if (x86_THREAD_STATE32 == platform_in_state->tsh.flavor) { run->pc = platform_in_state->uts.ts32.__eip; } else { run->pc = platform_in_state->uts.ts64.__rip; } +#elif defined(__aarch64__) + run->pc = platform_in_state->__pc; +#endif /* defined(__x86_64__) */ /* * Get the exception type diff --git a/lib/bolero-honggfuzz/honggfuzz/mangle.c b/lib/bolero-honggfuzz/honggfuzz/mangle.c index 637d428d..50ab6c99 100644 --- a/lib/bolero-honggfuzz/honggfuzz/mangle.c +++ b/lib/bolero-honggfuzz/honggfuzz/mangle.c @@ -569,7 +569,7 @@ static inline void mangle_AddSubWithRange( } case 2: { int16_t val; - memcpy(&val, &run->dynfile->data[off], sizeof(val)); + util_memcpyInline(&val, &run->dynfile->data[off], sizeof(val)); if (util_rnd64() & 0x1) { val += delta; } else { @@ -583,7 +583,7 @@ static inline void mangle_AddSubWithRange( } case 4: { int32_t val; - memcpy(&val, &run->dynfile->data[off], sizeof(val)); + util_memcpyInline(&val, &run->dynfile->data[off], sizeof(val)); if (util_rnd64() & 0x1) { val += delta; } else { @@ -597,7 +597,7 @@ static inline void mangle_AddSubWithRange( } case 8: { int64_t val; - memcpy(&val, &run->dynfile->data[off], sizeof(val)); + util_memcpyInline(&val, &run->dynfile->data[off], sizeof(val)); if (util_rnd64() & 0x1) { val += delta; } else { @@ -705,6 +705,7 @@ static void mangle_Shrink(run_t* run, bool printable HF_ATTR_UNUSED) { mangle_Move(run, off_end, off_start, len_to_move); input_setSize(run, run->dynfile->size - len); } + static void mangle_ASCIINum(run_t* run, bool printable) { size_t len = util_rndGet(2, 8); @@ -842,7 +843,7 @@ static void mangle_Resize(run_t* run, bool printable) { } void mangle_mangleContent(run_t* run, int speed_factor) { - static void (*const mangleFuncs[])(run_t * run, bool printable) = { + static void (*const mangleFuncs[])(run_t* run, bool printable) = { mangle_Shrink, mangle_Expand, mangle_Bit, @@ -890,17 +891,17 @@ void mangle_mangleContent(run_t* run, int speed_factor) { } } + /* + * mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback dictionary + * exists. If so, give it a 50% chance of being used. + */ + if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) { + mangle_ConstFeedbackDict(run, /* printable= */ run->global->cfg.only_printable); + } + for (uint64_t x = 0; x < changesCnt; x++) { - if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) { - /* - * mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback dictionary - * exists. If so, give it 50% chance of being used among all mangling functions. - */ - mangle_ConstFeedbackDict(run, /* printable= */ run->global->cfg.only_printable); - } else { - uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1); - mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable); - } + uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1); + mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable); } wmb(); diff --git a/lib/bolero-honggfuzz/honggfuzz/netbsd/arch.c b/lib/bolero-honggfuzz/honggfuzz/netbsd/arch.c index 43b2d081..2c846722 100644 --- a/lib/bolero-honggfuzz/honggfuzz/netbsd/arch.c +++ b/lib/bolero-honggfuzz/honggfuzz/netbsd/arch.c @@ -177,6 +177,9 @@ void arch_reapChild(run_t* run) { } } +void arch_reapKill(void) { +} + bool arch_archInit(honggfuzz_t* hfuzz) { /* Make %'d work */ setlocale(LC_NUMERIC, "en_US.UTF-8"); diff --git a/lib/bolero-honggfuzz/honggfuzz/netbsd/trace.c b/lib/bolero-honggfuzz/honggfuzz/netbsd/trace.c index 76f64648..8073c845 100644 --- a/lib/bolero-honggfuzz/honggfuzz/netbsd/trace.c +++ b/lib/bolero-honggfuzz/honggfuzz/netbsd/trace.c @@ -223,8 +223,8 @@ static void arch_getInstrStr(pid_t pid, lwpid_t lwp, register_t* pc, char* instr arch = CS_ARCH_X86; mode = CS_MODE_32; #elif defined(__x86_64__) - arch = CS_ARCH_X86; - mode = CS_MODE_64; + arch = CS_ARCH_X86; + mode = CS_MODE_64; #else #error Unsupported CPU architecture #endif diff --git a/lib/bolero-honggfuzz/honggfuzz/posix/arch.c b/lib/bolero-honggfuzz/honggfuzz/posix/arch.c index bf950fe1..9e1cc3a0 100644 --- a/lib/bolero-honggfuzz/honggfuzz/posix/arch.c +++ b/lib/bolero-honggfuzz/honggfuzz/posix/arch.c @@ -35,6 +35,9 @@ #if !defined(__sun) #include #endif +#if defined(__FreeBSD__) +#include +#endif #include #include #include @@ -178,10 +181,28 @@ static void arch_analyzeSignal(run_t* run, pid_t pid, int status) { } pid_t arch_fork(run_t* fuzzer HF_ATTR_UNUSED) { +#if defined(__FreeBSD__) + const int flags = RFPROC | RFCFDG; + return rfork(flags); +#else return fork(); +#endif } bool arch_launchChild(run_t* run) { +#if defined(__FreeBSD__) + int enableTrace = PROC_TRACE_CTL_ENABLE; + int disableRandomization = PROC_ASLR_FORCE_DISABLE; + if (procctl(P_PID, 0, PROC_TRACE_CTL, &enableTrace) == -1) { + PLOG_E("procctl(PROC_TRACE_CTL, PROC_TRACE_CTL_ENABLE)"); + return false; + } + + if (run->global->arch_linux.disableRandomization && + procctl(P_PID, 0, PROC_ASLR_CTL, &disableRandomization) == -1) { + PLOG_D("procctl(PROC_ASLR_CTL, PROC_ASLR_FORCE_DISABLE) failed"); + } +#endif /* alarm persists across forks, so disable it here */ alarm(0); execvp(run->args[0], (char* const*)run->args); @@ -263,6 +284,17 @@ void arch_reapChild(run_t* run) { } } +void arch_reapKill(void) { +#if defined(__FreeBSD__) + struct procctl_reaper_kill lst; + lst.rk_flags = 0; + lst.rk_sig = SIGTERM; + if (procctl(P_PID, getpid(), PROC_REAP_KILL, &lst) == -1) { + PLOG_W("procctl(PROC_REAP_KILL)"); + } +#endif +} + bool arch_archInit(honggfuzz_t* hfuzz HF_ATTR_UNUSED) { /* Make %'d work */ setlocale(LC_NUMERIC, "en_US.UTF-8"); @@ -271,5 +303,10 @@ bool arch_archInit(honggfuzz_t* hfuzz HF_ATTR_UNUSED) { } bool arch_archThreadInit(run_t* fuzzer HF_ATTR_UNUSED) { +#if defined(__FreeBSD_) + if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == -1) { + PLOG_W("procctl(PROC_REAP_ACQUIRE)"); + } +#endif return true; } diff --git a/lib/bolero-honggfuzz/honggfuzz/sanitizers.c b/lib/bolero-honggfuzz/honggfuzz/sanitizers.c index 22335190..58efeb8e 100644 --- a/lib/bolero-honggfuzz/honggfuzz/sanitizers.c +++ b/lib/bolero-honggfuzz/honggfuzz/sanitizers.c @@ -102,7 +102,7 @@ static pid_t sanitizers_PidForTid(pid_t pid) { char status_path[PATH_MAX]; snprintf(status_path, sizeof(status_path), "/proc/%d/status", (int)pid); FILE* f = fopen(status_path, "rb"); - if (!f) { + if (UNLIKELY(!f)) { return pid; } defer { diff --git a/lib/bolero-honggfuzz/honggfuzz/third_party/android/patches/libunwind.patch b/lib/bolero-honggfuzz/honggfuzz/third_party/android/patches/libunwind.patch deleted file mode 100644 index eab75dca..00000000 --- a/lib/bolero-honggfuzz/honggfuzz/third_party/android/patches/libunwind.patch +++ /dev/null @@ -1,406 +0,0 @@ -diff --git a/include/dwarf.h b/include/dwarf.h -index 633868b..3fe3a3f 100644 ---- a/include/dwarf.h -+++ b/include/dwarf.h -@@ -311,6 +311,7 @@ typedef struct dwarf_cursor - unw_word_t ret_addr_column; /* column for return-address */ - unw_word_t eh_args[UNW_TDEP_NUM_EH_REGS]; - unsigned int eh_valid_mask; -+ unsigned int frame; - - dwarf_loc_t loc[DWARF_NUM_PRESERVED_REGS]; - -diff --git a/include/libunwind-aarch64.h b/include/libunwind-aarch64.h -index cd01e57..3be8251 100644 ---- a/include/libunwind-aarch64.h -+++ b/include/libunwind-aarch64.h -@@ -168,15 +168,37 @@ typedef struct unw_tdep_save_loc - } - unw_tdep_save_loc_t; - -- - /* On AArch64, we can directly use ucontext_t as the unwind context. */ - typedef ucontext_t unw_tdep_context_t; - - #include "libunwind-common.h" - #include "libunwind-dynamic.h" - --#define unw_tdep_getcontext(uc) (getcontext (uc), 0) --#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) -+/* There is no getcontext in Android. */ -+#define unw_tdep_getcontext(uc) (({ \ -+ unw_tdep_context_t *unw_ctx = (uc); \ -+ register uint64_t *unw_base asm ("x0") = (uint64_t*) unw_ctx->uc_mcontext.regs; \ -+ __asm__ __volatile__ ( \ -+ "stp x0, x1, [%[base], #0]\n" \ -+ "stp x2, x3, [%[base], #16]\n" \ -+ "stp x4, x5, [%[base], #32]\n" \ -+ "stp x6, x7, [%[base], #48]\n" \ -+ "stp x8, x9, [%[base], #64]\n" \ -+ "stp x10, x11, [%[base], #80]\n" \ -+ "stp x12, x13, [%[base], #96]\n" \ -+ "stp x14, x13, [%[base], #112]\n" \ -+ "stp x16, x17, [%[base], #128]\n" \ -+ "stp x18, x19, [%[base], #144]\n" \ -+ "stp x20, x21, [%[base], #160]\n" \ -+ "stp x22, x23, [%[base], #176]\n" \ -+ "stp x24, x25, [%[base], #192]\n" \ -+ "stp x26, x27, [%[base], #208]\n" \ -+ "stp x28, x29, [%[base], #224]\n" \ -+ "str x30, [%[base], #240]\n" \ -+ "mov x1, sp\n" \ -+ "stp x1, x30, [%[base], #248]\n" \ -+ : [base] "+r" (unw_base) : : "x1", "memory"); \ -+ }), 0) - - extern int unw_tdep_is_fpreg (int); - -diff --git a/src/aarch64/Gstep.c b/src/aarch64/Gstep.c -index 0c35f98..2fe00ba 100644 ---- a/src/aarch64/Gstep.c -+++ b/src/aarch64/Gstep.c -@@ -121,6 +121,30 @@ unw_step (unw_cursor_t *cursor) - ret = dwarf_step (&c->dwarf); - Debug(1, "dwarf_step()=%d\n", ret); - -+ if (ret < 0 && c->dwarf.frame == 0) -+ { -+ /* If this is the first frame, the code may be executing garbage -+ * in the middle of nowhere. In this case, try using the lr as -+ * the pc. -+ */ -+ unw_word_t lr; -+ if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_AARCH64_X30], &lr) >= 0) -+ { -+ if (lr != c->dwarf.ip) -+ { -+ ret = 1; -+ c->dwarf.ip = lr; -+ } -+ } -+ } -+ -+ if (ret >= 0) -+ { -+ if (c->dwarf.ip >= 4) -+ c->dwarf.ip -= 4; -+ c->dwarf.frame++; -+ } -+ - if (unlikely (ret == -UNW_ESTOPUNWIND)) - return ret; - -diff --git a/src/aarch64/init.h b/src/aarch64/init.h -index 0cedc1a..c418932 100644 ---- a/src/aarch64/init.h -+++ b/src/aarch64/init.h -@@ -122,6 +122,7 @@ common_init (struct cursor *c, unsigned use_prev_instr) - c->dwarf.pi_is_dynamic = 0; - c->dwarf.hint = 0; - c->dwarf.prev_rs = 0; -+ c->dwarf.frame = 0; - - return 0; - } -diff --git a/src/arm/Gstep.c b/src/arm/Gstep.c -index 79f2dd2..28aa4c0 100644 ---- a/src/arm/Gstep.c -+++ b/src/arm/Gstep.c -@@ -73,6 +73,39 @@ arm_exidx_step (struct cursor *c) - return (c->dwarf.ip == 0) ? 0 : 1; - } - -+/* When taking a step back up the stack, the pc will point to the next -+ * instruction to execute, not the currently executing instruction. This -+ * function adjusts the pc to the currently executing instruction. -+ */ -+static void adjust_ip(struct cursor *c) -+{ -+ unw_word_t ip, value; -+ ip = c->dwarf.ip; -+ -+ if (ip) -+ { -+ int adjust = 4; -+ if (ip & 1) -+ { -+ /* Thumb instructions, the currently executing instruction could be -+ * 2 or 4 bytes, so adjust appropriately. -+ */ -+ unw_addr_space_t as; -+ unw_accessors_t *a; -+ void *arg; -+ -+ as = c->dwarf.as; -+ a = unw_get_accessors (as); -+ arg = c->dwarf.as_arg; -+ -+ if (ip < 5 || (*a->access_mem) (as, ip-5, &value, 0, arg) < 0 || -+ (value & 0xe000f000) != 0xe000f000) -+ adjust = 2; -+ } -+ c->dwarf.ip -= adjust; -+ } -+} -+ - PROTECTED int - unw_handle_signal_frame (unw_cursor_t *cursor) - { -@@ -268,5 +301,28 @@ unw_step (unw_cursor_t *cursor) - } - } - } -+ -+ if (ret < 0 && c->dwarf.frame == 0) -+ { -+ /* If this is the first frame, the code may be executing garbage -+ * in the middle of nowhere. In this case, try using the lr as -+ * the pc. -+ */ -+ unw_word_t lr; -+ if (dwarf_get(&c->dwarf, c->dwarf.loc[UNW_ARM_R14], &lr) >= 0) -+ { -+ if (lr != c->dwarf.ip) -+ { -+ ret = 1; -+ c->dwarf.ip = lr; -+ } -+ } -+ } -+ -+ if (ret >= 0) -+ { -+ c->dwarf.frame++; -+ } -+ - return ret == -UNW_ENOINFO ? 0 : 1; - } -diff --git a/src/arm/init.h b/src/arm/init.h -index 6379d8e..8222c02 100644 ---- a/src/arm/init.h -+++ b/src/arm/init.h -@@ -73,6 +73,7 @@ common_init (struct cursor *c, unsigned use_prev_instr) - c->dwarf.pi_is_dynamic = 0; - c->dwarf.hint = 0; - c->dwarf.prev_rs = 0; -+ c->dwarf.frame = 0; - - return 0; - } -diff --git a/src/ptrace/_UPT_access_fpreg.c b/src/ptrace/_UPT_access_fpreg.c -index e90ec47d..ae61d093 100644 ---- a/src/ptrace/_UPT_access_fpreg.c -+++ b/src/ptrace/_UPT_access_fpreg.c -@@ -46,8 +46,8 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, - #ifdef HAVE_TTRACE - # warning No support for ttrace() yet. - #else -- ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg] + i * sizeof(wp[i]), -- wp[i]); -+ ptrace (PTRACE_POKEUSER, pid, (void*) (_UPT_reg_offset[reg] + i * sizeof(wp[i])), -+ (void*) wp[i]); - #endif - if (errno) - return -UNW_EBADREG; -@@ -59,14 +59,14 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, - # warning No support for ttrace() yet. - #else - wp[i] = ptrace (PTRACE_PEEKUSER, pid, -- _UPT_reg_offset[reg] + i * sizeof(wp[i]), 0); -+ (void*) (_UPT_reg_offset[reg] + i * sizeof(wp[i])), 0); - #endif - if (errno) - return -UNW_EBADREG; - } - return 0; - } --#elif HAVE_DECL_PT_GETFPREGS -+#elif HAVE_DECL_PT_GETFPREGS && !defined(__aarch64__) - int - _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, - int write, void *arg) -@@ -100,6 +100,14 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, - #endif - return 0; - } -+#elif defined(__aarch64__) -+int -+_UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val, -+ int write, void *arg) -+{ -+# pragma message("_UPT_access_fpreg is not implemented and not currently used.") -+ return -UNW_EBADREG; -+} - #else - #error Fix me - #endif -diff --git a/src/ptrace/_UPT_access_reg.c b/src/ptrace/_UPT_access_reg.c -index ae71608..8d40bcc 100644 ---- a/src/ptrace/_UPT_access_reg.c -+++ b/src/ptrace/_UPT_access_reg.c -@@ -32,6 +32,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - # include - # endif - # include "tdep-ia64/rse.h" -+#elif defined(__aarch64__) -+# include - #endif - - #if HAVE_DECL_PTRACE_POKEUSER || HAVE_TTRACE -@@ -239,13 +241,13 @@ _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, - #else - errno = 0; - if (write) -- ptrace (PTRACE_POKEUSER, pid, _UPT_reg_offset[reg], *val); -+ ptrace (PTRACE_POKEUSER, pid, (void*) (uintptr_t) _UPT_reg_offset[reg], (void*) *val); - else { - #if UNW_DEBUG - Debug(16, "ptrace PEEKUSER pid: %lu , reg: %lu , offs: %lu\n", (unsigned long)pid, (unsigned long)reg, - (unsigned long)_UPT_reg_offset[reg]); - #endif -- *val = ptrace (PTRACE_PEEKUSER, pid, _UPT_reg_offset[reg], 0); -+ *val = ptrace (PTRACE_PEEKUSER, pid, (void*) (uintptr_t) _UPT_reg_offset[reg], 0); - } - if (errno) { - #if UNW_DEBUG -@@ -304,6 +306,60 @@ _UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, - Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); - return -UNW_EBADREG; - } -+#elif HAVE_DECL_PT_GETREGSET -+int -+_UPT_access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, -+ int write, void *arg) -+{ -+ struct UPT_info *ui = arg; -+ pid_t pid = ui->pid; -+#if defined(__aarch64__) -+ struct user_pt_regs regs; -+ struct iovec io; -+ io.iov_base = ®s; -+ io.iov_len = sizeof(regs); -+ -+#if UNW_DEBUG -+ Debug(16, "using getregset: reg: %s [%u], val: %lx, write: %u\n", unw_regname(reg), (unsigned) reg, (long) val, write); -+ -+ if (write) -+ Debug (16, "%s [%u] <- %lx\n", unw_regname (reg), (unsigned) reg, (long) *val); -+#endif -+ if (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, (void*)&io) == -1) -+ goto badreg; -+ if (write) -+ { -+ if (reg == UNW_AARCH64_SP) -+ regs.sp = *val; -+ else if (reg == UNW_AARCH64_PC) -+ regs.pc = *val; -+ else if (reg < UNW_AARCH64_SP) -+ regs.regs[reg] = *val; -+ else -+ goto badreg; -+ if (ptrace(PTRACE_SETREGSET, pid, (void*)NT_PRSTATUS, (void*)&io) == -1) -+ goto badreg; -+ } -+ else -+ { -+ if (reg == UNW_AARCH64_SP) -+ *val = regs.sp; -+ else if (reg == UNW_AARCH64_PC) -+ *val = regs.pc; -+ else if (reg < UNW_AARCH64_SP) -+ *val = regs.regs[reg]; -+ else -+ goto badreg; -+ } -+#else -+#error Unsupported architecture for getregset -+#endif -+ return 0; -+ -+ badreg: -+ Debug (1, "bad register %s [%u] (error: %s)\n", unw_regname(reg), reg, strerror (errno)); -+ return -UNW_EBADREG; -+} - #else - #error Port me - #endif -diff --git a/src/x86/Gos-linux.c b/src/x86/Gos-linux.c -index 17aebc2..bafca96 100644 ---- a/src/x86/Gos-linux.c -+++ b/src/x86/Gos-linux.c -@@ -283,7 +283,9 @@ HIDDEN int - x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) - { - struct cursor *c = (struct cursor *) cursor; -+#if !defined(__ANDROID__) - ucontext_t *uc = c->uc; -+#endif - - /* Ensure c->pi is up-to-date. On x86, it's relatively common to be - missing DWARF unwind info. We don't want to fail in that case, -@@ -296,12 +298,16 @@ x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg) - struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr; - - Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc); -+#if !defined(__ANDROID__) - sigreturn (sc); -+#endif - } - else - { - Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip); -+#if !defined(__ANDROID__) - setcontext (uc); -+#endif - } - return -UNW_EINVAL; - } -diff --git a/src/x86/Gstep.c b/src/x86/Gstep.c -index 10e2cbc..49a830d 100644 ---- a/src/x86/Gstep.c -+++ b/src/x86/Gstep.c -@@ -110,6 +110,20 @@ unw_step (unw_cursor_t *cursor) - else - c->dwarf.ip = 0; - } -+ -+ if (ret >= 0) -+ { -+ if (c->dwarf.ip) -+ { -+ /* Adjust the pc to the instruction before. */ -+ c->dwarf.ip--; -+ } -+ c->dwarf.frame++; -+ } -+ -+ if (unlikely (ret <= 0)) -+ return 0; -+ - ret = (c->dwarf.ip == 0) ? 0 : 1; - Debug (2, "returning %d\n", ret); - return ret; -diff --git a/src/x86/init.h b/src/x86/init.h -index 027aedc..4218aa3 100644 ---- a/src/x86/init.h -+++ b/src/x86/init.h -@@ -65,6 +65,7 @@ common_init (struct cursor *c, unsigned use_prev_instr) - c->dwarf.pi_is_dynamic = 0; - c->dwarf.hint = 0; - c->dwarf.prev_rs = 0; -+ c->dwarf.frame = 0; - - return 0; - } -diff --git a/src/x86_64/init.h b/src/x86_64/init.h -index 442b2bf..737b9f7 100644 ---- a/src/x86_64/init.h -+++ b/src/x86_64/init.h -@@ -84,6 +84,7 @@ common_init (struct cursor *c, unsigned use_prev_instr) - c->dwarf.pi_is_dynamic = 0; - c->dwarf.hint = 0; - c->dwarf.prev_rs = 0; -+ c->dwarf.frame = 0; - - return 0; - } diff --git a/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-capstone.sh b/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-capstone.sh index 2c86c0a4..fda18764 100755 --- a/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-capstone.sh +++ b/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-capstone.sh @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -#set -x # debug +set -xeu abort() { cd - &>/dev/null @@ -34,38 +34,20 @@ fi readonly CAPSTONE_DIR="$1" if [ ! -d "$CAPSTONE_DIR/.git" ]; then - git submodule update --init third_party/android/capstone || { - echo "[-] git submodules init failed" - exit 1 - } -fi - -# register client hooks -hooksDir="$(git -C "$CAPSTONE_DIR" rev-parse --git-dir)/hooks" -mkdir -p "$hooksDir" - -if [ ! -f "$hooksDir/post-checkout" ]; then - cat > "$hooksDir/post-checkout" <<'endmsg' -#!/usr/bin/env bash - -endmsg - chmod +x "$hooksDir/post-checkout" + git submodule update --init third_party/android/capstone fi # Change workspace cd "$CAPSTONE_DIR" &>/dev/null -if [ -z "$NDK" ]; then - # Search in $PATH - if [[ $(which ndk-build) != "" ]]; then - NDK=$(dirname $(which ndk-build)) - else - echo "[-] Could not detect Android NDK dir" - abort 1 - fi +if [[ $(which ndk-build) != "" ]]; then + NDK=$(dirname $(which ndk-build)) +else + echo "[-] Could not detect Android NDK dir" + abort 1 fi -ARCH="$2" +readonly ARCH="$2" case "$ARCH" in arm) @@ -86,21 +68,8 @@ case "$ARCH" in ;; esac -# Capstone ARM/ARM64 cross-compile automation is broken, -# we need to prepare the Android NDK toolchains manually -if [ -z "$NDK" ]; then - # Search in $PATH - if [[ $(which ndk-build) != "" ]]; then - $NDK=$(dirname $(which ndk-build)) - else - echo "[-] Could not detect Android NDK dir" - abort 1 - fi -fi +NDK=$(dirname $(which ndk-build)) -if [ -z "$ANDROID_API" ]; then - ANDROID_API="android-26" -fi if ! echo "$ANDROID_API" | grep -qoE 'android-[0-9]{1,2}'; then echo "[-] Invalid ANDROID_API '$ANDROID_API'" abort 1 @@ -120,11 +89,7 @@ make clean NDK=$NDK CAPSTONE_BUILD_CORE_ONLY=yes CAPSTONE_ARCHS=$CS_ARCH \ CAPSTONE_SHARED=no CAPSTONE_STATIC=yes \ eval $CS_BUILD_BIN -if [ $? -ne 0 ]; then - echo "[-] Compilation failed" - abort 1 -else - echo "[*] '$ARCH' libcapstone available at '$CAPSTONE_DIR/$ARCH'" -fi + +echo "[*] '$ARCH' libcapstone available at '$CAPSTONE_DIR/$ARCH'" abort 0 diff --git a/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-libBlocksRuntime.sh b/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-libBlocksRuntime.sh index c8b42d78..f92451aa 100755 --- a/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-libBlocksRuntime.sh +++ b/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-libBlocksRuntime.sh @@ -15,19 +15,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -if [ -z "$NDK" ]; then - # Search in $PATH - if [[ $(which ndk-build) != "" ]]; then - NDK=$(dirname $(which ndk-build)) - else - echo "[-] Could not detect Android NDK dir" - exit 1 - fi -fi +set -xeu -if [ -z "$ANDROID_API" ]; then - ANDROID_API="android-26" +# Search in $PATH +if [[ $(which ndk-build) != "" ]]; then + NDK=$(dirname $(which ndk-build)) +else + echo "[-] Could not detect Android NDK dir" + abort 1 fi + if ! echo "$ANDROID_API" | grep -qoE 'android-[0-9]{1,2}'; then echo "[-] Invalid ANDROID_API '$ANDROID_API'" exit 1 @@ -53,8 +50,6 @@ case "$2" in ;; esac -ARCH="$2" - case "$ARCH" in arm) BRT_ARCH="armeabi-v7a" @@ -83,15 +78,11 @@ $NDK/ndk-build NDK_PROJECT_PATH=$BRT_DIR APP_BUILD_SCRIPT=$BRT_DIR/Android.mk \ $NDK/ndk-build NDK_PROJECT_PATH=$BRT_DIR APP_BUILD_SCRIPT=$BRT_DIR/Android.mk \ APP_PLATFORM=$ANDROID_API APP_ABI=$BRT_ARCH \ NDK_TOOLCHAIN=$BRT_TOOLCHAIN -if [ $? -ne 0 ]; then - echo "[-] Compilation failed" - exit 1 -else - echo "[*] '$ARCH' libBlocksRuntime available at '$BRT_DIR/$ARCH'" -fi + +echo "[*] '$ARCH' libBlocksRuntime available at '$BRT_DIR/$ARCH'" # Change workdir to simplify args -cd $BRT_DIR +cd "$BRT_DIR" # Revert workdir to caller cd - &>/dev/null diff --git a/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-libunwind.sh b/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-libunwind.sh index d8fb963a..83a05127 100755 --- a/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-libunwind.sh +++ b/lib/bolero-honggfuzz/honggfuzz/third_party/android/scripts/compile-libunwind.sh @@ -15,9 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -x # debug - -readonly JOBS=$(getconf _NPROCESSORS_ONLN) +set -xeu abort() { cd - &>/dev/null @@ -36,47 +34,26 @@ fi readonly LIBUNWIND_DIR="$1" if [ ! -d "$LIBUNWIND_DIR/.git" ]; then - git submodule update --init third_party/android/libunwind || { - echo "[-] git submodules init failed" - exit 1 - } -fi - -# register client hooks -hooksDir="$(git -C "$LIBUNWIND_DIR" rev-parse --git-dir)/hooks" -mkdir -p "$hooksDir" - -if [ ! -f "$hooksDir/post-checkout" ]; then - cat > "$hooksDir/post-checkout" <<'endmsg' -#!/usr/bin/env bash - -endmsg - chmod +x "$hooksDir/post-checkout" + git submodule update --init third_party/android/libunwind fi # Change workspace cd "$LIBUNWIND_DIR" &>/dev/null -if [ -z "$NDK" ]; then - # Search in $PATH - if [[ $(which ndk-build) != "" ]]; then - NDK=$(dirname $(which ndk-build)) - else - echo "[-] Could not detect Android NDK dir" - abort 1 - fi +if [[ $(which ndk-build) != "" ]]; then + NDK=$(dirname $(which ndk-build)) +else + echo "[-] Could not detect Android NDK dir" + abort 1 fi -if [ -z "$ANDROID_API" ]; then - ANDROID_API="android-26" -fi if ! echo "$ANDROID_API" | grep -qoE 'android-[0-9]{1,2}'; then echo "[-] Invalid ANDROID_API '$ANDROID_API'" abort 1 fi ANDROID_API_V=$(echo "$ANDROID_API" | grep -oE '[0-9]{1,2}$') -LC_LDFLAGS="-static -Wl,-z,muldefs" +LC_LDFLAGS="-static" ARCH="$2" @@ -96,29 +73,10 @@ case "$ARCH" in ;; esac -# Apply patches required for Android -# TODO: Automate global patching when all archs have been tested - -# Ptrace patches due to Android incompatibilities -git reset --hard - -git apply --check ../patches/libunwind.patch -if [ $? -eq 0 ]; then - git apply ../patches/libunwind.patch - if [ $? -ne 0 ]; then - echo "[-] Failed to apply libunwind patches" - abort 1 - fi -else - echo "[-] Cannot apply libunwind patches" - abort 1 -fi - # Support both Linux & Darwin HOST_OS=$(uname -s | tr '[:upper:]' '[:lower:]') HOST_ARCH=$(uname -m) - export CC="$NDK"/toolchains/llvm/prebuilt/"$HOST_OS"-x86_64/bin/"$ANDROID_NDK_COMPILER_PREFIX""$ANDROID_API_V"-clang export CXX="$NDK"/toolchains/llvm/prebuilt/"$HOST_OS"-x86_64/bin/"$ANDROID_NDK_COMPILER_PREFIX""$ANDROID_API_V"-clang++ @@ -131,37 +89,13 @@ elif [ ! -x "$CXX" ]; then fi if [ ! -f configure ]; then - NOCONFIGURE=true ./autogen.sh - if [ $? -ne 0 ]; then - echo "[-] autogen failed" - abort 1 - fi - # Patch configure - sed -i -e 's/-lgcc_s//g' configure - sed -i -e 's/-lgcc//g' configure + autoreconf -i else make clean fi -./configure --host=$TOOLCHAIN --disable-coredump -if [ $? -ne 0 ]; then - echo "[-] configure failed" - abort 1 -fi - -# Fix stuff that configure failed to detect -# TODO: Investigate for more elegant patches -if [ "$ARCH" == "arm64" ]; then - sed -i -e 's/#define HAVE_DECL_PTRACE_POKEUSER 1/#define HAVE_DECL_PTRACE_POKEUSER 0/g' include/config.h - echo "#define HAVE_DECL_PT_GETREGSET 1" >> include/config.h -fi - -make -j"$JOBS" CFLAGS="$LC_CFLAGS" LDFLAGS="$LC_LDFLAGS" -if [ $? -ne 0 ]; then - echo "[-] Compilation failed" - cd - &>/dev/null - abort 1 -fi +./configure "--host=$TOOLCHAIN" --disable-coredump --enable-static --disable-shared --disable-tests --enable-ptrace +make -j LDFLAGS="$LC_LDFLAGS" # Naming conventions for arm64 if [[ "$ARCH" == "arm64" ]]; then diff --git a/lib/bolero-honggfuzz/update.sh b/lib/bolero-honggfuzz/update.sh index 646659ba..41286590 100755 --- a/lib/bolero-honggfuzz/update.sh +++ b/lib/bolero-honggfuzz/update.sh @@ -2,7 +2,7 @@ set -e -version=${1:-2.5} +version=${1:-2.6} project_dir="$(pwd)" tmp_dir="$(mktemp -d)" honggfuzz_dir="$project_dir/honggfuzz/" diff --git a/tests/src/cargo_bolero.rs b/tests/src/cargo_bolero.rs index e42652c4..1a50711c 100644 --- a/tests/src/cargo_bolero.rs +++ b/tests/src/cargo_bolero.rs @@ -29,14 +29,16 @@ impl Test { vec![] }; - cmd!(sh, "cargo {toolchain...} test").run()?; - cmd!(sh, "cargo {toolchain...} build").run()?; + let features = &vec!["--features", "honggfuzz"]; + + cmd!(sh, "cargo {toolchain...} test {features...}").run()?; + cmd!(sh, "cargo {toolchain...} build {features...}").run()?; // Validate failing tests don’t prevent fuzzers from being found sh.change_dir("cargo-bolero/test_crates/failing_tests"); let listed_fuzzers = cmd!( sh, - "cargo {toolchain...} run --manifest-path ../../Cargo.toml list" + "cargo {toolchain...} run {features...} --manifest-path ../../Cargo.toml list" ) .read()?; sh.change_dir("../../.."); @@ -47,7 +49,7 @@ impl Test { // This runs it in $repo/bin, which is fine as cargo-bolero does have fuzz-tests cmd!( sh, - "cargo {toolchain...} run build-clusterfuzz --rustc-bootstrap" + "cargo {toolchain...} run {features...} build-clusterfuzz --rustc-bootstrap" ) .run()?;