Merge pull request #1755 from AFLplusplus/dev

push to stable
This commit is contained in:
van Hauser 2023-06-05 14:12:56 +03:00 committed by GitHub
commit f9b72b6f2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 487 additions and 476 deletions

View File

@ -49,7 +49,7 @@ LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^[
LLVM_TOO_NEW = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[5-9]' && echo 1 || echo 0 )
LLVM_NEW_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[0-9]' && echo 1 || echo 0 )
LLVM_NEWER_API = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[6-9]' && echo 1 || echo 0 )
LLVM_10_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]|^10\.[1-9]|^10\.0.[1-9]' && echo 1 || echo 0 )
LLVM_13_OK = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[3-9]' && echo 1 || echo 0 )
LLVM_HAVE_LTO = $(shell $(LLVM_CONFIG) --version 2>/dev/null | grep -E -q '^1[1-9]' && echo 1 || echo 0 )
LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)
LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null)
@ -422,7 +422,7 @@ endif
$(CXX) $(CLANG_CPPFL) -Wdeprecated -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
./SanitizerCoveragePCGUARD.so: instrumentation/SanitizerCoveragePCGUARD.so.cc instrumentation/afl-llvm-common.o | test_deps
ifeq "$(LLVM_10_OK)" "1"
ifeq "$(LLVM_13_OK)" "1"
-$(CXX) $(CLANG_CPPFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) -Wno-deprecated-copy-dtor -Wdeprecated instrumentation/afl-llvm-common.o
endif

View File

@ -2,9 +2,7 @@
## Should
- redo PCGUARD + LTO for llvm 15+
- test cmplog for less than 16bit
- splicing selection weighted?
- support persistent and deferred fork server in afl-showmap?
- better autodetection of shifting runtime timeout values
- Update afl->pending_not_fuzzed for MOpt

View File

@ -206,7 +206,7 @@ fi
# Check for obvious errors.
if [ ! "$T_ARG" = "" -a ! "$F_ARG" = "" -a ! "$NYX_MODE" == 1 ]; then
if [ ! "$T_ARG" = "" -a -n "$F_ARG" -a ! "$NYX_MODE" == 1 ]; then
echo "[-] Error: -T and -f can not be used together." 1>&2
exit 1
fi
@ -323,7 +323,7 @@ if [ ! "$T_ARG" = "" ]; then
fi
fi
else
if [ "$F_ARG" = ""]; then
if [ -z "$F_ARG" ]; then
echo "[*] Are you aware of the '-T all' parallelize option that massively improves the speed?"
fi
fi

View File

@ -15,13 +15,16 @@
- new env `AFL_LLVM_LTO_SKIPINIT` to support the AFL++ based WASM
(https://github.com/fgsect/WAFL) project
- error and print help if afl-clan-lto is used with lto=thin
- rewrote our PCGUARD pass to be compatible with LLVM 15+ shenanigans,
requires LLVM 13+ now instead of 10.0.1+
- fallback to native LLVM PCGUARD if our PCGUARD is unavailable
- afl-showmap:
- added custom mutator post_process and send support
- add `-I filelist` option, an alternative to `-i in_dir`
- afl-cmin + afl-cmin.bash:
- `-T threads` parallel task support, can be a huge speedup!
- qemu_mode:
- Persistent mode +QASAN support for ppc32 tragets by @worksbutnottested
- Persistent mode + QASAN support for ppc32 targets by @worksbutnottested
- a new grammar custom mutator atnwalk was submitted by @voidptr127 !
- two new custom mutators are now available:
- TritonDSE in custom_mutators/aflpp_tritondse

View File

@ -14,8 +14,6 @@ void entry_init(void);
void entry_start(void);
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output);
void entry_on_fork(void);
#endif

View File

@ -78,6 +78,7 @@ void entry_init(void) {
void entry_start(void) {
FVERBOSE("AFL_ENTRYPOINT reached");
if (persistent_start == 0) {
ranges_exclude();
@ -85,32 +86,7 @@ void entry_start(void) {
}
if (entry_point == 0) { entry_launch(); }
}
static void entry_callout(GumCpuContext *cpu_context, gpointer user_data) {
UNUSED_PARAMETER(cpu_context);
UNUSED_PARAMETER(user_data);
entry_compiled = TRUE;
entry_launch();
}
void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output) {
UNUSED_PARAMETER(output);
FVERBOSE("AFL_ENTRYPOINT reached");
if (persistent_start == 0) {
ranges_exclude();
stalker_trust();
}
gum_stalker_iterator_put_callout(iterator, entry_callout, NULL, NULL);
}

View File

@ -169,7 +169,6 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
if (unlikely(begin)) { instrument_debug_start(instr->address, output); }
if (instr->address == entry_point) { entry_prologue(iterator, output); }
if (instr->address == persistent_start) { persistent_prologue(output); }
if (instr->address == persistent_ret) { persistent_epilogue(output); }

View File

@ -76,6 +76,45 @@ typedef struct {
} afl_log_code_asm_t;
typedef struct {
uint32_t b_imm8; /* br #XX (end) */
uint32_t restoration_prolog; /* ldp x16, x17, [sp], #0x90 */
uint32_t stp_x0_x1; /* stp x0, x1, [sp, #-0xa0] */
uint32_t ldr_x0_p_prev_loc_1; /* ldr x0, #0xXXXX */
uint32_t ldr_x1_ptr_x0; /* ldr x1, [x0] */
uint32_t ldr_x0_p_area_offset; /* ldr x0, #0xXXXX */
uint32_t eor_x0_x1_x0; /* eor x0, x1, x0 */
uint32_t ldr_x1_p_area_ptr; /* ldr x1, #0xXXXX */
uint32_t add_x0_x1_x0; /* add x0, x1, x0 */
uint32_t ldrb_w1_x0; /* ldrb w1, [x0] */
uint32_t add_w1_w1_1; /* add w1, w1, #1 */
uint32_t add_w1_w1_w1_lsr_8; /* add x1, x1, x1, lsr #8 */
uint32_t strb_w1_ptr_x0; /* strb w1, [x0] */
uint32_t ldr_x0_p_prev_loc_2; /* ldr x0, #0xXXXX */
uint32_t ldr_x1_p_area_offset_ror; /* ldr x1, #0xXXXX */
uint32_t str_x1_ptr_x0; /* str x1, [x0] */
uint32_t ldp_x0_x1; /* ldp x0, x1, [sp, #-0xa0] */
uint32_t b_end; /* skip the data */
uint64_t area_ptr;
uint64_t prev_loc_ptr;
uint64_t area_offset;
uint64_t area_offset_ror;
uint8_t end[0];
} afl_log_code_asm_long_t;
#pragma pack(pop)
typedef union {
@ -85,6 +124,13 @@ typedef union {
} afl_log_code;
typedef union {
afl_log_code_asm_long_t code;
uint8_t bytes[0];
} afl_log_code_long;
static const afl_log_code_asm_t template =
{
@ -119,6 +165,46 @@ static const afl_log_code_asm_t template =
;
static const afl_log_code_asm_long_t template_long =
{.b_imm8 = 0x1400001a,
.restoration_prolog = 0xa8c947f0, /* ldp x16, x17, [sp], #0x90 */
.stp_x0_x1 = 0xa93607e0, /* stp x0, x1, [sp, #-0xa0] */
.ldr_x0_p_prev_loc_1 = 0x58000220, /* ldr x0, #0xXXXX */
.ldr_x1_ptr_x0 = 0xf9400001, /* ldr x1, [x0] */
.ldr_x0_p_area_offset = 0x58000220, /* ldr x0, #0xXXXX */
.eor_x0_x1_x0 = 0xca000020, /* eor x0, x1, x0 */
.ldr_x1_p_area_ptr = 0x58000161, /* ldr x1, #0xXXXX */
.add_x0_x1_x0 = 0x8b000020, /* add x0, x1, x0 */
.ldrb_w1_x0 = 0x39400001, /* ldrb w1, [x0] */
.add_w1_w1_1 = 0x11000421, /* add w1, w1, #1 */
.add_w1_w1_w1_lsr_8 = 0x8b412021, /* add x1, x1, x1, lsr #8 */
.strb_w1_ptr_x0 = 0x39000001, /* strb w1, [x0] */
.ldr_x0_p_prev_loc_2 = 0x580000e0, /* ldr x0, #0xXXXX */
.ldr_x1_p_area_offset_ror = 0x58000141, /* ldr x1, #0xXXXX */
.str_x1_ptr_x0 = 0xf9000001, /* str x1, [x0] */
.ldp_x0_x1 = 0xa97607e0, /* ldp x0, x1, [sp, #-0xa0] */
.b_end = 0x14000009, /* skip the data */
.area_ptr = 0x0,
.prev_loc_ptr = 0x0,
.area_offset = 0x0,
.area_offset_ror = 0x0,
.end = {}
}
;
gboolean instrument_is_coverage_optimize_supported(void) {
return true;
@ -266,16 +352,22 @@ static gboolean instrument_coverage_in_range(gssize offset) {
}
static void instrument_patch_ardp(guint32 *patch, GumAddress insn,
static bool instrument_patch_ardp(guint32 *patch, GumAddress insn,
GumAddress target) {
if (!PAGE_ALIGNED(target)) { FATAL("Target not page aligned"); }
if (!PAGE_ALIGNED(target)) {
FWARNF("Target not page aligned");
return false;
}
gssize distance = target - (GUM_ADDRESS(insn) & PAGE_MASK);
if (!instrument_coverage_in_range(distance)) {
FATAL("Patch out of range 0x%016lX->0x%016lX = 0x%016lX", insn, target,
distance);
FVERBOSE("Patch out of range 0x%016lX->0x%016lX = 0x%016lX", insn, target,
distance);
return false;
}
@ -283,6 +375,95 @@ static void instrument_patch_ardp(guint32 *patch, GumAddress insn,
guint32 imm_high = ((distance >> 14) & 0x7FFFF) << 5;
*patch |= imm_low;
*patch |= imm_high;
return true;
}
bool instrument_write_inline(GumArm64Writer *cw, GumAddress code_addr,
guint64 area_offset, gsize area_offset_ror) {
afl_log_code code = {0};
code.code = template;
/*
* Given our map is allocated on a 64KB boundary and our map is a multiple of
* 64KB in size, then it should also end on a 64 KB boundary. It is followed
* by our previous_pc, so this too should be 64KB aligned.
*/
g_assert(PAGE_ALIGNED(instrument_previous_pc_addr));
g_assert(PAGE_ALIGNED(__afl_area_ptr));
if (!instrument_patch_ardp(
&code.code.adrp_x0_prev_loc1,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc1),
GUM_ADDRESS(instrument_previous_pc_addr))) {
return false;
}
code.code.mov_x0_curr_loc |= area_offset << 5;
if (!instrument_patch_ardp(
&code.code.adrp_x1_area_ptr,
code_addr + offsetof(afl_log_code, code.adrp_x1_area_ptr),
GUM_ADDRESS(__afl_area_ptr))) {
return false;
}
if (!instrument_patch_ardp(
&code.code.adrp_x0_prev_loc2,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc2),
GUM_ADDRESS(instrument_previous_pc_addr))) {
return false;
}
code.code.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5);
if (instrument_suppress) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
} else {
size_t offset = offsetof(afl_log_code, code.stp_x0_x1);
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
sizeof(afl_log_code) - offset);
}
return true;
}
bool instrument_write_inline_long(GumArm64Writer *cw, GumAddress code_addr,
guint64 area_offset, gsize area_offset_ror) {
afl_log_code_long code = {0};
code.code = template_long;
code.code.area_ptr = GUM_ADDRESS(__afl_area_ptr);
code.code.prev_loc_ptr = GUM_ADDRESS(instrument_previous_pc_addr);
code.code.area_offset = area_offset;
code.code.area_offset_ror = GUM_ADDRESS(area_offset_ror);
if (instrument_suppress) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code_long));
} else {
size_t offset = offsetof(afl_log_code_long, code.stp_x0_x1);
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
sizeof(afl_log_code_long) - offset);
}
return true;
}
@ -312,6 +493,8 @@ void instrument_coverage_optimize(const cs_insn *instr,
}
// gum_arm64_writer_put_brk_imm(cw, 0x0);
// uint32_t jmp_dot = 0x14000000;
// gum_arm64_writer_put_bytes(cw, (guint8 *)&jmp_dot, sizeof(jmp_dot));
if (instrument_suppress) { instrument_coverage_suppress_init(); }
@ -343,47 +526,19 @@ void instrument_coverage_optimize(const cs_insn *instr,
}
code.code = template;
/*
* Given our map is allocated on a 64KB boundary and our map is a multiple of
* 64KB in size, then it should also end on a 64 KB boundary. It is followed
* by our previous_pc, so this too should be 64KB aligned.
*/
g_assert(PAGE_ALIGNED(instrument_previous_pc_addr));
g_assert(PAGE_ALIGNED(__afl_area_ptr));
instrument_patch_ardp(
&code.code.adrp_x0_prev_loc1,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc1),
GUM_ADDRESS(instrument_previous_pc_addr));
code.code.mov_x0_curr_loc |= area_offset << 5;
instrument_patch_ardp(
&code.code.adrp_x1_area_ptr,
code_addr + offsetof(afl_log_code, code.adrp_x1_area_ptr),
GUM_ADDRESS(__afl_area_ptr));
map_size_pow2 = util_log2(__afl_map_size);
area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
instrument_patch_ardp(
&code.code.adrp_x0_prev_loc2,
code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc2),
GUM_ADDRESS(instrument_previous_pc_addr));
code.code = template;
code.code.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5);
if (!instrument_write_inline(cw, code_addr, area_offset, area_offset_ror)) {
if (instrument_suppress) {
if (!instrument_write_inline_long(cw, code_addr, area_offset,
area_offset_ror)) {
gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
FATAL("Failed to write inline instrumentation");
} else {
size_t offset = offsetof(afl_log_code, code.stp_x0_x1);
gum_arm64_writer_put_bytes(cw, &code.bytes[offset],
sizeof(afl_log_code) - offset);
}
}

View File

@ -197,7 +197,7 @@ static void afl_print_env(void) {
}
__attribute__((visibility("default"))) void afl_frida_start(void) {
void afl_frida_config(void) {
FOKF(cRED "**********************");
FOKF(cRED "* " cYEL "******************" cRED " *");
@ -225,9 +225,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
js_start();
/* Initialize */
output_init();
embedded_init();
entry_init();
instrument_init();
@ -240,12 +238,35 @@ __attribute__((visibility("default"))) void afl_frida_start(void) {
ranges_init();
stats_init();
/* Start */
}
void afl_frida_run(void) {
stalker_start();
entry_start();
}
__attribute__((visibility("default"))) void afl_frida_start(void) {
afl_frida_config();
afl_frida_run();
}
typedef void *(*entry_func_t)(size_t a1, size_t a2, size_t a3, size_t a4,
size_t a5, size_t a6);
static void *on_entry(size_t a1, size_t a2, size_t a3, size_t a4, size_t a5,
size_t a6) {
intercept_unhook(GSIZE_TO_POINTER(entry_point));
afl_frida_run();
entry_func_t entry = (entry_func_t)entry_point;
return entry(a1, a2, a3, a4, a5, a6);
}
static int on_main(int argc, char **argv, char **envp) {
int ret;
@ -254,7 +275,17 @@ static int on_main(int argc, char **argv, char **envp) {
intercept_unhook_self();
afl_frida_start();
afl_frida_config();
if (entry_point == 0) {
afl_frida_run();
} else {
intercept_hook(GSIZE_TO_POINTER(entry_point), on_entry, NULL);
}
if (js_main_hook != NULL) {

View File

@ -67,3 +67,8 @@ debug:
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
--ex 'set disassembly-flavor intel' \
--args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
lldb:
lldb \
-O 'settings set target.env-vars DYLD_INSERT_LIBRARIES=$(ROOT)afl-frida-trace.so' \
-- $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)

View File

@ -331,7 +331,7 @@ llvmGetPassPluginInfo() {
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
#if LLVM_VERSION_MAJOR >= 15
#if LLVM_VERSION_MAJOR >= 16
PB.registerFullLinkTimeOptimizationLastEPCallback(
#else
PB.registerOptimizerLastEPCallback(

View File

@ -13,42 +13,64 @@
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#if LLVM_VERSION_MAJOR >= 15
#if LLVM_VERSION_MAJOR < 17
#include "llvm/ADT/Triple.h"
#endif
#endif
#if LLVM_VERSION_MAJOR < 17
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/EHPersonalities.h"
#else
#include "llvm/IR/EHPersonalities.h"
#endif
#include "llvm/Analysis/PostDominators.h"
#include "llvm/IR/CFG.h"
#if LLVM_VERSION_MAJOR < 15
#include "llvm/IR/CFG.h"
#endif
#include "llvm/IR/Constant.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#if LLVM_VERSION_MAJOR < 15
#include "llvm/IR/DebugInfo.h"
#endif
#include "llvm/IR/Dominators.h"
#if LLVM_VERSION_MAJOR >= 17
#include "llvm/Analysis/EHPersonalities.h"
#endif
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#if LLVM_VERSION_MAJOR >= 16
#include "llvm/IR/GlobalVariable.h"
#endif
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InlineAsm.h"
#if LLVM_VERSION_MAJOR < 15
#include "llvm/IR/InlineAsm.h"
#endif
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Mangler.h"
#if LLVM_VERSION_MAJOR < 15
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Mangler.h"
#endif
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/IR/Type.h"
#include "llvm/InitializePasses.h"
#if LLVM_VERSION_MAJOR < 17
#include "llvm/InitializePasses.h"
#endif
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/SpecialCaseList.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Instrumentation.h"
#if LLVM_VERSION_MAJOR < 15
#include "llvm/Support/raw_ostream.h"
#endif
#if LLVM_VERSION_MAJOR < 17
#include "llvm/Transforms/Instrumentation.h"
#else
#include "llvm/TargetParser/Triple.h"
#endif
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#include "config.h"
#include "debug.h"
@ -58,7 +80,8 @@ using namespace llvm;
#define DEBUG_TYPE "sancov"
const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir";
static const uint64_t SanCtorAndDtorPriority = 2;
const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc";
const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1";
const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2";
@ -68,22 +91,13 @@ const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1";
const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2";
const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4";
const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8";
const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4";
const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8";
const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep";
const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch";
const char SanCovModuleCtorTracePcGuardName[] =
"sancov.module_ctor_trace_pc_guard";
const char SanCovModuleCtor8bitCountersName[] =
"sancov.module_ctor_8bit_counters";
const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag";
static const uint64_t SanCtorAndDtorPriority = 2;
const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init";
const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard";
const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init";
const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init";
const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init";
const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init";
const char SanCovGuardsSectionName[] = "sancov_guards";
const char SanCovCountersSectionName[] = "sancov_cntrs";
@ -99,27 +113,9 @@ namespace {
SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
// Sets CoverageType and IndirectCalls.
// SanitizerCoverageOptions CLOpts = getOptions(ClCoverageLevel);
Options.CoverageType =
SanitizerCoverageOptions::SCK_Edge; // std::max(Options.CoverageType,
// CLOpts.CoverageType);
Options.IndirectCalls = false; // CLOpts.IndirectCalls;
Options.TraceCmp = false; //|= ClCMPTracing;
Options.TraceDiv = false; //|= ClDIVTracing;
Options.TraceGep = false; //|= ClGEPTracing;
Options.TracePC = false; //|= ClTracePC;
Options.TracePCGuard = true; // |= ClTracePCGuard;
Options.Inline8bitCounters = 0; //|= ClInline8bitCounters;
// Options.InlineBoolFlag = 0; //|= ClInlineBoolFlag;
Options.PCTable = false; //|= ClCreatePCTable;
Options.NoPrune = false; //|= !ClPruneBlocks;
Options.StackDepth = false; //|= ClStackDepth;
if (!Options.TracePCGuard && !Options.TracePC &&
!Options.Inline8bitCounters && !Options.StackDepth /*&&
!Options.InlineBoolFlag*/)
Options.TracePCGuard = true; // TracePCGuard is default.
Options.CoverageType = SanitizerCoverageOptions::SCK_Edge;
// Options.NoPrune = true;
Options.TracePCGuard = true; // TracePCGuard is default.
return Options;
}
@ -139,20 +135,13 @@ class ModuleSanitizerCoverageAFL
}
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
bool instrumentModule(Module &M, DomTreeCallback DTCallback,
PostDomTreeCallback PDTCallback);
bool instrumentModule(Module &M, DomTreeCallback DTCallback,
PostDomTreeCallback PDTCallback);
private:
void instrumentFunction(Function &F, DomTreeCallback DTCallback,
PostDomTreeCallback PDTCallback);
void InjectCoverageForIndirectCalls(Function &F,
ArrayRef<Instruction *> IndirCalls);
void InjectTraceForCmp(Function &F, ArrayRef<Instruction *> CmpTraceTargets);
void InjectTraceForDiv(Function &F,
ArrayRef<BinaryOperator *> DivTraceTargets);
void InjectTraceForGep(Function &F,
ArrayRef<GetElementPtrInst *> GepTraceTargets);
void InjectTraceForSwitch(Function &F,
ArrayRef<Instruction *> SwitchTraceTargets);
bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
@ -173,20 +162,21 @@ class ModuleSanitizerCoverageAFL
void SetNoSanitizeMetadata(Instruction *I) {
#if LLVM_VERSION_MAJOR >= 16
I->setMetadata(LLVMContext::MD_nosanitize, MDNode::get(*C, std::nullopt));
#else
I->setMetadata(I->getModule()->getMDKindID("nosanitize"),
MDNode::get(*C, None));
#endif
}
std::string getSectionName(const std::string &Section) const;
std::string getSectionStart(const std::string &Section) const;
std::string getSectionEnd(const std::string &Section) const;
FunctionCallee SanCovTracePCIndir;
FunctionCallee SanCovTracePC, SanCovTracePCGuard;
FunctionCallee SanCovTraceCmpFunction[4];
FunctionCallee SanCovTraceConstCmpFunction[4];
FunctionCallee SanCovTraceDivFunction[2];
FunctionCallee SanCovTraceGepFunction;
FunctionCallee SanCovTraceSwitchFunction;
GlobalVariable *SanCovLowestStack;
Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
@ -215,18 +205,16 @@ class ModuleSanitizerCoverageAFL
} // namespace
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "SanitizerCoveragePCGUARD", "v0.1",
return {LLVM_PLUGIN_API_VERSION, "SanitizerCoveragePCGUARD", "v0.2",
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR <= 13
#if LLVM_VERSION_MAJOR == 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
#endif
PB.registerOptimizerLastEPCallback(
[](ModulePassManager &MPM, OptimizationLevel OL) {
@ -238,8 +226,7 @@ llvmGetPassPluginInfo() {
}
#endif
#if LLVM_VERSION_MAJOR == 1
PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
ModuleAnalysisManager &MAM) {
@ -257,34 +244,65 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
};
if (!ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
return PreservedAnalyses::all();
PreservedAnalyses PA = PreservedAnalyses::none();
// GlobalsAA is considered stateless and does not get invalidated unless
// explicitly invalidated; PreservedAnalyses::none() is not enough. Sanitizers
// make changes that require GlobalsAA to be invalidated.
PA.abandon<GlobalsAA>();
return PA;
}
#else
#if LLVM_VERSION_MAJOR >= 16
PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
ModuleAnalysisManager &MAM) {
#else
PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
ModuleAnalysisManager &MAM) {
#endif
ModuleSanitizerCoverageAFL ModuleSancov(Options);
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
auto DTCallback = [&FAM](Function &F) -> const DominatorTree * {
return &FAM.getResult<DominatorTreeAnalysis>(F);
};
auto PDTCallback = [&FAM](Function &F) -> const PostDominatorTree * {
return &FAM.getResult<PostDominatorTreeAnalysis>(F);
};
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
return PreservedAnalyses::none();
return PreservedAnalyses::all();
}
#endif
std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd(
Module &M, const char *Section, Type *Ty) {
GlobalVariable *SecStart =
new GlobalVariable(M,
#if LLVM_VERSION_MAJOR >= 15
Ty,
#else
Ty->getPointerElementType(),
#endif
false, GlobalVariable::ExternalWeakLinkage, nullptr,
getSectionStart(Section));
// Use ExternalWeak so that if all sections are discarded due to section
// garbage collection, the linker will not report undefined symbol errors.
// Windows defines the start/stop symbols in compiler-rt so no need for
// ExternalWeak.
GlobalValue::LinkageTypes Linkage = TargetTriple.isOSBinFormatCOFF()
? GlobalVariable::ExternalLinkage
: GlobalVariable::ExternalWeakLinkage;
GlobalVariable *SecStart = new GlobalVariable(M, Ty, false, Linkage, nullptr,
getSectionStart(Section));
SecStart->setVisibility(GlobalValue::HiddenVisibility);
GlobalVariable *SecEnd =
new GlobalVariable(M,
#if LLVM_VERSION_MAJOR >= 15
Ty,
#else
Ty->getPointerElementType(),
#endif
false, GlobalVariable::ExternalWeakLinkage, nullptr,
getSectionEnd(Section));
GlobalVariable *SecEnd = new GlobalVariable(M, Ty, false, Linkage, nullptr,
getSectionEnd(Section));
SecEnd->setVisibility(GlobalValue::HiddenVisibility);
IRBuilder<> IRB(M.getContext());
if (!TargetTriple.isOSBinFormatCOFF())
@ -295,7 +313,8 @@ std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd(
auto SecStartI8Ptr = IRB.CreatePointerCast(SecStart, Int8PtrTy);
auto GEP = IRB.CreateGEP(Int8Ty, SecStartI8Ptr,
ConstantInt::get(IntptrTy, sizeof(uint64_t)));
return std::make_pair(IRB.CreatePointerCast(GEP, Ty), SecEnd);
return std::make_pair(IRB.CreatePointerCast(GEP, PointerType::getUnqual(Ty)),
SecEnd);
}
@ -307,8 +326,9 @@ Function *ModuleSanitizerCoverageAFL::CreateInitCallsForSections(
auto SecStart = SecStartEnd.first;
auto SecEnd = SecStartEnd.second;
Function *CtorFunc;
Type *PtrTy = PointerType::getUnqual(Ty);
std::tie(CtorFunc, std::ignore) = createSanitizerCtorAndInitFunctions(
M, CtorName, InitFunctionName, {Ty, Ty}, {SecStart, SecEnd});
M, CtorName, InitFunctionName, {PtrTy, PtrTy}, {SecStart, SecEnd});
assert(CtorFunc->getName() == CtorName);
if (TargetTriple.supportsCOMDAT()) {
@ -332,7 +352,6 @@ Function *ModuleSanitizerCoverageAFL::CreateInitCallsForSections(
// to include the sancov constructor. This way the linker can deduplicate
// the constructors but always leave one copy.
CtorFunc->setLinkage(GlobalValue::WeakODRLinkage);
appendToUsed(M, CtorFunc);
}
@ -344,37 +363,25 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
setvbuf(stdout, NULL, _IONBF, 0);
if (getenv("AFL_DEBUG")) debug = 1;
if (getenv("AFL_DEBUG")) { debug = 1; }
if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
SAYF(cCYA "SanitizerCoveragePCGUARD" VERSION cRST "\n");
} else
} else {
be_quiet = 1;
}
skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
initInstrumentList();
scanForDangerousFunctions(&M);
if (debug) {
fprintf(stderr,
"SANCOV: covtype:%u indirect:%d stack:%d noprune:%d "
"createtable:%d tracepcguard:%d tracepc:%d\n",
Options.CoverageType, Options.IndirectCalls == true ? 1 : 0,
Options.StackDepth == true ? 1 : 0, Options.NoPrune == true ? 1 : 0,
// Options.InlineBoolFlag == true ? 1 : 0,
Options.PCTable == true ? 1 : 0,
Options.TracePCGuard == true ? 1 : 0,
Options.TracePC == true ? 1 : 0);
}
if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false;
C = &(M.getContext());
DL = &M.getDataLayout();
CurModule = &M;
@ -397,16 +404,14 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
Int16Ty = IRB.getInt16Ty();
Int8Ty = IRB.getInt8Ty();
Int1Ty = IRB.getInt1Ty();
LLVMContext &Ctx = M.getContext();
LLVMContext &Ctx = M.getContext();
AFLMapPtr =
new GlobalVariable(M, PointerType::get(Int8Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
One = ConstantInt::get(IntegerType::getInt8Ty(Ctx), 1);
Zero = ConstantInt::get(IntegerType::getInt8Ty(Ctx), 0);
SanCovTracePCIndir =
M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy);
// Make sure smaller parameters are zero-extended to i64 if required by the
// target ABI.
AttributeList SanCovTraceCmpZeroExtAL;
@ -436,26 +441,13 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
SanCovTraceConstCmpFunction[3] =
M.getOrInsertFunction(SanCovTraceConstCmp8, VoidTy, Int64Ty, Int64Ty);
{
AttributeList AL;
AL = AL.addParamAttribute(*C, 0, Attribute::ZExt);
SanCovTraceDivFunction[0] =
M.getOrInsertFunction(SanCovTraceDiv4, AL, VoidTy, IRB.getInt32Ty());
}
SanCovTraceDivFunction[1] =
M.getOrInsertFunction(SanCovTraceDiv8, VoidTy, Int64Ty);
SanCovTraceGepFunction =
M.getOrInsertFunction(SanCovTraceGep, VoidTy, IntptrTy);
SanCovTraceSwitchFunction =
M.getOrInsertFunction(SanCovTraceSwitchName, VoidTy, Int64Ty, Int64PtrTy);
Constant *SanCovLowestStackConstant =
M.getOrInsertGlobal(SanCovLowestStackName, IntptrTy);
SanCovLowestStack = dyn_cast<GlobalVariable>(SanCovLowestStackConstant);
if (!SanCovLowestStack) {
if (!SanCovLowestStack || SanCovLowestStack->getValueType() != IntptrTy) {
C->emitError(StringRef("'") + SanCovLowestStackName +
"' should not be declared by the user");
@ -465,8 +457,6 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
SanCovLowestStack->setThreadLocalMode(
GlobalValue::ThreadLocalMode::InitialExecTLSModel);
if (Options.StackDepth && !SanCovLowestStack->isDeclaration())
SanCovLowestStack->setInitializer(Constant::getAllOnesValue(IntptrTy));
SanCovTracePC = M.getOrInsertFunction(SanCovTracePCName, VoidTy);
SanCovTracePCGuard =
@ -481,40 +471,25 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
Ctor = CreateInitCallsForSections(M, SanCovModuleCtorTracePcGuardName,
SanCovTracePCGuardInitName, Int32PtrTy,
SanCovGuardsSectionName);
if (Function8bitCounterArray)
Ctor = CreateInitCallsForSections(M, SanCovModuleCtor8bitCountersName,
SanCov8bitCountersInitName, Int8PtrTy,
SanCovCountersSectionName);
if (FunctionBoolArray) {
Ctor = CreateInitCallsForSections(M, SanCovModuleCtorBoolFlagName,
SanCovBoolFlagInitName, Int1PtrTy,
SanCovBoolFlagSectionName);
if (Ctor && debug) {
fprintf(stderr, "SANCOV: installed pcguard_init in ctor\n");
}
if (Ctor && Options.PCTable) {
auto SecStartEnd = CreateSecStartEnd(M, SanCovPCsSectionName, IntptrPtrTy);
FunctionCallee InitFunction = declareSanitizerInitFunction(
M, SanCovPCsInitName, {IntptrPtrTy, IntptrPtrTy});
IRBuilder<> IRBCtor(Ctor->getEntryBlock().getTerminator());
IRBCtor.CreateCall(InitFunction, {SecStartEnd.first, SecStartEnd.second});
}
// We don't reference these arrays directly in any of our runtime functions,
// so we need to prevent them from being dead stripped.
if (TargetTriple.isOSBinFormatMachO()) appendToUsed(M, GlobalsToAppendToUsed);
appendToUsed(M, GlobalsToAppendToUsed);
appendToCompilerUsed(M, GlobalsToAppendToCompilerUsed);
if (!be_quiet) {
if (!instr)
WARNF("No instrumentation targets found.");
else {
if (!instr) {
char modeline[100];
WARNF("No instrumentation targets found.");
} else {
char modeline[128];
snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s",
getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
getenv("AFL_USE_ASAN") ? ", ASAN" : "",
@ -535,39 +510,36 @@ bool ModuleSanitizerCoverageAFL::instrumentModule(
}
// True if block has successors and it dominates all of them.
bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
if (succ_begin(BB) == succ_end(BB)) return false;
if (succ_empty(BB)) return false;
for (const BasicBlock *SUCC : make_range(succ_begin(BB), succ_end(BB))) {
return llvm::all_of(successors(BB), [&](const BasicBlock *SUCC) {
if (!DT->dominates(BB, SUCC)) return false;
return DT->dominates(BB, SUCC);
}
return true;
});
}
// True if block has predecessors and it postdominates all of them.
bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) {
static bool isFullPostDominator(const BasicBlock *BB,
const PostDominatorTree *PDT) {
if (pred_begin(BB) == pred_end(BB)) return false;
if (pred_empty(BB)) return false;
for (const BasicBlock *PRED : make_range(pred_begin(BB), pred_end(BB))) {
return llvm::all_of(predecessors(BB), [&](const BasicBlock *PRED) {
if (!PDT->dominates(BB, PRED)) return false;
return PDT->dominates(BB, PRED);
}
return true;
});
}
bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
const DominatorTree *DT,
const PostDominatorTree *PDT,
const SanitizerCoverageOptions &Options) {
static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
const DominatorTree *DT,
const PostDominatorTree *PDT,
const SanitizerCoverageOptions &Options) {
// Don't insert coverage for blocks containing nothing but unreachable: we
// will never call __sanitizer_cov() for them, so counting them in
@ -582,10 +554,6 @@ bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
if (Options.NoPrune || &F.getEntryBlock() == BB) return true;
if (Options.CoverageType == SanitizerCoverageOptions::SCK_Function &&
&F.getEntryBlock() != BB)
return false;
// Do not instrument full dominators, or full post-dominators with multiple
// predecessors.
return !isFullDominator(BB, DT) &&
@ -597,38 +565,47 @@ bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
// A twist here is that we treat From->To as a backedge if
// * To dominates From or
// * To->UniqueSuccessor dominates From
bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) {
#if 0
static bool IsBackEdge(BasicBlock *From, BasicBlock *To,
const DominatorTree *DT) {
if (DT->dominates(To, From)) return true;
if (DT->dominates(To, From))
return true;
if (auto Next = To->getUniqueSuccessor())
if (DT->dominates(Next, From)) return true;
if (DT->dominates(Next, From))
return true;
return false;
}
#endif
// Prunes uninteresting Cmp instrumentation:
// * CMP instructions that feed into loop backedge branch.
//
// Note that Cmp pruning is controlled by the same flag as the
// BB pruning.
bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT,
const SanitizerCoverageOptions &Options) {
#if 0
static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT,
const SanitizerCoverageOptions &Options) {
if (!Options.NoPrune)
if (CMP->hasOneUse())
if (auto BR = dyn_cast<BranchInst>(CMP->user_back()))
for (BasicBlock *B : BR->successors())
if (IsBackEdge(BR->getParent(), B, DT)) return false;
if (IsBackEdge(BR->getParent(), B, DT))
return false;
return true;
}
#endif
void ModuleSanitizerCoverageAFL::instrumentFunction(
Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
if (F.empty()) return;
if (!isInInstrumentList(&F, FMNAME)) return;
if (F.getName().find(".module_ctor") != std::string::npos)
return; // Should not instrument sanitizer init functions.
if (F.getName().startswith("__sanitizer_"))
@ -647,15 +624,13 @@ void ModuleSanitizerCoverageAFL::instrumentFunction(
if (F.hasPersonalityFn() &&
isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
return;
if (F.hasFnAttribute(Attribute::NoSanitizeCoverage)) return;
if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
SplitAllCriticalEdges(
F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
SmallVector<Instruction *, 8> IndirCalls;
SmallVector<BasicBlock *, 16> BlocksToInstrument;
SmallVector<Instruction *, 8> CmpTraceTargets;
SmallVector<Instruction *, 8> SwitchTraceTargets;
SmallVector<BinaryOperator *, 8> DivTraceTargets;
SmallVector<GetElementPtrInst *, 8> GepTraceTargets;
SmallVector<BasicBlock *, 16> BlocksToInstrument;
SmallVector<Instruction *, 8> CmpTraceTargets;
SmallVector<Instruction *, 8> SwitchTraceTargets;
const DominatorTree *DT = DTCallback(F);
const PostDominatorTree *PDT = PDTCallback(F);
@ -665,47 +640,28 @@ void ModuleSanitizerCoverageAFL::instrumentFunction(
if (shouldInstrumentBlock(F, &BB, DT, PDT, Options))
BlocksToInstrument.push_back(&BB);
for (auto &Inst : BB) {
/*
for (auto &Inst : BB) {
if (Options.IndirectCalls) {
if (Options.TraceCmp) {
CallBase *CB = dyn_cast<CallBase>(&Inst);
if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst);
if (ICmpInst *CMP = dyn_cast<ICmpInst>(&Inst))
if (IsInterestingCmp(CMP, DT, Options))
CmpTraceTargets.push_back(&Inst);
if (isa<SwitchInst>(&Inst))
SwitchTraceTargets.push_back(&Inst);
}
}
if (Options.TraceCmp) {
}
if (ICmpInst *CMP = dyn_cast<ICmpInst>(&Inst))
if (IsInterestingCmp(CMP, DT, Options))
CmpTraceTargets.push_back(&Inst);
if (isa<SwitchInst>(&Inst)) SwitchTraceTargets.push_back(&Inst);
}
if (Options.TraceDiv)
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(&Inst))
if (BO->getOpcode() == Instruction::SDiv ||
BO->getOpcode() == Instruction::UDiv)
DivTraceTargets.push_back(BO);
if (Options.TraceGep)
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(&Inst))
GepTraceTargets.push_back(GEP);
if (Options.StackDepth)
if (isa<InvokeInst>(Inst) ||
(isa<CallInst>(Inst) && !isa<IntrinsicInst>(Inst)))
IsLeafFunc = false;
}
*/
}
InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
InjectCoverageForIndirectCalls(F, IndirCalls);
InjectTraceForCmp(F, CmpTraceTargets);
InjectTraceForSwitch(F, SwitchTraceTargets);
InjectTraceForDiv(F, DivTraceTargets);
InjectTraceForGep(F, GepTraceTargets);
// InjectTraceForCmp(F, CmpTraceTargets);
// InjectTraceForSwitch(F, SwitchTraceTargets);
}
@ -717,33 +673,30 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection(
*CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
Constant::getNullValue(ArrayTy), "__sancov_gen_");
#if LLVM_VERSION_MAJOR >= 13
if (TargetTriple.supportsCOMDAT() &&
(TargetTriple.isOSBinFormatELF() || !F.isInterposable()))
if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple))
Array->setComdat(Comdat);
Array->setSection(getSectionName(Section));
#if LLVM_VERSION_MAJOR >= 16
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedValue()));
#else
if (TargetTriple.supportsCOMDAT() && !F.isInterposable())
if (auto Comdat =
GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
Array->setComdat(Comdat);
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
#endif
Array->setSection(getSectionName(Section));
#if (LLVM_VERSION_MAJOR >= 11) || \
(LLVM_VERSION_MAJOR == 10 && LLVM_VERSION_MINOR >= 1)
#if LLVM_VERSION_MAJOR >= 16
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedValue()));
#else
Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize()));
#endif
#else
Array->setAlignment(Align(4)); // cheating
#endif
GlobalsToAppendToUsed.push_back(Array);
GlobalsToAppendToCompilerUsed.push_back(Array);
MDNode *MD = MDNode::get(F.getContext(), ValueAsMetadata::get(&F));
Array->addMetadata(LLVMContext::MD_associated, *MD);
// sancov_pcs parallels the other metadata section(s). Optimizers (e.g.
// GlobalOpt/ConstantMerge) may not discard sancov_pcs and the other
// section(s) as a unit, so we conservatively retain all unconditionally in
// the compiler.
//
// With comdat (COFF/ELF), the linker can guarantee the associated sections
// will be retained or discarded as a unit, so llvm.compiler.used is
// sufficient. Otherwise, conservatively make all of them retained by the
// linker.
if (Array->hasComdat())
GlobalsToAppendToCompilerUsed.push_back(Array);
else
GlobalsToAppendToUsed.push_back(Array);
return Array;
@ -768,8 +721,12 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreatePCArray(
PCs.push_back((Constant *)IRB.CreatePointerCast(
BlockAddress::get(AllBlocks[i]), IntptrPtrTy));
#if LLVM_VERSION_MAJOR >= 16
PCs.push_back(Constant::getNullValue(IntptrPtrTy));
#else
PCs.push_back((Constant *)IRB.CreateIntToPtr(
ConstantInt::get(IntptrTy, 0), IntptrPtrTy));
#endif
}
@ -792,21 +749,13 @@ void ModuleSanitizerCoverageAFL::CreateFunctionLocalArrays(
FunctionGuardArray = CreateFunctionLocalArrayInSection(
AllBlocks.size() + special, F, Int32Ty, SanCovGuardsSectionName);
if (Options.Inline8bitCounters)
Function8bitCounterArray = CreateFunctionLocalArrayInSection(
AllBlocks.size(), F, Int8Ty, SanCovCountersSectionName);
/*
if (Options.InlineBoolFlag)
FunctionBoolArray = CreateFunctionLocalArrayInSection(
AllBlocks.size(), F, Int1Ty, SanCovBoolFlagSectionName);
*/
if (Options.PCTable) FunctionPCsArray = CreatePCArray(F, AllBlocks);
}
bool ModuleSanitizerCoverageAFL::InjectCoverage(
Function &F, ArrayRef<BasicBlock *> AllBlocks, bool IsLeafFunc) {
if (AllBlocks.empty()) return false;
uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0;
static uint32_t first = 1;
@ -855,7 +804,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
#if (LLVM_VERSION_MAJOR >= 12)
else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
@ -868,16 +816,14 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
#endif
}
}
}
/* Create PCGUARD array */
CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc);
if (first) { first = 0; }
selects += cnt_sel;
@ -889,12 +835,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
CallInst *callInst = nullptr;
/*
std::string errMsg;
raw_string_ostream os(errMsg);
IN.print(os);
fprintf(stderr, "X: %s\n", os.str().c_str());
*/
if ((callInst = dyn_cast<CallInst>(&IN))) {
Function *Callee = callInst->getCalledFunction();
@ -1033,12 +973,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
/*
std::string errMsg;
raw_string_ostream os(errMsg);
x->print(os);
fprintf(stderr, "X: %s\n", os.str().c_str());
*/
result = IRB.CreateSelect(condition, x, y);
}
@ -1063,13 +997,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(MapPtr);
/*
std::string errMsg;
raw_string_ostream os(errMsg);
result->print(os);
fprintf(stderr, "X: %s\n", os.str().c_str());
*/
while (1) {
/* Get CurLoc */
@ -1159,29 +1086,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
// On every indirect call we call a run-time function
// __sanitizer_cov_indir_call* with two parameters:
// - callee address,
// - global cache array that contains CacheSize pointers (zero-initialized).
// The cache is used to speed up recording the caller-callee pairs.
// The address of the caller is passed implicitly via caller PC.
// CacheSize is encoded in the name of the run-time function.
void ModuleSanitizerCoverageAFL::InjectCoverageForIndirectCalls(
Function &F, ArrayRef<Instruction *> IndirCalls) {
if (IndirCalls.empty()) return;
for (auto I : IndirCalls) {
IRBuilder<> IRB(I);
CallBase &CB = cast<CallBase>(*I);
Value *Callee = CB.getCalledOperand();
if (isa<InlineAsm>(Callee)) continue;
IRB.CreateCall(SanCovTracePCIndir, IRB.CreatePointerCast(Callee, IntptrTy));
}
}
// For every switch statement we insert a call:
// __sanitizer_cov_trace_switch(CondValue,
// {NumCases, ValueSizeInBits, Case0Value, Case1Value, Case2Value, ... })
@ -1237,41 +1141,6 @@ void ModuleSanitizerCoverageAFL::InjectTraceForSwitch(
}
void ModuleSanitizerCoverageAFL::InjectTraceForDiv(
Function &, ArrayRef<BinaryOperator *> DivTraceTargets) {
for (auto BO : DivTraceTargets) {
IRBuilder<> IRB(BO);
Value *A1 = BO->getOperand(1);
if (isa<ConstantInt>(A1)) continue;
if (!A1->getType()->isIntegerTy()) continue;
uint64_t TypeSize = DL->getTypeStoreSizeInBits(A1->getType());
int CallbackIdx = TypeSize == 32 ? 0 : TypeSize == 64 ? 1 : -1;
if (CallbackIdx < 0) continue;
auto Ty = Type::getIntNTy(*C, TypeSize);
IRB.CreateCall(SanCovTraceDivFunction[CallbackIdx],
{IRB.CreateIntCast(A1, Ty, true)});
}
}
void ModuleSanitizerCoverageAFL::InjectTraceForGep(
Function &, ArrayRef<GetElementPtrInst *> GepTraceTargets) {
for (auto GEP : GepTraceTargets) {
IRBuilder<> IRB(GEP);
for (Use &Idx : GEP->indices())
if (!isa<ConstantInt>(Idx) && Idx->getType()->isIntegerTy())
IRB.CreateCall(SanCovTraceGepFunction,
{IRB.CreateIntCast(Idx, IntptrTy, true)});
}
}
void ModuleSanitizerCoverageAFL::InjectTraceForCmp(
Function &, ArrayRef<Instruction *> CmpTraceTargets) {
@ -1321,27 +1190,44 @@ void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function &F,
BasicBlock::iterator IP = BB.getFirstInsertionPt();
bool IsEntryBB = &BB == &F.getEntryBlock();
DebugLoc EntryLoc;
if (IsEntryBB) {
// Keep allocas and llvm.localescape calls in the entry block. Even
if (auto SP = F.getSubprogram())
EntryLoc = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP);
// Keep static allocas and llvm.localescape calls in the entry block. Even
// if we aren't splitting the block, it's nice for allocas to be before
// calls.
IP = PrepareToSplitEntryBlock(BB, IP);
#if LLVM_VERSION_MAJOR < 15
} else {
EntryLoc = IP->getDebugLoc();
if (!EntryLoc)
if (auto *SP = F.getSubprogram())
EntryLoc = DILocation::get(SP->getContext(), 0, 0, SP);
#endif
}
#if LLVM_VERSION_MAJOR >= 16
InstrumentationIRBuilder IRB(&*IP);
#else
IRBuilder<> IRB(&*IP);
if (Options.TracePC) {
IRB.CreateCall(SanCovTracePC);
// ->setCannotMerge(); // gets the PC using GET_CALLER_PC.
}
#endif
if (EntryLoc) IRB.SetCurrentDebugLocation(EntryLoc);
if (Options.TracePCGuard) {
/*
auto GuardPtr = IRB.CreateIntToPtr(
IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(IntptrTy, Idx * 4)),
Int32PtrTy);
IRB.CreateCall(SanCovTracePCGuard, GuardPtr)->setCannotMerge();
*/
/* Get CurLoc */
Value *GuardPtr = IRB.CreateIntToPtr(
@ -1399,57 +1285,6 @@ void ModuleSanitizerCoverageAFL::InjectCoverageAtBlock(Function &F,
}
if (Options.Inline8bitCounters) {
auto CounterPtr = IRB.CreateGEP(
Function8bitCounterArray->getValueType(), Function8bitCounterArray,
{ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
auto Load = IRB.CreateLoad(Int8Ty, CounterPtr);
auto Inc = IRB.CreateAdd(Load, ConstantInt::get(Int8Ty, 1));
auto Store = IRB.CreateStore(Inc, CounterPtr);
SetNoSanitizeMetadata(Load);
SetNoSanitizeMetadata(Store);
}
/*
if (Options.InlineBoolFlag) {
auto FlagPtr = IRB.CreateGEP(
FunctionBoolArray->getValueType(), FunctionBoolArray,
{ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
auto Load = IRB.CreateLoad(Int1Ty, FlagPtr);
auto ThenTerm =
SplitBlockAndInsertIfThen(IRB.CreateIsNull(Load), &*IP, false);
IRBuilder<> ThenIRB(ThenTerm);
auto Store = ThenIRB.CreateStore(ConstantInt::getTrue(Int1Ty), FlagPtr);
SetNoSanitizeMetadata(Load);
SetNoSanitizeMetadata(Store);
}
*/
if (Options.StackDepth && IsEntryBB && !IsLeafFunc) {
// Check stack depth. If it's the deepest so far, record it.
Module *M = F.getParent();
Function *GetFrameAddr = Intrinsic::getDeclaration(
M, Intrinsic::frameaddress,
IRB.getInt8PtrTy(M->getDataLayout().getAllocaAddrSpace()));
auto FrameAddrPtr =
IRB.CreateCall(GetFrameAddr, {Constant::getNullValue(Int32Ty)});
auto FrameAddrInt = IRB.CreatePtrToInt(FrameAddrPtr, IntptrTy);
auto LowestStack = IRB.CreateLoad(IntptrTy, SanCovLowestStack);
auto IsStackLower = IRB.CreateICmpULT(FrameAddrInt, LowestStack);
auto ThenTerm = SplitBlockAndInsertIfThen(IsStackLower, &*IP, false);
IRBuilder<> ThenIRB(ThenTerm);
auto Store = ThenIRB.CreateStore(FrameAddrInt, SanCovLowestStack);
SetNoSanitizeMetadata(LowestStack);
SetNoSanitizeMetadata(Store);
}
}
std::string ModuleSanitizerCoverageAFL::getSectionName(

View File

@ -997,7 +997,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (instrument_mode == INSTRUMENT_PCGUARD) {
#if LLVM_MAJOR >= 11
#if LLVM_MAJOR >= 13
#if defined __ANDROID__ || ANDROID
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode = INSTRUMENT_LLVMNATIVE;
@ -1014,7 +1014,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
} else {
#if LLVM_MAJOR >= 11 /* use new pass manager */
#if LLVM_MAJOR >= 13 /* use new pass manager */
#if LLVM_MAJOR < 16
cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
#endif
@ -1035,12 +1035,12 @@ static void edit_params(u32 argc, char **argv, char **envp) {
#if LLVM_MAJOR >= 4
if (!be_quiet)
SAYF(
"Using unoptimized trace-pc-guard, upgrade to llvm 10.0.1+ for "
"Using unoptimized trace-pc-guard, upgrade to LLVM 13+ for "
"enhanced version.\n");
cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
instrument_mode = INSTRUMENT_LLVMNATIVE;
#else
FATAL("pcguard instrumentation requires llvm 4.0.1+");
FATAL("pcguard instrumentation requires LLVM 4.0.1+");
#endif
#endif
@ -1053,7 +1053,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
cc_params[cc_par_cnt++] =
"-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table";
#else
FATAL("pcguard instrumentation with pc-table requires llvm 6.0.1+");
FATAL("pcguard instrumentation with pc-table requires LLVM 6.0.1+");
#endif
} else {
@ -1063,7 +1063,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
#else
FATAL("pcguard instrumentation requires llvm 4.0.1+");
FATAL("pcguard instrumentation requires LLVM 4.0.1+");
#endif
} else {
@ -2031,7 +2031,7 @@ int main(int argc, char **argv, char **envp) {
if (!compiler_mode) {
// lto is not a default because outside of afl-cc RANLIB and AR have to
// be set to llvm versions so this would work
// be set to LLVM versions so this would work
if (have_llvm)
compiler_mode = LLVM;
else if (have_gcc_plugin)
@ -2050,6 +2050,17 @@ int main(int argc, char **argv, char **envp) {
}
/* if our PCGUARD implementation is not available then silently switch to
native LLVM PCGUARD */
if (compiler_mode == CLANG &&
(instrument_mode == INSTRUMENT_DEFAULT ||
instrument_mode == INSTRUMENT_PCGUARD) &&
find_object("SanitizerCoveragePCGUARD.so", argv[0]) == NULL) {
instrument_mode = INSTRUMENT_LLVMNATIVE;
}
if (compiler_mode == GCC) {
if (clang_mode) {
@ -2096,12 +2107,12 @@ int main(int argc, char **argv, char **envp) {
"-------------|\n"
"MODES: NCC PERSIST DICT LAF "
"CMPLOG SELECT\n"
" [LTO] llvm LTO: %s%s\n"
" [LTO] LLVM LTO: %s%s\n"
" PCGUARD DEFAULT yes yes yes yes yes "
" yes\n"
" CLASSIC yes yes yes yes yes "
" yes\n"
" [LLVM] llvm: %s%s\n"
" [LLVM] LLVM: %s%s\n"
" PCGUARD %s yes yes module yes yes "
"yes\n"
" CLASSIC %s no yes module yes yes "
@ -2171,7 +2182,7 @@ int main(int argc, char **argv, char **envp) {
" (instrumentation/README.lto.md)\n"
" PERSIST: persistent mode support [code] (huge speed increase!)\n"
" (instrumentation/README.persistent_mode.md)\n"
" DICT: dictionary in the target [yes=automatic or llvm module "
" DICT: dictionary in the target [yes=automatic or LLVM module "
"pass]\n"
" (instrumentation/README.lto.md + "
"instrumentation/README.llvm.md)\n"