diff options
-rw-r--r-- | TODO.md | 3 | ||||
-rw-r--r-- | custom_mutators/radamsa/libradamsa.c | 2 | ||||
-rw-r--r-- | docs/Changelog.md | 5 | ||||
-rw-r--r-- | docs/env_variables.md | 2 | ||||
-rw-r--r-- | include/afl-fuzz.h | 15 | ||||
-rw-r--r-- | include/envs.h | 3 | ||||
-rw-r--r-- | include/forkserver.h | 4 | ||||
-rw-r--r-- | instrumentation/SanitizerCoverageLTO.so.cc | 29 | ||||
-rw-r--r-- | instrumentation/SanitizerCoveragePCGUARD.so.cc | 44 | ||||
-rw-r--r-- | src/afl-forkserver.c | 8 | ||||
-rw-r--r-- | src/afl-fuzz-init.c | 2 | ||||
-rw-r--r-- | src/afl-fuzz-queue.c | 9 | ||||
-rw-r--r-- | src/afl-fuzz-run.c | 21 | ||||
-rw-r--r-- | src/afl-fuzz-state.c | 7 | ||||
-rw-r--r-- | src/afl-fuzz-stats.c | 8 | ||||
-rw-r--r-- | src/afl-fuzz.c | 279 | ||||
-rw-r--r-- | src/afl-performance.c | 2 |
17 files changed, 383 insertions, 60 deletions
diff --git a/TODO.md b/TODO.md index b36269b4..6f7505a6 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,8 @@ ## Must - - fast restart of afl-fuzz if cmdline + target hash is the same + - fast resume: + use gzopen(fn, "rb"/"wb9-/f/h", gzwrite, gzread and gzclose - check for null ptr for xml/curl/g_ string transform functions - hardened_usercopy=0 page_alloc.shuffle=0 - add value_profile but only enable after 15 minutes without finds diff --git a/custom_mutators/radamsa/libradamsa.c b/custom_mutators/radamsa/libradamsa.c index e6838752..1dcf91d8 100644 --- a/custom_mutators/radamsa/libradamsa.c +++ b/custom_mutators/radamsa/libradamsa.c @@ -3707,7 +3707,7 @@ typedef intptr_t wdiff; 1024 * 1024 * 8 /* static malloc'd heap size if used as a library */ #define FBITS 24 /* bits in fixnum, on the way to 24 and beyond */ #define FMAX \ - ((1 << FBITS) - 1) /* maximum fixnum (and most negative fixnum) \ + ((1U << FBITS) - 1) /* maximum fixnum (and most negative fixnum) \ */ #define MAXOBJ 0xffff /* max words in tuple including header */ #define MAXPAYL \ diff --git a/docs/Changelog.md b/docs/Changelog.md index 1590b2df..f146534f 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -4,6 +4,11 @@ release of the tool. See README.md for the general instruction manual. ### Version ++4.22a (dev) + - afl-fuzz: + - fastresume feature added. if you abort fuzzing and resume fuzzing + with `-i -` or `AFL_AUTORESUME=1` and the target binary has not changed + then a dump will be loaded and the calibration phase skipped. + to disable this feature set `AFL_NO_FASTRESUME=1` - frida_mode: - AFL_FRIDA_PERSISTENT_ADDR can now be be any reachable address not just a function entry diff --git a/docs/env_variables.md b/docs/env_variables.md index 22e0ce0f..6db31df0 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -514,6 +514,8 @@ checks or alter some of the more exotic semantics of the tool: - `AFL_NO_SNAPSHOT` will advise afl-fuzz not to use the snapshot feature if the snapshot lkm is loaded. + - `AFL_NO_FASTRESUME` will not try to read or write a fast resume file. + - Setting `AFL_NO_UI` inhibits the UI altogether and just periodically prints some basic stats. This behavior is also automatically triggered when the output from afl-fuzz is redirected to a file or to a pipe. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e3e4e246..6d03a74c 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -236,7 +236,6 @@ struct queue_entry { custom, /* Marker for custom mutators */ stats_mutated; /* stats: # of mutations performed */ - u8 *trace_mini; /* Trace bytes, if kept */ u32 tc_ref; /* Trace bytes ref count */ #ifdef INTROSPECTION @@ -246,13 +245,11 @@ struct queue_entry { double perf_score, /* performance score */ weight; - u8 *testcase_buf; /* The testcase buffer, if loaded. */ - - u8 *cmplog_colorinput; /* the result buf of colorization */ - struct tainted *taint; /* Taint information from CmpLog */ - - struct queue_entry *mother; /* queue entry this based on */ - + struct queue_entry *mother; /* queue entry this based on */ + u8 *trace_mini; /* Trace bytes, if kept */ + u8 *testcase_buf; /* The testcase buffer, if loaded. */ + u8 *cmplog_colorinput; /* the result buf of colorization */ + struct tainted *taint; /* Taint information from CmpLog */ struct skipdet_entry *skipdet_e; }; @@ -457,7 +454,7 @@ typedef struct afl_env_vars { afl_no_startup_calibration, afl_no_warn_instability, afl_post_process_keep_original, afl_crashing_seeds_as_new_crash, afl_final_sync, afl_ignore_seed_problems, afl_disable_redundant, - afl_sha1_filenames, afl_no_sync; + afl_sha1_filenames, afl_no_sync, afl_no_fastresume; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, diff --git a/include/envs.h b/include/envs.h index 45b080cb..ef522ab4 100644 --- a/include/envs.h +++ b/include/envs.h @@ -115,7 +115,8 @@ static char *afl_environment_variables[] = { "AFL_TRACE_PC", "AFL_USE_ASAN", "AFL_USE_MSAN", "AFL_USE_TRACE_PC", "AFL_USE_UBSAN", "AFL_USE_TSAN", "AFL_USE_CFISAN", "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", "AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", - "AFL_USE_QASAN", "AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", NULL + "AFL_USE_QASAN", "AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", + "AFL_NO_FASTRESUME", NULL }; diff --git a/include/forkserver.h b/include/forkserver.h index 593e34a2..3fd813a4 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -206,6 +206,10 @@ typedef struct afl_forkserver { s32 nyx_log_fd; #endif +#ifdef __AFL_CODE_COVERAGE + u8 *persistent_trace_bits; /* Persistent copy of bitmap */ +#endif + } afl_forkserver_t; typedef enum fsrv_run_result { diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index a09f28a9..63ea71c1 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -214,8 +214,12 @@ class ModuleSanitizerCoverageLTO void SetNoSanitizeMetadata(Instruction *I) { +#if LLVM_VERSION_MAJOR >= 19 + I->setNoSanitizeMetadata(); +#else I->setMetadata(I->getModule()->getMDKindID("nosanitize"), MDNode::get(*C, None)); +#endif } @@ -225,7 +229,7 @@ class ModuleSanitizerCoverageLTO FunctionCallee SanCovTracePCIndir; FunctionCallee SanCovTracePC /*, SanCovTracePCGuard*/; Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy, - *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy; + *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy, *PtrTy; Module *CurModule; std::string CurModuleUniqueId; Triple TargetTriple; @@ -416,6 +420,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( Int16Ty = IRB.getInt16Ty(); Int8Ty = IRB.getInt8Ty(); Int1Ty = IRB.getInt1Ty(); + PtrTy = PointerType::getUnqual(*C); /* AFL++ START */ char *ptr; @@ -1350,7 +1355,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) { if (F.empty()) return; - if (F.getName().find(".module_ctor") != std::string::npos) + if (F.getName().contains(".module_ctor")) return; // Should not instrument sanitizer init functions. #if LLVM_VERSION_MAJOR >= 18 if (F.getName().starts_with("__sanitizer_")) @@ -1372,6 +1377,10 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( if (F.hasPersonalityFn() && isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn()))) return; + if (F.hasFnAttribute(Attribute::NoSanitizeCoverage)) return; +#if LLVM_VERSION_MAJOR >= 19 + if (F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation)) return; +#endif // if (Allowlist && !Allowlist->inSection("coverage", "fun", F.getName())) // return; // if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName())) @@ -2023,16 +2032,20 @@ GlobalVariable *ModuleSanitizerCoverageLTO::CreatePCArray( if (&F.getEntryBlock() == AllBlocks[i]) { - PCs.push_back((Constant *)IRB.CreatePointerCast(&F, IntptrPtrTy)); - PCs.push_back((Constant *)IRB.CreateIntToPtr( - ConstantInt::get(IntptrTy, 1), IntptrPtrTy)); + PCs.push_back((Constant *)IRB.CreatePointerCast(&F, PtrTy)); + PCs.push_back( + (Constant *)IRB.CreateIntToPtr(ConstantInt::get(IntptrTy, 1), PtrTy)); } else { PCs.push_back((Constant *)IRB.CreatePointerCast( - BlockAddress::get(AllBlocks[i]), IntptrPtrTy)); - PCs.push_back((Constant *)IRB.CreateIntToPtr( - ConstantInt::get(IntptrTy, 0), IntptrPtrTy)); + BlockAddress::get(AllBlocks[i]), PtrTy)); +#if LLVM_VERSION_MAJOR >= 16 + PCs.push_back(Constant::getNullValue(PtrTy)); +#else + PCs.push_back( + (Constant *)IRB.CreateIntToPtr(ConstantInt::get(IntptrTy, 0), PtrTy)); +#endif } diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 01881f28..49fe904b 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -161,7 +161,9 @@ class ModuleSanitizerCoverageAFL void SetNoSanitizeMetadata(Instruction *I) { -#if LLVM_VERSION_MAJOR >= 16 +#if LLVM_VERSION_MAJOR >= 19 + I->setNoSanitizeMetadata(); +#elif LLVM_VERSION_MAJOR >= 16 I->setMetadata(LLVMContext::MD_nosanitize, MDNode::get(*C, std::nullopt)); #else I->setMetadata(I->getModule()->getMDKindID("nosanitize"), @@ -179,7 +181,7 @@ class ModuleSanitizerCoverageAFL FunctionCallee SanCovTraceSwitchFunction; GlobalVariable *SanCovLowestStack; Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy, - *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy; + *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy, *PtrTy; Module *CurModule; std::string CurModuleUniqueId; Triple TargetTriple; @@ -272,13 +274,19 @@ std::pair<Value *, Value *> ModuleSanitizerCoverageAFL::CreateSecStartEnd( if (!TargetTriple.isOSBinFormatCOFF()) return std::make_pair(SecStart, SecEnd); - // Account for the fact that on windows-msvc __start_* symbols actually - // point to a uint64_t before the start of the array. + // Account for the fact that on windows-msvc __start_* symbols actually + // point to a uint64_t before the start of the array. +#if LLVM_VERSION_MAJOR >= 19 + auto GEP = + IRB.CreatePtrAdd(SecStart, ConstantInt::get(IntptrTy, sizeof(uint64_t))); + return std::make_pair(GEP, SecEnd); +#else 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, PointerType::getUnqual(Ty)), SecEnd); +#endif } @@ -370,6 +378,7 @@ bool ModuleSanitizerCoverageAFL::instrumentModule( Int16Ty = IRB.getInt16Ty(); Int8Ty = IRB.getInt8Ty(); Int1Ty = IRB.getInt1Ty(); + PtrTy = PointerType::getUnqual(*C); LLVMContext &Ctx = M.getContext(); AFLMapPtr = @@ -572,7 +581,8 @@ void ModuleSanitizerCoverageAFL::instrumentFunction( if (F.empty()) return; if (!isInInstrumentList(&F, FMNAME)) return; - if (F.getName().find(".module_ctor") != std::string::npos) + // if (F.getName().find(".module_ctor") != std::string::npos) + if (F.getName().contains(".module_ctor")) return; // Should not instrument sanitizer init functions. #if LLVM_VERSION_MAJOR >= 18 if (F.getName().starts_with("__sanitizer_")) @@ -595,6 +605,9 @@ void ModuleSanitizerCoverageAFL::instrumentFunction( isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn()))) return; if (F.hasFnAttribute(Attribute::NoSanitizeCoverage)) return; +#if LLVM_VERSION_MAJOR >= 19 + if (F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation)) return; +#endif if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge) SplitAllCriticalEdges( F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests()); @@ -692,16 +705,16 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreatePCArray( if (&F.getEntryBlock() == AllBlocks[i]) { - PCs.push_back((Constant *)IRB.CreatePointerCast(&F, IntptrPtrTy)); - PCs.push_back((Constant *)IRB.CreateIntToPtr( - ConstantInt::get(IntptrTy, 1), IntptrPtrTy)); + PCs.push_back((Constant *)IRB.CreatePointerCast(&F, PtrTy)); + PCs.push_back( + (Constant *)IRB.CreateIntToPtr(ConstantInt::get(IntptrTy, 1), PtrTy)); } else { PCs.push_back((Constant *)IRB.CreatePointerCast( - BlockAddress::get(AllBlocks[i]), IntptrPtrTy)); + BlockAddress::get(AllBlocks[i]), PtrTy)); #if LLVM_VERSION_MAJOR >= 16 - PCs.push_back(Constant::getNullValue(IntptrPtrTy)); + PCs.push_back(Constant::getNullValue(PtrTy)); #else PCs.push_back((Constant *)IRB.CreateIntToPtr( ConstantInt::get(IntptrTy, 0), IntptrPtrTy)); @@ -711,10 +724,10 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreatePCArray( } - auto *PCArray = CreateFunctionLocalArrayInSection(N * 2, F, IntptrPtrTy, - SanCovPCsSectionName); + auto *PCArray = + CreateFunctionLocalArrayInSection(N * 2, F, PtrTy, SanCovPCsSectionName); PCArray->setInitializer( - ConstantArray::get(ArrayType::get(IntptrPtrTy, N * 2), PCs)); + ConstantArray::get(ArrayType::get(PtrTy, N * 2), PCs)); PCArray->setConstant(true); return PCArray; @@ -822,7 +835,12 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( StringRef FuncName = Callee->getName(); if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue; +#if LLVM_VERSION_MAJOR >= 20 + // test canary + InstrumentationIRBuilder IRB(callInst); +#else IRBuilder<> IRB(callInst); +#endif if (!FunctionGuardArray) { diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 71d8570d..a998c10f 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -252,6 +252,10 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->uses_crash_exitcode = false; fsrv->uses_asan = false; +#ifdef __AFL_CODE_COVERAGE + fsrv->persistent_trace_bits = NULL; +#endif + fsrv->init_child_func = fsrv_exec_child; list_append(&fsrv_list, fsrv); @@ -278,6 +282,10 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->fsrv_kill_signal = from->fsrv_kill_signal; fsrv_to->debug = from->debug; +#ifdef __AFL_CODE_COVERAGE + fsrv_to->persistent_trace_bits = from->persistent_trace_bits; +#endif + // These are forkserver specific. fsrv_to->out_dir_fd = -1; fsrv_to->child_pid = -1; diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 7310e49f..98de26dd 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1019,7 +1019,7 @@ void perform_dry_run(afl_state_t *afl) { } - if (!q->was_fuzzed) { + if (unlikely(!q->was_fuzzed)) { q->was_fuzzed = 1; afl->reinit_table = 1; diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index f4cb930d..6069f5b9 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -401,7 +401,9 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) { } else { - if (unlink(fn)) { PFATAL("Unable to remove '%s'", fn); } + if (unlink(fn)) { /*PFATAL("Unable to remove '%s'", fn);*/ + + } } @@ -699,12 +701,11 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) { void destroy_queue(afl_state_t *afl) { - u32 i; + u32 i; + struct queue_entry *q; for (i = 0; i < afl->queued_items; i++) { - struct queue_entry *q; - q = afl->queue_buf[i]; ck_free(q->fname); ck_free(q->trace_mini); diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 6a0da6ab..c234fc42 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -60,6 +60,27 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon); +#ifdef __AFL_CODE_COVERAGE + if (unlikely(!fsrv->persistent_trace_bits)) { + + // On the first run, we allocate the persistent map to collect coverage. + fsrv->persistent_trace_bits = (u8 *)malloc(fsrv->map_size); + memset(fsrv->persistent_trace_bits, 0, fsrv->map_size); + + } + + for (u32 i = 0; i < fsrv->map_size; ++i) { + + if (fsrv->persistent_trace_bits[i] != 255 && fsrv->trace_bits[i]) { + + fsrv->persistent_trace_bits[i]++; + + } + + } + +#endif + /* If post_run() function is defined in custom mutator, the function will be called each time after AFL++ executes the target program. */ diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index fbe6d32a..dd684a19 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -286,6 +286,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_no_sync = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_NO_FASTRESUME", + + afl_environment_variable_len)) { + + afl->afl_env.afl_no_fastresume = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_CUSTOM_MUTATOR_ONLY", afl_environment_variable_len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 3a71e158..a20c46d0 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -76,7 +76,13 @@ char *get_fuzzing_state(afl_state_t *afl) { void write_setup_file(afl_state_t *afl, u32 argc, char **argv) { - u8 fn[PATH_MAX]; + u8 fn[PATH_MAX], fn2[PATH_MAX]; + + snprintf(fn2, PATH_MAX, "%s/target_hash", afl->out_dir); + FILE *f2 = create_ffile(fn2); + fprintf(f2, "%p\n", (void *)get_binary_hash(afl->fsrv.target_path)); + fclose(f2); + snprintf(fn, PATH_MAX, "%s/fuzzer_setup", afl->out_dir); FILE *f = create_ffile(fn); u32 i; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a7ddef6e..0ae12fc1 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -181,7 +181,7 @@ static void usage(u8 *argv0, int more_help) { "it.\n" " if using QEMU/FRIDA or the fuzzing target is " "compiled\n" - " for CmpLog then use '-c 0'. To disable Cmplog use '-c " + " for CmpLog then use '-c 0'. To disable CMPLOG use '-c " "-'.\n" " -l cmplog_opts - CmpLog configuration values (e.g. \"2ATR\"):\n" " 1=small files, 2=larger files (default), 3=all " @@ -335,6 +335,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_STATSD_PORT: change default statsd port (default: 8125)\n" "AFL_STATSD_TAGS_FLAVOR: set statsd tags format (default: disable tags)\n" " suported formats: dogstatsd, librato, signalfx, influxdb\n" + "AFL_NO_FASTRESUME: do not read or write a fast resume file\n" "AFL_NO_SYNC: disables all syncing\n" "AFL_SYNC_TIME: sync time between fuzzing instances (in minutes)\n" "AFL_FINAL_SYNC: sync a final time when exiting (will delay the exit!)\n" @@ -960,7 +961,11 @@ int main(int argc, char **argv_orig, char **envp) { } - if (afl->fsrv.mem_limit < 5) { FATAL("Dangerously low value of -m"); } + if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 5) { + + FATAL("Dangerously low value of -m"); + + } if (sizeof(rlim_t) == 4 && afl->fsrv.mem_limit > 2000) { @@ -1868,6 +1873,13 @@ int main(int argc, char **argv_orig, char **envp) { OKF("Using Frida Address Sanitizer Mode"); + if (afl->fsrv.mem_limit) { + + WARNF("in the Frida Address Sanitizer Mode we disable all memory limits"); + afl->fsrv.mem_limit = 0; + + } + fasan_check_afl_preload(afl_preload); setenv("ASAN_OPTIONS", "detect_leaks=false", 1); @@ -2101,13 +2113,80 @@ int main(int argc, char **argv_orig, char **envp) { } + setup_cmdline_file(afl, argv + optind); + check_binary(afl, argv[optind]); + + u64 prev_target_hash = 0; + s32 fast_resume = 0, fr_fd = -1; + + if (afl->in_place_resume && !afl->afl_env.afl_no_fastresume) { + + u8 fn[PATH_MAX], buf[32]; + snprintf(fn, PATH_MAX, "%s/target_hash", afl->out_dir); + fr_fd = open(fn, O_RDONLY); + if (fr_fd >= 0) { + + if (read(fr_fd, buf, 32) >= 16) { + + sscanf(buf, "%p", (void **)&prev_target_hash); + + } + + close(fr_fd); + + } + + } + write_setup_file(afl, argc, argv); - setup_cmdline_file(afl, argv + optind); + if (afl->in_place_resume && !afl->afl_env.afl_no_fastresume) { + + u64 target_hash = get_binary_hash(afl->fsrv.target_path); + + if (!target_hash || prev_target_hash != target_hash) { + + ACTF("Target binary is different, cannot perform FAST RESUME!"); + + } else { + + u8 fn[PATH_MAX]; + snprintf(fn, PATH_MAX, "%s/fastresume.bin", afl->out_dir); + if ((fr_fd = open(fn, O_RDONLY)) >= 0) { + + u8 ver_string[8]; + u64 *ver = (u64 *)ver_string; + u64 expect_ver = + afl->shm.cmplog_mode + (sizeof(struct queue_entry) << 1); + + if (read(fr_fd, ver_string, sizeof(ver_string)) != sizeof(ver_string)) + WARNF("Emtpy fastresume.bin, ignoring, cannot perform FAST RESUME"); + else if (expect_ver != *ver) + WARNF( + "Different AFL++ version or feature usage, cannot perform FAST " + "RESUME"); + else { + + OKF("Will perform FAST RESUME"); + fast_resume = 1; + + } + + } else { + + ACTF("fastresume.bin not found, cannot perform FAST RESUME!"); + + } + + // If the fast resume file is not valid we will be unable to start, so + // we remove the file but keep the file descriptor open. + unlink(fn); + + } + + } read_testcases(afl, NULL); - // read_foreign_testcases(afl, 1); for the moment dont do this - OKF("Loaded a total of %u seeds.", afl->queued_items); pivot_inputs(afl); @@ -2140,6 +2219,9 @@ int main(int argc, char **argv_orig, char **envp) { } + // read_foreign_testcases(afl, 1); for the moment dont do this + OKF("Loaded a total of %u seeds.", afl->queued_items); + /* If we don't have a file name chosen yet, use a safe default. */ if (!afl->fsrv.out_file) { @@ -2196,8 +2278,6 @@ int main(int argc, char **argv_orig, char **envp) { } - check_binary(afl, argv[optind]); - #ifdef AFL_PERSISTENT_RECORD if (unlikely(afl->fsrv.persistent_record)) { @@ -2416,7 +2496,7 @@ int main(int argc, char **argv_orig, char **envp) { } - OKF("Cmplog forkserver successfully started"); + OKF("CMPLOG forkserver successfully started"); } @@ -2454,29 +2534,102 @@ int main(int argc, char **argv_orig, char **envp) { dedup_extras(afl); if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); } - // after we have the correct bitmap size we can read the bitmap -B option - // and set the virgin maps - if (afl->in_bitmap) { + if (unlikely(fast_resume)) { - read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size); + u64 resume_start = get_cur_time_us(); + // if we get here then we should abort on errors + ck_read(fr_fd, afl->virgin_bits, afl->fsrv.map_size, "virgin_bits"); + ck_read(fr_fd, afl->virgin_tmout, afl->fsrv.map_size, "virgin_tmout"); + ck_read(fr_fd, afl->virgin_crash, afl->fsrv.map_size, "virgin_crash"); + ck_read(fr_fd, afl->var_bytes, afl->fsrv.map_size, "var_bytes"); - } else { + u8 res[1] = {0}; + u8 *o_start = (u8 *)&(afl->queue_buf[0]->colorized); + u8 *o_end = (u8 *)&(afl->queue_buf[0]->mother); + u32 r = 8 + afl->fsrv.map_size * 4; + u32 q_len = o_end - o_start; + u32 m_len = (afl->fsrv.map_size >> 3); + struct queue_entry *q; - memset(afl->virgin_bits, 255, map_size); + for (u32 i = 0; i < afl->queued_items; i++) { - } + q = afl->queue_buf[i]; + ck_read(fr_fd, (u8 *)&(q->colorized), q_len, "queue data"); + ck_read(fr_fd, res, 1, "check map"); + if (res[0]) { - memset(afl->virgin_tmout, 255, map_size); - memset(afl->virgin_crash, 255, map_size); + q->trace_mini = ck_alloc(m_len); + ck_read(fr_fd, q->trace_mini, m_len, "trace_mini"); + r += q_len + m_len + 1; + + } else { - if (likely(!afl->afl_env.afl_no_startup_calibration)) { + r += q_len + 1; - perform_dry_run(afl); + } + + afl->total_bitmap_size += q->bitmap_size; + ++afl->total_bitmap_entries; + update_bitmap_score(afl, q); + + if (q->was_fuzzed) { --afl->pending_not_fuzzed; } + + if (q->disabled) { + + if (!q->was_fuzzed) { --afl->pending_not_fuzzed; } + --afl->active_items; + + } + + if (q->var_behavior) { ++afl->queued_variable; } + if (q->favored) { + + ++afl->queued_favored; + if (!q->was_fuzzed) { ++afl->pending_favored; } + + } + + } + + u8 buf[4]; + if (read(fr_fd, buf, 3) > 0) { + + FATAL("invalid trailing data in fastresume.bin"); + + } + + OKF("Successfully loaded fastresume.bin (%u bytes)!", r); + close(fr_fd); + afl->reinit_table = 1; + update_calibration_time(afl, &resume_start); } else { - ACTF("skipping initial seed calibration due option override!"); - usleep(1000); + // after we have the correct bitmap size we can read the bitmap -B option + // and set the virgin maps + if (afl->in_bitmap) { + + read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size); + + } else { + + memset(afl->virgin_bits, 255, map_size); + + } + + memset(afl->virgin_tmout, 255, map_size); + memset(afl->virgin_crash, 255, map_size); + + if (likely(!afl->afl_env.afl_no_startup_calibration)) { + + perform_dry_run(afl); + + } else { + + ACTF("Skipping initial seed calibration due option override!"); + usleep(1000); + + } } @@ -2984,6 +3137,28 @@ stop_fuzzing: write_bitmap(afl); save_auto(afl); + #ifdef __AFL_CODE_COVERAGE + if (afl->fsrv.persistent_trace_bits) { + + char cfn[4096]; + snprintf(cfn, sizeof(cfn), "%s/covmap.dump", afl->out_dir); + + FILE *cov_fd; + if ((cov_fd = fopen(cfn, "w")) == NULL) { + + PFATAL("could not create '%s'", cfn); + + } + + // Write the real map size, as the map size must exactly match the pointer + // map in length. + fwrite(afl->fsrv.persistent_trace_bits, 1, afl->fsrv.real_map_size, cov_fd); + fclose(cov_fd); + + } + + #endif + if (afl->pizza_is_served) { SAYF(CURSOR_SHOW cLRD "\n\n+++ Baking aborted %s +++\n" cRST, @@ -3067,6 +3242,68 @@ stop_fuzzing: fclose(afl->fsrv.det_plot_file); #endif + if (!afl->afl_env.afl_no_fastresume) { + + /* create fastresume.bin */ + u8 fr[PATH_MAX]; + snprintf(fr, PATH_MAX, "%s/fastresume.bin", afl->out_dir); + ACTF("Writing %s ...", fr); + if ((fr_fd = open(fr, O_WRONLY | O_TRUNC | O_CREAT, DEFAULT_PERMISSION)) >= + 0) { + + u8 ver_string[8]; + u32 w = 0; + u64 *ver = (u64 *)ver_string; + *ver = afl->shm.cmplog_mode + (sizeof(struct queue_entry) << 1); + + w += write(fr_fd, ver_string, sizeof(ver_string)); + + w += write(fr_fd, afl->virgin_bits, afl->fsrv.map_size); + w += write(fr_fd, afl->virgin_tmout, afl->fsrv.map_size); + w += write(fr_fd, afl->virgin_crash, afl->fsrv.map_size); + w += write(fr_fd, afl->var_bytes, afl->fsrv.map_size); + + u8 on[1] = {1}, off[1] = {0}; + u8 *o_start = (u8 *)&(afl->queue_buf[0]->colorized); + u8 *o_end = (u8 *)&(afl->queue_buf[0]->mother); + u32 q_len = o_end - o_start; + u32 m_len = (afl->fsrv.map_size >> 3); + struct queue_entry *q; + + afl->pending_not_fuzzed = afl->queued_items; + afl->active_items = afl->queued_items; + + for (u32 i = 0; i < afl->queued_items; i++) { + + q = afl->queue_buf[i]; + ck_write(fr_fd, (u8 *)&(q->colorized), q_len, "queue data"); + if (!q->trace_mini) { + + ck_write(fr_fd, off, 1, "no_mini"); + w += q_len + 1; + + } else { + + ck_write(fr_fd, on, 1, "yes_mini"); + ck_write(fr_fd, q->trace_mini, m_len, "trace_mini"); + w += q_len + m_len + 1; + + } + + } + + close(fr_fd); + afl->var_byte_count = count_bytes(afl, afl->var_bytes); + OKF("Written fastresume.bin with %u bytes!", w); + + } else { + + WARNF("Could not create fastresume.bin"); + + } + + } + destroy_queue(afl); destroy_extras(afl); destroy_custom_mutators(afl); diff --git a/src/afl-performance.c b/src/afl-performance.c index e8ece6b5..b824fd35 100644 --- a/src/afl-performance.c +++ b/src/afl-performance.c @@ -99,11 +99,13 @@ inline u64 hash64(u8 *key, u32 len, u64 seed) { u64 get_binary_hash(u8 *fn) { + if (!fn) { return 0; } int fd = open(fn, O_RDONLY); if (fd < 0) { PFATAL("Unable to open '%s'", fn); } struct stat st; if (fstat(fd, &st) < 0) { PFATAL("Unable to fstat '%s'", fn); } u32 f_len = st.st_size; + if (!f_len) { return 0; } u8 *f_data = mmap(0, f_len, PROT_READ, MAP_PRIVATE, fd, 0); if (f_data == MAP_FAILED) { PFATAL("Unable to mmap file '%s'", fn); } close(fd); |