From be96253f5293a0446aae8b2f1795119456c0d5d5 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 31 Mar 2023 11:02:27 +0200 Subject: nits --- src/afl-fuzz-bitmap.c | 10 +++++++--- src/afl-fuzz-one.c | 6 +++--- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index d9c792d1..556bb5d1 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -465,7 +465,8 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { u8 fn[PATH_MAX]; u8 *queue_fn = ""; - u8 new_bits = 0, keeping = 0, res, classified = 0, is_timeout = 0; + u8 new_bits = 0, keeping = 0, res, classified = 0, is_timeout = 0, + need_hash = 1; s32 fd; u64 cksum = 0; @@ -477,6 +478,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { classify_counts(&afl->fsrv); classified = 1; + need_hash = 0; cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); @@ -499,6 +501,8 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { new_bits = has_new_bits_unclassified(afl, afl->virgin_bits); + if (unlikely(new_bits)) { classified = 1; } + } if (likely(!new_bits)) { @@ -565,12 +569,12 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { } - if (unlikely(!classified && new_bits)) { + if (unlikely(need_hash && new_bits)) { /* due to classify counts we have to recalculate the checksum */ afl->queue_top->exec_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); - classified = 1; + need_hash = 0; } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 070669c5..eec5e4b5 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2071,7 +2071,7 @@ havoc_stage: afl->stage_short = "havoc"; afl->stage_max = ((doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) * perf_score / afl->havoc_div) >> - 7; + 8; } else { @@ -2080,7 +2080,7 @@ havoc_stage: snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "splice %u", splice_cycle); afl->stage_name = afl->stage_name_buf; afl->stage_short = "splice"; - afl->stage_max = (SPLICE_HAVOC * perf_score / afl->havoc_div) >> 7; + afl->stage_max = (SPLICE_HAVOC * perf_score / afl->havoc_div) >> 8; } @@ -4640,7 +4640,7 @@ pacemaker_fuzzing: MOpt_globals.splice_stageformat, splice_cycle); afl->stage_name = afl->stage_name_buf; afl->stage_short = MOpt_globals.splice_stagenameshort; - afl->stage_max = (SPLICE_HAVOC * perf_score / afl->havoc_div) >> 7; + afl->stage_max = (SPLICE_HAVOC * perf_score / afl->havoc_div) >> 8; } -- cgit 1.4.1 From 4d02d8e43dd9b413ed819e27bb012e16022d85f6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 2 Apr 2023 11:52:36 +0200 Subject: fix buffer overflow in pizza mode :( --- src/afl-fuzz-stats.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 25ebe987..88844322 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -753,20 +753,20 @@ void show_stats_normal(afl_state_t *afl) { #ifdef __linux__ if (afl->fsrv.nyx_mode) { - sprintf(banner + banner_pad, - "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx", - afl->crash_mode ? cPIN "peruvian were-rabbit" - : cYEL "american fuzzy lop", - si, afl->use_banner, afl->power_name); + snprintf(banner + banner_pad, sizeof(banner) - banner_pad, + "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx", + afl->crash_mode ? cPIN "peruvian were-rabbit" + : cYEL "american fuzzy lop", + si, afl->use_banner, afl->power_name); } else { #endif - sprintf(banner + banner_pad, - "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]", - afl->crash_mode ? cPIN "peruvian were-rabbit" - : cYEL "american fuzzy lop", - si, afl->use_banner, afl->power_name); + snprintf(banner + banner_pad, sizeof(banner) - banner_pad, + "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]", + afl->crash_mode ? cPIN "peruvian were-rabbit" + : cYEL "american fuzzy lop", + si, afl->use_banner, afl->power_name); #ifdef __linux__ @@ -1557,20 +1557,22 @@ void show_stats_pizza(afl_state_t *afl) { #ifdef __linux__ if (afl->fsrv.nyx_mode) { - sprintf(banner + banner_pad, - "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx", - afl->crash_mode ? cPIN "Mozzarbella Pizzeria table booking system" - : cYEL "Mozzarbella Pizzeria management system", - si, afl->use_banner, afl->power_name); + snprintf(banner + banner_pad, sizeof(banner) - banner_pad, + "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx", + afl->crash_mode ? cPIN + "Mozzarbella Pizzeria table booking system" + : cYEL "Mozzarbella Pizzeria management system", + si, afl->use_banner, afl->power_name); } else { #endif - sprintf(banner + banner_pad, - "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]", - afl->crash_mode ? cPIN "Mozzarbella Pizzeria table booking system" - : cYEL "Mozzarbella Pizzeria management system", - si, afl->use_banner, afl->power_name); + snprintf(banner + banner_pad, sizeof(banner) - banner_pad, + "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]", + afl->crash_mode ? cPIN + "Mozzarbella Pizzeria table booking system" + : cYEL "Mozzarbella Pizzeria management system", + si, afl->use_banner, afl->power_name); #ifdef __linux__ -- cgit 1.4.1 From e46e0bce44f0799731f5e7724ba3dfacafd4c41a Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 2 Apr 2023 12:03:45 +0200 Subject: allow pizza mode to be disabled --- docs/Changelog.md | 3 +++ docs/env_variables.md | 2 +- include/afl-fuzz.h | 6 ++++-- src/afl-fuzz-state.c | 10 +++++++++- 4 files changed, 17 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index 3c06a785..fbf50137 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,9 @@ - added `AFL_NO_WARN_INSTABILITY` - added `AFL_FRIDA_STATS_INTERVAL` - added time_wo_finds to fuzzer_stats + - fixed a crash in pizza (1st april easter egg) mode. Sorry for + everyone who was affected! + - allow pizza mode to be disabled when AFL_PIZZA_MODE is set to -1 - afl-cc: - add CFI sanitizer variant to gcc targets - llvm 16 support (thanks to @devnexen!) diff --git a/docs/env_variables.md b/docs/env_variables.md index c9dc1bbd..a6a0ae44 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -581,7 +581,7 @@ checks or alter some of the more exotic semantics of the tool: constructors in your target, you can set `AFL_EARLY_FORKSERVER`. Note that this is not a compile time option but a runtime option :-) - - Set `AFL_PIZZA_MODE` to 1 to enable the April 1st stats menu, set to 0 + - Set `AFL_PIZZA_MODE` to 1 to enable the April 1st stats menu, set to -1 to disable although it is 1st of April. - If you need a specific interval to update fuzzer_stats file, you can diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 58d02af5..5fd393dd 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -398,8 +398,8 @@ typedef struct afl_env_vars { afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, afl_exit_on_seed_issues, afl_try_affinity, afl_ignore_problems, - afl_keep_timeouts, afl_pizza_mode, afl_no_crash_readme, - afl_ignore_timeouts, afl_no_startup_calibration, afl_no_warn_instability; + afl_keep_timeouts, afl_no_crash_readme, afl_ignore_timeouts, + afl_no_startup_calibration, afl_no_warn_instability; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, @@ -408,6 +408,8 @@ typedef struct afl_env_vars { *afl_testcache_entries, *afl_child_kill_signal, *afl_fsrv_kill_signal, *afl_target_env, *afl_persistent_record, *afl_exit_on_time; + s32 afl_pizza_mode; + } afl_env_vars_t; struct afl_pass_stat { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index f9aa5cfe..46b67def 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -648,7 +648,15 @@ void read_afl_environment(afl_state_t *afl, char **envp) { } - if (afl->afl_env.afl_pizza_mode) { afl->pizza_is_served = 1; } + if (afl->afl_env.afl_pizza_mode > 0) { + + afl->pizza_is_served = 1; + + } else if (afl->afl_env.afl_pizza_mode < 0) { + + OKF("Pizza easter egg mode is now disabled."); + + } if (issue_detected) { sleep(2); } -- cgit 1.4.1 From 319b2e8e6f64bd35c5395c8a9e5053f25875a86d Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 2 Apr 2023 12:08:54 +0200 Subject: fix ui layout with slow targets in pizza mode --- src/afl-fuzz-stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 88844322..07157bf7 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1803,10 +1803,10 @@ void show_stats_pizza(afl_state_t *afl) { /* Show a warning about slow execution. */ - if (afl->stats_avg_exec < 100) { + if (afl->stats_avg_exec < 20) { sprintf(tmp, "%s/sec (%s)", u_stringify_float(IB(0), afl->stats_avg_exec), - afl->stats_avg_exec < 20 ? "zzzz..." : "Gennarino is at it again!"); + "zzzz..."); SAYF(bV bSTOP " pizza making speed : " cLRD "%-22s ", -- cgit 1.4.1 From 36127fb1970746f53fec44f9394061f57a4e94c3 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 5 Apr 2023 12:59:20 +0200 Subject: add -z switch --- docs/Changelog.md | 1 + include/afl-fuzz.h | 3 ++- src/afl-fuzz-queue.c | 7 ++++++- src/afl-fuzz.c | 5 +++++ 4 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index fbf50137..8127e594 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -12,6 +12,7 @@ - fixed a crash in pizza (1st april easter egg) mode. Sorry for everyone who was affected! - allow pizza mode to be disabled when AFL_PIZZA_MODE is set to -1 + - add -z switch to prefer new coverage findings in seed selection - afl-cc: - add CFI sanitizer variant to gcc targets - llvm 16 support (thanks to @devnexen!) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 5fd393dd..7ff3315b 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -501,7 +501,8 @@ typedef struct afl_state { custom_splice_optout, /* Custom mutator no splice buffer */ is_main_node, /* if this is the main node */ is_secondary_node, /* if this is a secondary instance */ - pizza_is_served; /* pizza mode */ + pizza_is_served, /* pizza mode */ + prefer_new; /* prefer new queue entries */ u32 stats_update_freq; /* Stats update frequency (execs) */ diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 40184645..1cdc8b54 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -74,9 +74,14 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q, if (likely(afl->schedule < RARE)) { weight *= (avg_exec_us / q->exec_us); } weight *= (log(q->bitmap_size) / avg_bitmap_size); weight *= (1 + (q->tc_ref / avg_top_size)); - if (unlikely(weight < 1.0)) { weight = 1.0; } + if (unlikely(weight < 0.1)) { weight = 0.1; } if (unlikely(q->favored)) { weight *= 5; } if (unlikely(!q->was_fuzzed)) { weight *= 2; } + if (unlikely(afl->prefer_new)) { + + weight *= (2.0 * (q->id / (afl->queued_items - 1))); + + } return weight; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 3380fd90..0f01360e 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -132,6 +132,7 @@ static void usage(u8 *argv0, int more_help) { " fast(default), explore, exploit, seek, rare, mmopt, " "coe, lin\n" " quad -- see docs/FAQ.md for more information\n" + " -z - prefer new coverage findings when fuzzing\n" " -f file - location read by the fuzzed program (default: stdin " "or @@)\n" " -t msec - timeout for each run (auto-scaled, default %u ms). " @@ -569,6 +570,10 @@ int main(int argc, char **argv_orig, char **envp) { afl->max_length = atoi(optarg); break; + case 'z': + afl->prefer_new = 1; + break; + case 'Z': afl->old_seed_selection = 1; break; -- cgit 1.4.1 From dba93705a79fb859ce0ede606f79dd4ed203725b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 5 Apr 2023 13:07:22 +0200 Subject: better new weighting --- src/afl-fuzz-queue.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 1cdc8b54..3335e869 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -74,15 +74,17 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q, if (likely(afl->schedule < RARE)) { weight *= (avg_exec_us / q->exec_us); } weight *= (log(q->bitmap_size) / avg_bitmap_size); weight *= (1 + (q->tc_ref / avg_top_size)); - if (unlikely(weight < 0.1)) { weight = 0.1; } - if (unlikely(q->favored)) { weight *= 5; } - if (unlikely(!q->was_fuzzed)) { weight *= 2; } + if (unlikely(afl->prefer_new)) { - weight *= (2.0 * (q->id / (afl->queued_items - 1))); + weight *= (2.0 * ((1 + q->id) / afl->queued_items)); } + if (unlikely(weight < 0.1)) { weight = 0.1; } + if (unlikely(q->favored)) { weight *= 5; } + if (unlikely(!q->was_fuzzed)) { weight *= 2; } + return weight; } -- cgit 1.4.1 From d67ee1777859b55b1660cef15fc09219fb165140 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 5 Apr 2023 13:30:06 +0200 Subject: fix --- src/afl-fuzz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 0f01360e..c7eb985c 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -557,7 +557,7 @@ int main(int argc, char **argv_orig, char **envp) { while ( (opt = getopt( argc, argv, - "+Ab:B:c:CdDe:E:hi:I:f:F:g:G:l:L:m:M:nNOo:p:RQs:S:t:T:UV:WXx:YZ")) > + "+Ab:B:c:CdDe:E:hi:I:f:F:g:G:l:L:m:M:nNOo:p:RQs:S:t:T:UV:WXx:YzZ")) > 0) { switch (opt) { -- cgit 1.4.1 From f9851dbfbbfbc013172f500099b5f4dc572c508b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 8 Apr 2023 13:00:57 +0200 Subject: hopefully better -z algorithm --- src/afl-fuzz-queue.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 3335e869..6fc3c743 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -75,12 +75,6 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q, weight *= (log(q->bitmap_size) / avg_bitmap_size); weight *= (1 + (q->tc_ref / avg_top_size)); - if (unlikely(afl->prefer_new)) { - - weight *= (2.0 * ((1 + q->id) / afl->queued_items)); - - } - if (unlikely(weight < 0.1)) { weight = 0.1; } if (unlikely(q->favored)) { weight *= 5; } if (unlikely(!q->was_fuzzed)) { weight *= 2; } @@ -155,6 +149,26 @@ void create_alias_table(afl_state_t *afl) { } + if (unlikely(afl->prefer_new) && afl->queued_discovered) { + + double avg_weight = sum / active; + + for (i = n - afl->queued_discovered; i < n; i++) { + + struct queue_entry *q = afl->queue_buf[i]; + + if (likely(!q->disabled) && q->weight > avg_weight) { + + double prev_weight = q->weight; + q->weight *= (2.0 * (i / n)); + sum += (q->weight - prev_weight); + + } + + } + + } + for (i = 0; i < n; i++) { // weight is always 0 for disabled entries -- cgit 1.4.1 From 75d7a094691550afe86519a1d669def0d698b5ce Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 8 Apr 2023 13:48:07 +0200 Subject: show custom mutator name in UI --- docs/Changelog.md | 1 + src/afl-fuzz-mutators.c | 16 ++++++++++++---- src/afl-fuzz-one.c | 1 + src/afl-fuzz-python.c | 13 ++++++++++++- 4 files changed, 26 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index 8127e594..40c328ec 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -13,6 +13,7 @@ everyone who was affected! - allow pizza mode to be disabled when AFL_PIZZA_MODE is set to -1 - add -z switch to prefer new coverage findings in seed selection + - print name of custom mutator in UI - afl-cc: - add CFI sanitizer variant to gcc targets - llvm 16 support (thanks to @devnexen!) diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 9ea46e7a..64dbe7c6 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -179,11 +179,19 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { void *dh; struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator)); - mutator->name = fn; - if (memchr(fn, '/', strlen(fn))) - mutator->name_short = strrchr(fn, '/') + 1; - else + if (memchr(fn, '/', strlen(fn))) { + + mutator->name_short = strdup(strrchr(fn, '/') + 1); + + } else { + mutator->name_short = strdup(fn); + + } + + if (strlen(mutator->name_short) > 22) { mutator->name_short[21] = 0; } + + mutator->name = fn; ACTF("Loading custom mutator library from '%s'...", fn); dh = dlopen(fn, RTLD_NOW); diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index eec5e4b5..ee562f96 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1931,6 +1931,7 @@ custom_mutator_stage: if (el->afl_custom_fuzz) { afl->current_custom_fuzz = el; + afl->stage_name = el->name_short; if (el->afl_custom_fuzz_count) { diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 2799268b..673e5a6c 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -414,10 +414,21 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl, struct custom_mutator *mutator; mutator = ck_alloc(sizeof(struct custom_mutator)); - mutator->name = module_name; ACTF("Loading Python mutator library from '%s'...", module_name); + if (memchr(module_name, '/', strlen(module_name))) { + + mutator->name_short = strdup(strrchr(module_name, '/') + 1); + + } else { + + mutator->name_short = strdup(module_name); + + } + + if (strlen(mutator->name_short) > 22) { mutator->name_short[21] = 0; } + py_mutator_t *py_mutator; py_mutator = init_py_module(afl, module_name); mutator->data = py_mutator; -- cgit 1.4.1 From 0eace0212e35e9ed6ba5d084f787402406fa440c Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Sat, 8 Apr 2023 17:19:09 +0200 Subject: afl-cc: Avoid casts of string literals to char*, in definition of __AFL_INIT() etc. With the right -W options, compilers may complain about the cast of string literals (for PERSIST_SIG and DEFER_SIG) to (char*), and they're right to do so, because string literals are constant. Since some projects enable -Werror, this can lead to a broken build with afl-cc. Let's simply cast to (const char *), which preserves the constness of the string literal. --- src/afl-cc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/afl-cc.c b/src/afl-cc.c index 7b059d40..35b90a5c 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1171,8 +1171,8 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)=" - "({ static volatile char *_B __attribute__((used,unused)); " - " _B = (char*)\"" PERSIST_SIG + "({ static volatile const char *_B __attribute__((used,unused)); " + " _B = (const char*)\"" PERSIST_SIG "\"; " "extern int __afl_connected;" #ifdef __APPLE__ @@ -1187,8 +1187,8 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = "-D__AFL_INIT()=" - "do { static volatile char *_A __attribute__((used,unused)); " - " _A = (char*)\"" DEFER_SIG + "do { static volatile const char *_A __attribute__((used,unused)); " + " _A = (const char*)\"" DEFER_SIG "\"; " #ifdef __APPLE__ "__attribute__((visibility(\"default\"))) " -- cgit 1.4.1 From 0782ed38414bed37168feafc971fd102b8294510 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 9 Apr 2023 10:33:39 +0200 Subject: remove pointer to removed doc --- src/afl-fuzz.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index c7eb985c..a0c322da 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -166,7 +166,6 @@ static void usage(u8 *argv0, int more_help) { " pacemaker mode (minutes of no new finds). 0 = " "immediately,\n" " -1 = immediately and together with normal mutation.\n" - " See docs/README.MOpt.md\n" " -c program - enable CmpLog by specifying a binary compiled for " "it.\n" " if using QEMU/FRIDA or the fuzzing target is " -- cgit 1.4.1 From 9e3e1a5512acd44020430f24c9ec1260aeeda285 Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Mon, 10 Apr 2023 12:22:42 +0200 Subject: afl-cc: Don't offer __AFL_INIT() etc. in GCC/CLANG modes instrumentation/README.persistent_mode.md documents in the section about deferred forkserver initialization: > With the location selected, add this code in the appropriate spot: > > ```c > #ifdef __AFL_HAVE_MANUAL_CONTROL > __AFL_INIT(); > #endif > ``` > > You don't need the #ifdef guards, but including them ensures that the program > will keep working normally when compiled with a tool other than afl-clang-fast/ > afl-clang-lto/afl-gcc-fast. > > Finally, recompile the program with afl-clang-fast/afl-clang-lto/afl-gcc-fast > (afl-gcc or afl-clang will *not* generate a deferred-initialization binary) - > and you should be all set! This strongly implies that you can compile a program that uses __AFL_INIT() under an `#ifdef __AFL_HAVE_MANUAL_CONTROL` guard with afl-gcc/-clang. However, this currently fails: $ cat example.c #include int main(void) { #ifdef __AFL_HAVE_MANUAL_CONTROL __AFL_INIT(); #endif puts("Hello"); } $ afl-gcc example.c -o example afl-cc++4.06a by Michal Zalewski, Laszlo Szekeres, Marc Heuse - mode: GCC-GCC [!] WARNING: You are using outdated instrumentation, install LLVM and/or gcc-plugin and use afl-clang-fast/afl-clang-lto/afl-gcc-fast instead! afl-as++4.06a by Michal Zalewski [+] Instrumented 1 locations (64-bit, non-hardened mode, ratio 100%). /usr/bin/ld: /tmp/ccuJHcpt.o: in function `main': /home/jn/dev/fuzz/AFLplusplus/example.c:5: undefined reference to `__afl_manual_init' collect2: error: ld returned 1 exit status The issue here is an inconsistency in afl-gcc (i.e. afl-cc operating in GCC mode): - afl-cc defines __AFL_HAVE_MANUAL_CONTROL and __AFL_INIT unconditionally - __AFL_INIT relies on __afl_manual_init, which is defined in afl-compiler-rt.o - afl-cc doesn't link afl-compiler-rt in GCC or CLANG mode Since afl-gcc/-clang is documented as not supporting deferred forkserver initialization, this patch omits the definitions of __AFL_HAVE_MANUAL_CONTROL and related macros in GCC/CLANG mode. This restores the ability to compile a deferred-forkserver program under afl-gcc, if it can also be compiled under gcc. [ In case someone reads this an feels adventurous enough (as I did) to think about enabling deferred forkserver under afl-gcc: Whether the deferred forkserver actually works can be verified by placing a usleep(100000) or similar at the start of main (before __AFL_INIT()), and watching the execution speed. It doesn't work. ] --- src/afl-cc.c | 102 +++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/afl-cc.c b/src/afl-cc.c index 35b90a5c..7f15ad76 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1101,37 +1101,45 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!have_c) cc_params[cc_par_cnt++] = "-lrt"; #endif - cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; - /* When the user tries to use persistent or deferred forkserver modes by - appending a single line to the program, we want to reliably inject a - signature into the binary (to be picked up by afl-fuzz) and we want - to call a function from the runtime .o file. This is unnecessarily - painful for three reasons: + /* As documented in instrumentation/README.persistent_mode.md, deferred + forkserver initialization and persistent mode are not available in afl-gcc + and afl-clang. */ + if (compiler_mode != GCC && compiler_mode != CLANG) { - 1) We need to convince the compiler not to optimize out the signature. - This is done with __attribute__((used)). + cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; - 2) We need to convince the linker, when called with -Wl,--gc-sections, - not to do the same. This is done by forcing an assignment to a - 'volatile' pointer. + /* When the user tries to use persistent or deferred forkserver modes by + appending a single line to the program, we want to reliably inject a + signature into the binary (to be picked up by afl-fuzz) and we want + to call a function from the runtime .o file. This is unnecessarily + painful for three reasons: - 3) We need to declare __afl_persistent_loop() in the global namespace, - but doing this within a method in a class is hard - :: and extern "C" - are forbidden and __attribute__((alias(...))) doesn't work. Hence the - __asm__ aliasing trick. + 1) We need to convince the compiler not to optimize out the signature. + This is done with __attribute__((used)). - */ + 2) We need to convince the linker, when called with -Wl,--gc-sections, + not to do the same. This is done by forcing an assignment to a + 'volatile' pointer. - cc_params[cc_par_cnt++] = - "-D__AFL_FUZZ_INIT()=" - "int __afl_sharedmem_fuzzing = 1;" - "extern unsigned int *__afl_fuzz_len;" - "extern unsigned char *__afl_fuzz_ptr;" - "unsigned char __afl_fuzz_alt[1048576];" - "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;"; + 3) We need to declare __afl_persistent_loop() in the global namespace, + but doing this within a method in a class is hard - :: and extern "C" + are forbidden and __attribute__((alias(...))) doesn't work. Hence the + __asm__ aliasing trick. + + */ + + cc_params[cc_par_cnt++] = + "-D__AFL_FUZZ_INIT()=" + "int __afl_sharedmem_fuzzing = 1;" + "extern unsigned int *__afl_fuzz_len;" + "extern unsigned char *__afl_fuzz_ptr;" + "unsigned char __afl_fuzz_alt[1048576];" + "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;"; + + } if (plusplus_mode) { @@ -1169,35 +1177,39 @@ static void edit_params(u32 argc, char **argv, char **envp) { "(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff " "? 0 : *__afl_fuzz_len)"; - cc_params[cc_par_cnt++] = - "-D__AFL_LOOP(_A)=" - "({ static volatile const char *_B __attribute__((used,unused)); " - " _B = (const char*)\"" PERSIST_SIG - "\"; " - "extern int __afl_connected;" + if (compiler_mode != GCC && compiler_mode != CLANG) { + + cc_params[cc_par_cnt++] = + "-D__AFL_LOOP(_A)=" + "({ static volatile const char *_B __attribute__((used,unused)); " + " _B = (const char*)\"" PERSIST_SIG + "\"; " + "extern int __afl_connected;" #ifdef __APPLE__ - "__attribute__((visibility(\"default\"))) " - "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); " + "__attribute__((visibility(\"default\"))) " + "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); " #else - "__attribute__((visibility(\"default\"))) " - "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); " + "__attribute__((visibility(\"default\"))) " + "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); " #endif /* ^__APPLE__ */ - // if afl is connected, we run _A times, else once. - "_L(__afl_connected ? _A : 1); })"; + // if afl is connected, we run _A times, else once. + "_L(__afl_connected ? _A : 1); })"; - cc_params[cc_par_cnt++] = - "-D__AFL_INIT()=" - "do { static volatile const char *_A __attribute__((used,unused)); " - " _A = (const char*)\"" DEFER_SIG - "\"; " + cc_params[cc_par_cnt++] = + "-D__AFL_INIT()=" + "do { static volatile const char *_A __attribute__((used,unused)); " + " _A = (const char*)\"" DEFER_SIG + "\"; " #ifdef __APPLE__ - "__attribute__((visibility(\"default\"))) " - "void _I(void) __asm__(\"___afl_manual_init\"); " + "__attribute__((visibility(\"default\"))) " + "void _I(void) __asm__(\"___afl_manual_init\"); " #else - "__attribute__((visibility(\"default\"))) " - "void _I(void) __asm__(\"__afl_manual_init\"); " + "__attribute__((visibility(\"default\"))) " + "void _I(void) __asm__(\"__afl_manual_init\"); " #endif /* ^__APPLE__ */ - "_I(); } while (0)"; + "_I(); } while (0)"; + + } if (x_set) { -- cgit 1.4.1 From 6cc8d607fb24e060591ece4b42d83fc06de68fc6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 13 Apr 2023 11:44:39 +0200 Subject: remove -z option, use -p mmopt instead --- GNUmakefile | 2 +- docs/Changelog.md | 2 +- include/afl-fuzz.h | 3 +-- instrumentation/SanitizerCoverageLTO.so.cc | 2 +- instrumentation/SanitizerCoveragePCGUARD.so.cc | 2 +- src/afl-fuzz-queue.c | 14 ++++---------- src/afl-fuzz.c | 7 +------ 7 files changed, 10 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/GNUmakefile b/GNUmakefile index 208e965b..85f164f5 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -546,7 +546,7 @@ ifndef AFL_NO_X86 test_build: afl-cc afl-gcc afl-as afl-showmap @echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..." @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c $(LDFLAGS) -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) - - ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -o .test-instr0 ./test-instr < /dev/null + -ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -q -m none -o .test-instr0 ./test-instr < /dev/null -echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr @rm -f test-instr @cmp -s .test-instr0 .test-instr1; DR="$$?"; rm -f .test-instr0 .test-instr1; if [ "$$DR" = "0" ]; then echo; echo "Oops, the instrumentation of afl-cc does not seem to be behaving correctly!"; echo; echo "Please post to https://github.com/AFLplusplus/AFLplusplus/issues to troubleshoot the issue."; echo; exit 1; fi diff --git a/docs/Changelog.md b/docs/Changelog.md index 736deb30..501300b1 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -12,7 +12,7 @@ - fixed a crash in pizza (1st april easter egg) mode. Sorry for everyone who was affected! - allow pizza mode to be disabled when AFL_PIZZA_MODE is set to -1 - - add -z switch to prefer new coverage findings in seed selection + - option `-p mmopt` now also selects new queue items more often - print name of custom mutator in UI - afl-cc: - add CFI sanitizer variant to gcc targets diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 7ff3315b..5fd393dd 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -501,8 +501,7 @@ typedef struct afl_state { custom_splice_optout, /* Custom mutator no splice buffer */ is_main_node, /* if this is the main node */ is_secondary_node, /* if this is a secondary instance */ - pizza_is_served, /* pizza mode */ - prefer_new; /* prefer new queue entries */ + pizza_is_served; /* pizza mode */ u32 stats_update_freq; /* Stats update frequency (execs) */ diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 5603c455..e41f19b6 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -18,7 +18,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #if LLVM_VERSION_MAJOR < 17 -#include "llvm/ADT/Triple.h" + #include "llvm/ADT/Triple.h" #endif #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/PostDominators.h" diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 5f23698b..85b1ddd5 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -14,7 +14,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #if LLVM_VERSION_MAJOR < 17 -#include "llvm/ADT/Triple.h" + #include "llvm/ADT/Triple.h" #endif #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/PostDominators.h" diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 6fc3c743..8ad7cd97 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -149,21 +149,15 @@ void create_alias_table(afl_state_t *afl) { } - if (unlikely(afl->prefer_new) && afl->queued_discovered) { + if (unlikely(afl->schedule == MMOPT) && afl->queued_discovered) { - double avg_weight = sum / active; + u32 cnt = afl->queued_discovered >= 5 ? 5 : afl->queued_discovered; - for (i = n - afl->queued_discovered; i < n; i++) { + for (i = n - cnt; i < n; i++) { struct queue_entry *q = afl->queue_buf[i]; - if (likely(!q->disabled) && q->weight > avg_weight) { - - double prev_weight = q->weight; - q->weight *= (2.0 * (i / n)); - sum += (q->weight - prev_weight); - - } + if (likely(!q->disabled)) { q->weight *= 2.0; } } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a0c322da..5ba54d0b 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -132,7 +132,6 @@ static void usage(u8 *argv0, int more_help) { " fast(default), explore, exploit, seek, rare, mmopt, " "coe, lin\n" " quad -- see docs/FAQ.md for more information\n" - " -z - prefer new coverage findings when fuzzing\n" " -f file - location read by the fuzzed program (default: stdin " "or @@)\n" " -t msec - timeout for each run (auto-scaled, default %u ms). " @@ -556,7 +555,7 @@ int main(int argc, char **argv_orig, char **envp) { while ( (opt = getopt( argc, argv, - "+Ab:B:c:CdDe:E:hi:I:f:F:g:G:l:L:m:M:nNOo:p:RQs:S:t:T:UV:WXx:YzZ")) > + "+Ab:B:c:CdDe:E:hi:I:f:F:g:G:l:L:m:M:nNOo:p:RQs:S:t:T:UV:WXx:YZ")) > 0) { switch (opt) { @@ -569,10 +568,6 @@ int main(int argc, char **argv_orig, char **envp) { afl->max_length = atoi(optarg); break; - case 'z': - afl->prefer_new = 1; - break; - case 'Z': afl->old_seed_selection = 1; break; -- cgit 1.4.1 From f756734ad2782c3ed56feadb4b7b23fc82a7a968 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 13 Apr 2023 12:07:27 +0200 Subject: fix attempt at post_process implementation --- docs/Changelog.md | 1 + docs/custom_mutators.md | 9 +++++++-- include/afl-fuzz.h | 9 +++++++-- src/afl-fuzz-python.c | 49 +++++++++---------------------------------------- src/afl-fuzz-run.c | 7 ++++++- 5 files changed, 30 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index 501300b1..9436fc9f 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -13,6 +13,7 @@ everyone who was affected! - allow pizza mode to be disabled when AFL_PIZZA_MODE is set to -1 - option `-p mmopt` now also selects new queue items more often + - fix bug in post_process custom mutator implementation - print name of custom mutator in UI - afl-cc: - add CFI sanitizer variant to gcc targets diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 82131c92..a1de479e 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -118,7 +118,7 @@ def deinit(): # optional for Python ### Custom Mutation -- `init`: +- `init` (optional in Python): This method is called when AFL++ starts up and is used to seed RNG and set up buffers and state. @@ -184,6 +184,11 @@ def deinit(): # optional for Python to the target, e.g. if it is too short, too corrupted, etc. If so, return a NULL buffer and zero length (or a 0 length string in Python). + NOTE: Do not make any random changes to the data in this function! + + PERFORMANCE for C/C++: If possible make the changes in-place (so modify + the `*data` directly, and return it as `*outbuf = data`. + - `fuzz_send` (optional): This method can be used if you want to send data to the target yourself, @@ -202,7 +207,7 @@ def deinit(): # optional for Python discovered if compiled with INTROSPECTION. The custom mutator can then return a string (const char *) that reports the exact mutations used. -- `deinit`: +- `deinit` (optional in Python): The last method to be called, deinitializing the state. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 5fd393dd..8b6502b4 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -885,14 +885,19 @@ struct custom_mutator { * A post-processing function to use right before AFL writes the test case to * disk in order to execute the target. * - * (Optional) If this functionality is not needed, simply don't define this + * NOTE: Do not do any random changes to the data in this function! + * + * PERFORMANCE: If you can modify the data in-place you will have a better + * performance. Modify *data and set `*out_buf = data`. + * + * (Optional) If this functionality is not needed, simply do not define this * function. * * @param[in] data pointer returned in afl_custom_init by this custom mutator * @param[in] buf Buffer containing the test case to be executed * @param[in] buf_size Size of the test case * @param[out] out_buf Pointer to the buffer storing the test case after - * processing. External library should allocate memory for out_buf. + * processing. The external library should allocate memory for out_buf. * It can chose to alter buf in-place, if the space is large enough. * @return Size of the output buffer. */ diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 673e5a6c..7dad0770 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -219,11 +219,14 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { if (py_module != NULL) { - u8 py_notrim = 0, py_idx; - /* init, required */ + u8 py_notrim = 0; py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init"); - if (!py_functions[PY_FUNC_INIT]) - FATAL("init function not found in python module"); + if (!py_functions[PY_FUNC_INIT]) { + + WARNF("init function not found in python module"); + + } + py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz"); if (!py_functions[PY_FUNC_FUZZ]) py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate"); @@ -231,12 +234,6 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { PyObject_GetAttrString(py_module, "describe"); py_functions[PY_FUNC_FUZZ_COUNT] = PyObject_GetAttrString(py_module, "fuzz_count"); - if (!py_functions[PY_FUNC_FUZZ]) { - - WARNF("fuzz function not found in python module"); - - } - py_functions[PY_FUNC_POST_PROCESS] = PyObject_GetAttrString(py_module, "post_process"); py_functions[PY_FUNC_INIT_TRIM] = @@ -263,36 +260,6 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { if (!py_functions[PY_FUNC_DEINIT]) WARNF("deinit function not found in python module"); - for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) { - - if (!py_functions[py_idx] || !PyCallable_Check(py_functions[py_idx])) { - - if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) { - - // Implementing the trim API is optional for now - if (PyErr_Occurred()) { PyErr_Print(); } - py_notrim = 1; - - } else if (py_idx >= PY_OPTIONAL) { - - // Only _init and _deinit are not optional currently - - if (PyErr_Occurred()) { PyErr_Print(); } - - } else { - - fprintf(stderr, - "Cannot find/call function with index %d in external " - "Python module.\n", - py_idx); - return NULL; - - } - - } - - } - if (py_notrim) { py_functions[PY_FUNC_INIT_TRIM] = NULL; @@ -345,6 +312,8 @@ static void init_py(afl_state_t *afl, py_mutator_t *py_mutator, (void)afl; + if (py_mutator->py_functions[PY_FUNC_INIT] == NULL) { return; } + PyObject *py_args, *py_value; /* Provide the init function a seed for the Python RNG */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index f5425011..26e8549d 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -133,7 +133,12 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { } - if (new_mem != *mem) { *mem = new_mem; } + if (new_mem != *mem && new_mem != NULL && new_size > 0) { + + *mem = afl_realloc((void **)mem, new_size); + memmove(*mem, new_mem, new_size); + + } if (unlikely(afl->custom_mutators_count)) { -- cgit 1.4.1 From eefd98f3741b5feca32c75b34a8d7b33e34044d0 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Fri, 14 Apr 2023 02:25:33 +0200 Subject: add Nyx support in various tools (like afl-cmin) --- afl-cmin | 14 ++++++-- include/common.h | 6 ++++ include/forkserver.h | 3 ++ src/afl-analyze.c | 64 ++++++++++++++++++++++++++++++--- src/afl-common.c | 31 ++++++++++++++++ src/afl-forkserver.c | 65 ++++++++++++++++++++++++++++++++++ src/afl-fuzz.c | 63 --------------------------------- src/afl-showmap.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/afl-tmin.c | 59 ++++++++++++++++++++++++++++++- 9 files changed, 330 insertions(+), 74 deletions(-) (limited to 'src') diff --git a/afl-cmin b/afl-cmin index 15b61f89..12791584 100755 --- a/afl-cmin +++ b/afl-cmin @@ -109,6 +109,7 @@ function usage() { " -O - use binary-only instrumentation (FRIDA mode)\n" \ " -Q - use binary-only instrumentation (QEMU mode)\n" \ " -U - use unicorn-based instrumentation (unicorn mode)\n" \ +" -X - use Nyx mode\n" \ "\n" \ "Minimization settings:\n" \ " -A - allow crashes and timeouts (not recommended)\n" \ @@ -156,7 +157,7 @@ BEGIN { # process options Opterr = 1 # default is to diagnose Optind = 1 # skip ARGV[0] - while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQU?")) != -1) { + while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUX?")) != -1) { if (_go_c == "i") { if (!Optarg) usage() if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} @@ -217,6 +218,12 @@ BEGIN { extra_par = extra_par " -U" unicorn_mode = 1 continue + } else + if (_go_c == "X") { + if (nyx_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} + extra_par = extra_par " -X" + nyx_mode = 1 + continue } else if (_go_c == "?") { exit 1 @@ -291,7 +298,8 @@ BEGIN { exit 1 } - if (target_bin && !exists_and_is_executable(target_bin)) { + + if (!nyx_mode && target_bin && !exists_and_is_executable(target_bin)) { "command -v "target_bin" 2>/dev/null" | getline tnew if (!tnew || !exists_and_is_executable(tnew)) { @@ -311,7 +319,7 @@ BEGIN { } } - if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode) { + if (!ENVIRON["AFL_SKIP_BIN_CHECK"] && !qemu_mode && !frida_mode && !unicorn_mode && !nyx_mode) { if (0 != system( "grep -q __AFL_SHM_ID "target_bin )) { print "[-] Error: binary '"target_bin"' doesn't appear to be instrumented." > "/dev/stderr" exit 1 diff --git a/include/common.h b/include/common.h index 0958b035..279a5f47 100644 --- a/include/common.h +++ b/include/common.h @@ -147,5 +147,11 @@ s32 create_file(u8 *fn); void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); +#ifdef __linux__ +/* Nyx helper functions to create and remove tmp workdirs */ +char* create_nyx_tmp_workdir(void); +void remove_nyx_tmp_workdir(char* nyx_out_dir_path); +#endif + #endif diff --git a/include/forkserver.h b/include/forkserver.h index 50898a08..273a9255 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -75,6 +75,9 @@ typedef struct { } nyx_plugin_handler_t; +/* Imports helper functions to enable Nyx mode (Linux only )*/ +nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary); + #endif typedef struct afl_forkserver { diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 548956d8..0bdadfdc 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -121,9 +121,9 @@ static void kill_child() { } -static void classify_counts(u8 *mem) { +static void classify_counts(u8 *mem, u32 mem_size) { - u32 i = map_size; + u32 i = mem_size; if (edges_only) { @@ -222,7 +222,7 @@ static u64 analyze_run_target(u8 *mem, u32 len, u8 first_run) { } - classify_counts(fsrv.trace_bits); + classify_counts(fsrv.trace_bits, fsrv.map_size); total_execs++; if (stop_soon) { @@ -768,6 +768,7 @@ static void usage(u8 *argv0) { " -U - use unicorn-based instrumentation (Unicorn mode)\n" " -W - use qemu-based instrumentation with Wine (Wine " "mode)\n" + " -X - use Nyx mode\n" #endif "\n" @@ -814,7 +815,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_fsrv_init(&fsrv); - while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWh")) > 0) { + while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXh")) > 0) { switch (opt) { @@ -965,6 +966,22 @@ int main(int argc, char **argv_orig, char **envp) { fsrv.mem_limit = mem_limit; break; + + #ifdef __linux__ + case 'X': /* NYX mode */ + + if (fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); } + + fsrv.nyx_mode = 1; + fsrv.nyx_parent = true; + fsrv.nyx_standalone = true; + + break; + #else + case 'X': + FATAL("Nyx mode is only availabe on linux..."); + break; + #endif case 'h': usage(argv[0]); @@ -997,7 +1014,17 @@ int main(int argc, char **argv_orig, char **envp) { set_up_environment(argv); +#ifdef __linux__ + if(!fsrv.nyx_mode){ + fsrv.target_path = find_binary(argv[optind]); + } + else{ + fsrv.target_path = ck_strdup(argv[optind]); + } +#else fsrv.target_path = find_binary(argv[optind]); +#endif + fsrv.trace_bits = afl_shm_init(&shm, map_size, 0); detect_file_args(argv + optind, fsrv.out_file, &use_stdin); signal(SIGALRM, kill_child); @@ -1020,6 +1047,23 @@ int main(int argc, char **argv_orig, char **envp) { use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind); +#ifdef __linux__ + } else if (fsrv.nyx_mode) { + + fsrv.nyx_id = 0; + + u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so"); + fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary); + if (fsrv.nyx_handlers == NULL) { + FATAL("failed to initialize libnyx.so..."); + } + + fsrv.out_dir_path = create_nyx_tmp_workdir(); + fsrv.nyx_bind_cpu_id = 0; + + use_argv = argv + optind; +#endif + } else { use_argv = argv + optind; @@ -1045,7 +1089,13 @@ int main(int argc, char **argv_orig, char **envp) { &fsrv, NULL, NULL, (fsrv.qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM); read_initial_file(); +#ifdef __linux__ + if(!fsrv.nyx_mode){ + (void)check_binary_signatures(fsrv.target_path); + } +#else (void)check_binary_signatures(fsrv.target_path); +#endif ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", mem_limit, exec_tmout, edges_only ? ", edges only" : ""); @@ -1069,6 +1119,12 @@ int main(int argc, char **argv_orig, char **envp) { OKF("We're done here. Have a nice day!\n"); +#ifdef __linux__ + if (fsrv.nyx_mode) { + remove_nyx_tmp_workdir(fsrv.out_dir_path); + } +#endif + afl_shm_deinit(&shm); afl_fsrv_deinit(&fsrv); if (fsrv.target_path) { ck_free(fsrv.target_path); } diff --git a/src/afl-common.c b/src/afl-common.c index 86226c9f..7dbf7129 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -1359,3 +1359,34 @@ s32 create_file(u8 *fn) { } +#ifdef __linux__ + +/* Nyx requires a tmp workdir to access specific files (such as mmapped files, + * etc.). This helper function basically creates both a path to a tmp workdir + * and the workdir itself. If the environment variable TMPDIR is set, we use + * that as the base directory, otherwise we use /tmp. */ +char* create_nyx_tmp_workdir(void) { + + char *tmpdir = getenv("TMPDIR"); + + if (!tmpdir) { tmpdir = "/tmp"; } + + char* nyx_out_dir_path = alloc_printf("%s/.nyx_tmp_%d/", tmpdir, (u32)getpid()); + + if (mkdir(nyx_out_dir_path, 0700)) { + PFATAL("Unable to create nyx workdir"); + } + + return nyx_out_dir_path; +} + +/* Vice versa, we remove the tmp workdir for nyx with this helper function. */ +void remove_nyx_tmp_workdir(char* nyx_out_dir_path) { + /* Fix me: This is not recursive, so it will always fail. Use a libnyx helper function instead + * to remove the workdir safely (and not risking to wipe the whole filesystem accidentally). */ + //if (rmdir(nyx_out_dir_path)) { + // PFATAL("Unable to remove nyx workdir"); + //} + free(nyx_out_dir_path); +} +#endif diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 5aa4c2ff..95328aa2 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -49,6 +49,71 @@ #include #include +#ifdef __linux__ +#include + +/* function to load nyx_helper function from libnyx.so */ + +nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) { + + void *handle; + nyx_plugin_handler_t *plugin = calloc(1, sizeof(nyx_plugin_handler_t)); + + ACTF("Trying to load libnyx.so plugin..."); + handle = dlopen((char *)libnyx_binary, RTLD_NOW); + if (!handle) { goto fail; } + + plugin->nyx_new = dlsym(handle, "nyx_new"); + if (plugin->nyx_new == NULL) { goto fail; } + + plugin->nyx_new_parent = dlsym(handle, "nyx_new_parent"); + if (plugin->nyx_new_parent == NULL) { goto fail; } + + plugin->nyx_new_child = dlsym(handle, "nyx_new_child"); + if (plugin->nyx_new_child == NULL) { goto fail; } + + plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown"); + if (plugin->nyx_shutdown == NULL) { goto fail; } + + plugin->nyx_option_set_reload_mode = + dlsym(handle, "nyx_option_set_reload_mode"); + if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; } + + plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout"); + if (plugin->nyx_option_set_timeout == NULL) { goto fail; } + + plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply"); + if (plugin->nyx_option_apply == NULL) { goto fail; } + + plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input"); + if (plugin->nyx_set_afl_input == NULL) { goto fail; } + + plugin->nyx_exec = dlsym(handle, "nyx_exec"); + if (plugin->nyx_exec == NULL) { goto fail; } + + plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer"); + if (plugin->nyx_get_bitmap_buffer == NULL) { goto fail; } + + plugin->nyx_get_bitmap_buffer_size = + dlsym(handle, "nyx_get_bitmap_buffer_size"); + if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; } + + plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string"); + if (plugin->nyx_get_aux_string == NULL) { goto fail; } + + OKF("libnyx plugin is ready!"); + return plugin; + +fail: + + FATAL("failed to load libnyx: %s\n", dlerror()); + free(plugin); + return NULL; + +} + +#endif + /** * The correct fds for reading and writing pipes */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a0c322da..8b4fe1e5 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -436,69 +436,6 @@ static void fasan_check_afl_preload(char *afl_preload) { } - #ifdef __linux__ - #include - -nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) { - - void *handle; - nyx_plugin_handler_t *plugin = calloc(1, sizeof(nyx_plugin_handler_t)); - - ACTF("Trying to load libnyx.so plugin..."); - handle = dlopen((char *)libnyx_binary, RTLD_NOW); - if (!handle) { goto fail; } - - plugin->nyx_new = dlsym(handle, "nyx_new"); - if (plugin->nyx_new == NULL) { goto fail; } - - plugin->nyx_new_parent = dlsym(handle, "nyx_new_parent"); - if (plugin->nyx_new_parent == NULL) { goto fail; } - - plugin->nyx_new_child = dlsym(handle, "nyx_new_child"); - if (plugin->nyx_new_child == NULL) { goto fail; } - - plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown"); - if (plugin->nyx_shutdown == NULL) { goto fail; } - - plugin->nyx_option_set_reload_mode = - dlsym(handle, "nyx_option_set_reload_mode"); - if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; } - - plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout"); - if (plugin->nyx_option_set_timeout == NULL) { goto fail; } - - plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply"); - if (plugin->nyx_option_apply == NULL) { goto fail; } - - plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input"); - if (plugin->nyx_set_afl_input == NULL) { goto fail; } - - plugin->nyx_exec = dlsym(handle, "nyx_exec"); - if (plugin->nyx_exec == NULL) { goto fail; } - - plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer"); - if (plugin->nyx_get_bitmap_buffer == NULL) { goto fail; } - - plugin->nyx_get_bitmap_buffer_size = - dlsym(handle, "nyx_get_bitmap_buffer_size"); - if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; } - - plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string"); - if (plugin->nyx_get_aux_string == NULL) { goto fail; } - - OKF("libnyx plugin is ready!"); - return plugin; - -fail: - - FATAL("failed to load libnyx: %s\n", dlerror()); - free(plugin); - return NULL; - -} - - #endif - /* Main entry point */ int main(int argc, char **argv_orig, char **envp) { diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 29abeb13..3ddebaad 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -434,6 +434,20 @@ static u32 read_file(u8 *in_file) { } +#ifdef __linux__ +/* Execute the target application with an empty input (in Nyx mode). */ +static void showmap_run_target_nyx_mode(afl_forkserver_t *fsrv) { + + afl_fsrv_write_to_testcase(fsrv, NULL, 0); + + if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon) == + FSRV_RUN_ERROR) { + + FATAL("Error running target in Nyx mode"); + } +} +#endif + /* Execute target application. */ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { @@ -797,6 +811,7 @@ static void usage(u8 *argv0) { " -W - use qemu-based instrumentation with Wine (Wine mode)\n" " (Not necessary, here for consistency with other afl-* " "tools)\n" + " -X - use Nyx mode\n" #endif "\n" "Other settings:\n" @@ -875,7 +890,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrsh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshX")) > 0) { switch (opt) { @@ -1063,6 +1078,22 @@ int main(int argc, char **argv_orig, char **envp) { break; + #ifdef __linux__ + case 'X': /* NYX mode */ + + if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); } + + fsrv->nyx_mode = 1; + fsrv->nyx_parent = true; + fsrv->nyx_standalone = true; + + break; + #else + case 'X': + FATAL("Nyx mode is only availabe on linux..."); + break; + #endif + case 'b': /* Secret undocumented mode. Writes output in raw binary format @@ -1134,7 +1165,17 @@ int main(int argc, char **argv_orig, char **envp) { set_up_environment(fsrv, argv); +#ifdef __linux__ + if(!fsrv->nyx_mode){ + fsrv->target_path = find_binary(argv[optind]); + } + else{ + fsrv->target_path = ck_strdup(argv[optind]); + } +#else fsrv->target_path = find_binary(argv[optind]); +#endif + fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); if (!quiet_mode) { @@ -1190,6 +1231,26 @@ int main(int argc, char **argv_orig, char **envp) { use_argv = get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind); +#ifdef __linux__ + } else if (fsrv->nyx_mode) { + + use_argv = ck_alloc(sizeof(char *) * (1)); + use_argv[0] = argv[0]; + + fsrv->nyx_id = 0; + + u8 *libnyx_binary = find_afl_binary(use_argv[0], "libnyx.so"); + fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary); + if (fsrv->nyx_handlers == NULL) { + + FATAL("failed to initialize libnyx.so..."); + + } + + fsrv->out_dir_path = create_nyx_tmp_workdir(); + fsrv->nyx_bind_cpu_id = 0; +#endif + } else { use_argv = argv + optind; @@ -1226,7 +1287,13 @@ int main(int argc, char **argv_orig, char **envp) { } +#ifdef __linux__ + if(!fsrv->nyx_mode && in_dir){ + (void)check_binary_signatures(fsrv->target_path); + } +#else if (in_dir) { (void)check_binary_signatures(fsrv->target_path); } +#endif shm_fuzz = ck_alloc(sizeof(sharedmem_t)); @@ -1247,7 +1314,13 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->shmem_fuzz = map + sizeof(u32); configure_afl_kill_signals( - fsrv, NULL, NULL, (fsrv->qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM); + fsrv, NULL, NULL, (fsrv->qemu_mode || unicorn_mode + #ifdef __linux__ + || fsrv->nyx_mode + #endif + ) + ? SIGKILL + : SIGTERM); if (!fsrv->cs_mode && !fsrv->qemu_mode && !unicorn_mode) { @@ -1370,6 +1443,12 @@ int main(int argc, char **argv_orig, char **envp) { if (execute_testcases(in_dir) == 0) { +#ifdef __linux__ + if (fsrv->nyx_mode) { + remove_nyx_tmp_workdir(fsrv->out_dir_path); + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + } +#endif FATAL("could not read input testcases from %s", in_dir); } @@ -1390,7 +1469,15 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - showmap_run_target(fsrv, use_argv); +#ifdef __linux__ + if(!fsrv->nyx_mode){ +#endif + showmap_run_target(fsrv, use_argv); +#ifdef __linux__ + } else { + showmap_run_target_nyx_mode(fsrv); + } +#endif tcnt = write_results_to_file(fsrv, out_file); if (!quiet_mode) { @@ -1441,6 +1528,12 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->target_path) { ck_free(fsrv->target_path); } +#ifdef __linux__ + if (fsrv->nyx_mode) { + remove_nyx_tmp_workdir(fsrv->out_dir_path); + } +#endif + afl_fsrv_deinit(fsrv); if (stdin_file) { ck_free(stdin_file); } diff --git a/src/afl-tmin.c b/src/afl-tmin.c index c0087f5f..942525d4 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -789,6 +789,7 @@ static void usage(u8 *argv0) { "mode)\n" " (Not necessary, here for consistency with other afl-* " "tools)\n" + " -X - use Nyx mode\n" #endif "\n" @@ -845,7 +846,7 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n"); - while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWHh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWXHh")) > 0) { switch (opt) { @@ -1003,6 +1004,22 @@ int main(int argc, char **argv_orig, char **envp) { break; + #ifdef __linux__ + case 'X': /* NYX mode */ + + if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); } + + fsrv->nyx_mode = 1; + fsrv->nyx_parent = true; + fsrv->nyx_standalone = true; + + break; + #else + case 'X': + FATAL("Nyx mode is only availabe on linux..."); + break; + #endif + case 'H': /* Hang Mode */ /* Minimizes a testcase to the minimum that still times out */ @@ -1068,7 +1085,17 @@ int main(int argc, char **argv_orig, char **envp) { set_up_environment(fsrv, argv); +#ifdef __linux__ + if(!fsrv->nyx_mode){ + fsrv->target_path = find_binary(argv[optind]); + } + else{ + fsrv->target_path = ck_strdup(argv[optind]); + } +#else fsrv->target_path = find_binary(argv[optind]); +#endif + fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); detect_file_args(argv + optind, out_file, &fsrv->use_stdin); signal(SIGALRM, kill_child); @@ -1092,6 +1119,23 @@ int main(int argc, char **argv_orig, char **envp) { use_argv = get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind); +#ifdef __linux__ + } else if (fsrv->nyx_mode) { + + fsrv->nyx_id = 0; + + u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so"); + fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary); + if (fsrv->nyx_handlers == NULL) { + FATAL("failed to initialize libnyx.so..."); + } + + fsrv->out_dir_path = create_nyx_tmp_workdir(); + fsrv->nyx_bind_cpu_id = 0; + + use_argv = argv + optind; +#endif + } else { use_argv = argv + optind; @@ -1161,7 +1205,14 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->shmem_fuzz = map + sizeof(u32); read_initial_file(); + +#ifdef __linux__ + if(!fsrv->nyx_mode){ + (void)check_binary_signatures(fsrv->target_path); + } +#else (void)check_binary_signatures(fsrv->target_path); +#endif if (!fsrv->qemu_mode && !unicorn_mode) { @@ -1265,6 +1316,12 @@ int main(int argc, char **argv_orig, char **envp) { OKF("We're done here. Have a nice day!\n"); +#ifdef __linux__ + if (fsrv->nyx_mode) { + remove_nyx_tmp_workdir(fsrv->out_dir_path); + } +#endif + remove_shm = 0; afl_shm_deinit(&shm); if (fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); -- cgit 1.4.1 From a96cdc649fbdf2ae6f40d4e966812c46083032a2 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Fri, 14 Apr 2023 05:59:12 +0200 Subject: switch to latest libnyx API --- include/forkserver.h | 25 ++++++++++++++++-------- src/afl-forkserver.c | 54 ++++++++++++++++++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/include/forkserver.h b/include/forkserver.h index 273a9255..7cbad8c8 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -51,16 +51,23 @@ typedef enum NyxReturnValue { } NyxReturnValue; +typedef enum NyxProcessRole { + StandAlone, + Parent, + Child, +} NyxProcessRole; + typedef struct { - void *(*nyx_new)(const char *sharedir, const char *workdir, uint32_t cpu_id, - uint32_t input_buffer_size, - bool input_buffer_write_protection); - void *(*nyx_new_parent)(const char *sharedir, const char *workdir, - uint32_t cpu_id, uint32_t input_buffer_size, - bool input_buffer_write_protection); - void *(*nyx_new_child)(const char *sharedir, const char *workdir, - uint32_t cpu_id, uint32_t worker_id); + void *(*nyx_config_load)(const char *sharedir); + void (*nyx_config_set_workdir_path)(void *config, const char *workdir); + void (*nyx_config_set_input_buffer_size)(void *config, uint32_t input_buffer_size); + void (*nyx_config_set_input_buffer_write_protection)(void *config, bool input_buffer_write_protection); + void (*nyx_config_set_hprintf_fd)(void *config, int32_t hprintf_fd); + void (*nyx_config_set_process_role)(void *config, enum NyxProcessRole role); + void (*nyx_config_set_reuse_snapshot_path)(void *config, const char *reuse_snapshot_path); + + void *(*nyx_new)(void *config, uint32_t worker_id); void (*nyx_shutdown)(void *qemu_process); void (*nyx_option_set_reload_mode)(void *qemu_process, bool enable); void (*nyx_option_set_timeout)(void *qemu_process, uint8_t timeout_sec, @@ -73,6 +80,8 @@ typedef struct { uint32_t (*nyx_get_aux_string)(void *nyx_process, uint8_t *buffer, uint32_t size); + bool (*nyx_remove_work_dir)(const char *workdir); + } nyx_plugin_handler_t; /* Imports helper functions to enable Nyx mode (Linux only )*/ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 95328aa2..33c46b8c 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -63,14 +63,29 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) { handle = dlopen((char *)libnyx_binary, RTLD_NOW); if (!handle) { goto fail; } - plugin->nyx_new = dlsym(handle, "nyx_new"); - if (plugin->nyx_new == NULL) { goto fail; } + plugin->nyx_config_load = dlsym(handle, "nyx_config_load"); + if (plugin->nyx_config_load == NULL) { goto fail; } + + plugin->nyx_config_set_workdir_path = dlsym(handle, "nyx_config_set_workdir_path"); + if (plugin->nyx_config_set_workdir_path == NULL) { goto fail; } + + plugin->nyx_config_set_input_buffer_size = dlsym(handle, "nyx_config_set_input_buffer_size"); + if (plugin->nyx_config_set_input_buffer_size == NULL) { goto fail; } + + plugin->nyx_config_set_input_buffer_write_protection = dlsym(handle, "nyx_config_set_input_buffer_write_protection"); + if (plugin->nyx_config_set_input_buffer_write_protection == NULL) { goto fail; } - plugin->nyx_new_parent = dlsym(handle, "nyx_new_parent"); - if (plugin->nyx_new_parent == NULL) { goto fail; } + plugin->nyx_config_set_hprintf_fd = dlsym(handle, "nyx_config_set_hprintf_fd"); + if (plugin->nyx_config_set_hprintf_fd == NULL) { goto fail; } - plugin->nyx_new_child = dlsym(handle, "nyx_new_child"); - if (plugin->nyx_new_child == NULL) { goto fail; } + plugin->nyx_config_set_process_role = dlsym(handle, "nyx_config_set_process_role"); + if (plugin->nyx_config_set_process_role == NULL) { goto fail; } + + plugin->nyx_config_set_reuse_snapshot_path = dlsym(handle, "nyx_config_set_reuse_snapshot_path"); + if (plugin->nyx_config_set_reuse_snapshot_path == NULL) { goto fail; } + + plugin->nyx_new = dlsym(handle, "nyx_new"); + if (plugin->nyx_new == NULL) { goto fail; } plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown"); if (plugin->nyx_shutdown == NULL) { goto fail; } @@ -101,6 +116,10 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) { plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string"); if (plugin->nyx_get_aux_string == NULL) { goto fail; } + plugin->nyx_remove_work_dir = dlsym(handle, "nyx_remove_work_dir"); + if (plugin->nyx_remove_work_dir == NULL) { goto fail; } + + OKF("libnyx plugin is ready!"); return plugin; @@ -474,27 +493,24 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } - if (fsrv->nyx_standalone) { + void* nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path); - fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new( - fsrv->target_path, x, fsrv->nyx_bind_cpu_id, MAX_FILE, true); + fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, x); + fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config, MAX_FILE); + fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config, true); + if (fsrv->nyx_standalone) { + fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, StandAlone); } else { - if (fsrv->nyx_parent) { - - fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new_parent( - fsrv->target_path, x, fsrv->nyx_bind_cpu_id, MAX_FILE, true); - + fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Parent); } else { - - fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new_child( - fsrv->target_path, x, fsrv->nyx_bind_cpu_id, fsrv->nyx_id); - + fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Child); } - } + fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id); + ck_free(x); if (fsrv->nyx_runner == NULL) { FATAL("Something went wrong ..."); } -- cgit 1.4.1 From 4f6ec6cb081bfee7a6e1d6ac211b33a820ec2f71 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Fri, 14 Apr 2023 06:21:43 +0200 Subject: add NYX_REUSE_SNAPSHOT env-var option --- src/afl-forkserver.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src') diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 33c46b8c..7eb2155e 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -509,6 +509,22 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } } + if (getenv("NYX_REUSE_SNAPSHOT") != NULL){ + + if (access(getenv("NYX_REUSE_SNAPSHOT"), F_OK) == -1) { + FATAL("NYX_REUSE_SNAPSHOT path does not exist"); + } + + /* stupid sanity check to avoid passing an empty or invalid snapshot directory */ + char* snapshot_file_path = alloc_printf("%s/global.state", getenv("NYX_REUSE_SNAPSHOT")); + if (access(snapshot_file_path, R_OK) == -1) { + FATAL("NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot"); + } + free(snapshot_file_path); + + fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(nyx_config, getenv("NYX_REUSE_SNAPSHOT")); + } + fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id); ck_free(x); -- cgit 1.4.1 From c34c3e2f5f70d9a445bdbbb2e2f0937e98358607 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Fri, 14 Apr 2023 06:24:46 +0200 Subject: add some sanity checks and remove duplicate nyx_shutdown calls --- src/afl-forkserver.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 7eb2155e..ae2adc3d 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -555,14 +555,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, switch (fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)) { case Abort: - fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); FATAL("Error: Nyx abort occured..."); break; case IoError: FATAL("Error: QEMU-Nyx has died..."); break; case Error: - fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); FATAL("Error: Nyx runtime error has occured..."); break; default: @@ -1293,8 +1291,14 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) { #ifdef __linux__ if (fsrv->nyx_mode) { - free(fsrv->nyx_aux_string); - fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + if (fsrv->nyx_aux_string){ + free(fsrv->nyx_aux_string); + } + + /* check if we actually got a valid nyx runner */ + if (fsrv->nyx_runner) { + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + } } @@ -1474,7 +1478,6 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, FATAL("FixMe: Nyx InvalidWriteToPayload handler is missing"); break; case Abort: - fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); FATAL("Error: Nyx abort occured..."); case IoError: if (*stop_soon_p) { -- cgit 1.4.1 From 8f6d9d66ef96286661dab876d9b57a36982b2a4d Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 15 Apr 2023 08:33:50 +0200 Subject: fix post_process --- src/afl-fuzz-run.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 26e8549d..4d56f3a7 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -135,8 +135,11 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { if (new_mem != *mem && new_mem != NULL && new_size > 0) { - *mem = afl_realloc((void **)mem, new_size); - memmove(*mem, new_mem, new_size); + u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size); + if (unlikely(!new_buf)) { PFATAL("alloc"); } + *mem = new_buf; + memcpy(*mem, new_mem, new_size); + afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); } -- cgit 1.4.1 From 47833bcf9e4b642e090f7cc0da25d1ed99688e5e Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Sun, 16 Apr 2023 04:28:19 +0200 Subject: fix remove_nyx_tmp_workdir function --- include/common.h | 2 +- src/afl-common.c | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/include/common.h b/include/common.h index 279a5f47..e03566de 100644 --- a/include/common.h +++ b/include/common.h @@ -150,7 +150,7 @@ void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle, #ifdef __linux__ /* Nyx helper functions to create and remove tmp workdirs */ char* create_nyx_tmp_workdir(void); -void remove_nyx_tmp_workdir(char* nyx_out_dir_path); +void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char* nyx_out_dir_path); #endif #endif diff --git a/src/afl-common.c b/src/afl-common.c index 7dbf7129..fe0db94d 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -1381,12 +1381,22 @@ char* create_nyx_tmp_workdir(void) { } /* Vice versa, we remove the tmp workdir for nyx with this helper function. */ -void remove_nyx_tmp_workdir(char* nyx_out_dir_path) { - /* Fix me: This is not recursive, so it will always fail. Use a libnyx helper function instead - * to remove the workdir safely (and not risking to wipe the whole filesystem accidentally). */ - //if (rmdir(nyx_out_dir_path)) { - // PFATAL("Unable to remove nyx workdir"); - //} - free(nyx_out_dir_path); +void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char* nyx_out_dir_path) { + char* workdir_path = alloc_printf("%s/workdir", nyx_out_dir_path); + + if (access(workdir_path, R_OK) == 0) { + if(fsrv->nyx_handlers->nyx_remove_work_dir(workdir_path) != true) { + WARNF("Unable to remove nyx workdir (%s)", workdir_path); + } + } + + if (access(nyx_out_dir_path, R_OK) == 0) { + if (rmdir(nyx_out_dir_path)) { + WARNF("Unable to remove nyx workdir (%s)", nyx_out_dir_path); + } + } + + ck_free(workdir_path); + ck_free(nyx_out_dir_path); } #endif -- cgit 1.4.1 From 059d470e8dd0a5339daefe0842f4ad5014717838 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Sun, 16 Apr 2023 04:42:09 +0200 Subject: improved Nyx tmp dir handling (additional sanity checks) --- include/forkserver.h | 2 ++ src/afl-analyze.c | 7 +--- src/afl-forkserver.c | 97 +++++++++++++++++++++++++++++++++++----------------- src/afl-fuzz.c | 8 ----- src/afl-showmap.c | 13 +------ src/afl-tmin.c | 7 +--- 6 files changed, 71 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/include/forkserver.h b/include/forkserver.h index 7cbad8c8..ba280d38 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -190,6 +190,8 @@ typedef struct afl_forkserver { u32 nyx_id; /* nyx runner id (0 -> master) */ u32 nyx_bind_cpu_id; /* nyx runner cpu id */ char *nyx_aux_string; + bool nyx_use_tmp_workdir; + char *nyx_tmp_workdir_path; #endif } afl_forkserver_t; diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 0bdadfdc..0a4e7fb5 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -1058,7 +1058,7 @@ int main(int argc, char **argv_orig, char **envp) { FATAL("failed to initialize libnyx.so..."); } - fsrv.out_dir_path = create_nyx_tmp_workdir(); + fsrv.nyx_use_tmp_workdir = true; fsrv.nyx_bind_cpu_id = 0; use_argv = argv + optind; @@ -1119,11 +1119,6 @@ int main(int argc, char **argv_orig, char **envp) { OKF("We're done here. Have a nice day!\n"); -#ifdef __linux__ - if (fsrv.nyx_mode) { - remove_nyx_tmp_workdir(fsrv.out_dir_path); - } -#endif afl_shm_deinit(&shm); afl_fsrv_deinit(&fsrv); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index ae2adc3d..0e705c63 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -126,11 +126,39 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) { fail: FATAL("failed to load libnyx: %s\n", dlerror()); - free(plugin); + ck_free(plugin); return NULL; } +void afl_nyx_runner_kill(afl_forkserver_t *fsrv){ + if (fsrv->nyx_mode) { + + if (fsrv->nyx_aux_string){ + ck_free(fsrv->nyx_aux_string); + } + + /* check if we actually got a valid nyx runner */ + if (fsrv->nyx_runner) { + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + } + + /* if we have use a tmp work dir we need to remove it */ + if (fsrv->nyx_use_tmp_workdir && fsrv->nyx_tmp_workdir_path) { + remove_nyx_tmp_workdir(fsrv, fsrv->nyx_tmp_workdir_path); + } + } +} + +/* Wrapper for FATAL() that kills the nyx runner (and removes all created tmp + * files) before exiting. Used before "afl_fsrv_killall()" is registered as + * an atexit() handler. */ +#define NYX_PRE_FATAL(fsrv, x...) \ + do { \ + afl_nyx_runner_kill(fsrv); \ + FATAL(x); \ + } while (0) + #endif /** @@ -168,6 +196,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->nyx_runner = NULL; fsrv->nyx_id = 0xFFFFFFFF; fsrv->nyx_bind_cpu_id = 0xFFFFFFFF; + fsrv->nyx_use_tmp_workdir = false; + fsrv->nyx_tmp_workdir_path = NULL; #endif // this structure needs default so we initialize it if this was not done @@ -481,21 +511,24 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!be_quiet) { ACTF("Spinning up the NYX backend..."); } - if (fsrv->out_dir_path == NULL) { FATAL("Nyx workdir path not found..."); } + if (fsrv->nyx_use_tmp_workdir){ + fsrv->nyx_tmp_workdir_path = create_nyx_tmp_workdir(); + fsrv->out_dir_path = fsrv->nyx_tmp_workdir_path; + } else { + if (fsrv->out_dir_path == NULL) { NYX_PRE_FATAL(fsrv, "Nyx workdir path not found..."); } + } - char *x = alloc_printf("%s/workdir", fsrv->out_dir_path); + char *workdir_path = alloc_printf("%s/workdir", fsrv->out_dir_path); - if (fsrv->nyx_id == 0xFFFFFFFF) { FATAL("Nyx ID is not set..."); } + if (fsrv->nyx_id == 0xFFFFFFFF) {NYX_PRE_FATAL(fsrv, "Nyx ID is not set..."); } if (fsrv->nyx_bind_cpu_id == 0xFFFFFFFF) { - - FATAL("Nyx CPU ID is not set..."); - + NYX_PRE_FATAL(fsrv, "Nyx CPU ID is not set..."); } void* nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path); - fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, x); + fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, workdir_path); fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config, MAX_FILE); fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config, true); @@ -512,22 +545,36 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (getenv("NYX_REUSE_SNAPSHOT") != NULL){ if (access(getenv("NYX_REUSE_SNAPSHOT"), F_OK) == -1) { - FATAL("NYX_REUSE_SNAPSHOT path does not exist"); + NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not exist"); } /* stupid sanity check to avoid passing an empty or invalid snapshot directory */ char* snapshot_file_path = alloc_printf("%s/global.state", getenv("NYX_REUSE_SNAPSHOT")); if (access(snapshot_file_path, R_OK) == -1) { - FATAL("NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot"); + NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot"); } - free(snapshot_file_path); + ck_free(snapshot_file_path); + + /* another sanity check to avoid passing a snapshot directory that is + * located in the current workdir (the workdir will be wiped by libnyx on startup) */ + char* outdir_path_real = realpath(fsrv->out_dir_path, NULL); + char* workdir_snapshot_path = alloc_printf("%s/workdir/snapshot", outdir_path_real); + char* reuse_snapshot_path_real = realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL); + + if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0){ + NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path is located in current workdir (use another output directory)"); + } + + ck_free(reuse_snapshot_path_real); + ck_free(workdir_snapshot_path); + ck_free(outdir_path_real); fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(nyx_config, getenv("NYX_REUSE_SNAPSHOT")); } fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id); - ck_free(x); + ck_free(workdir_path); if (fsrv->nyx_runner == NULL) { FATAL("Something went wrong ..."); } @@ -555,13 +602,13 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, switch (fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)) { case Abort: - FATAL("Error: Nyx abort occured..."); + NYX_PRE_FATAL(fsrv, "Error: Nyx abort occured..."); break; case IoError: - FATAL("Error: QEMU-Nyx has died..."); + NYX_PRE_FATAL(fsrv, "Error: QEMU-Nyx has died..."); break; case Error: - FATAL("Error: Nyx runtime error has occured..."); + NYX_PRE_FATAL(fsrv, "Error: Nyx runtime error has occured..."); break; default: break; @@ -571,7 +618,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* autodict in Nyx mode */ if (!ignore_autodict) { - x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path); + char* x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path); int nyx_autodict_fd = open(x, O_RDONLY); ck_free(x); @@ -584,7 +631,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, u8 *dict = ck_alloc(f_len); if (dict == NULL) { - FATAL("Could not allocate %u bytes of autodictionary memory", + NYX_PRE_FATAL(fsrv, "Could not allocate %u bytes of autodictionary memory", f_len); } @@ -602,7 +649,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } else { - FATAL( + NYX_PRE_FATAL(fsrv, "Reading autodictionary fail at position %u with %u bytes " "left.", offset, len); @@ -1289,19 +1336,7 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) { fsrv->child_pid = -1; #ifdef __linux__ - if (fsrv->nyx_mode) { - - if (fsrv->nyx_aux_string){ - free(fsrv->nyx_aux_string); - } - - /* check if we actually got a valid nyx runner */ - if (fsrv->nyx_runner) { - fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); - } - - } - + afl_nyx_runner_kill(fsrv); #endif } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 8b4fe1e5..0e380f73 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2191,14 +2191,6 @@ int main(int argc, char **argv_orig, char **envp) { if (!afl->pending_not_fuzzed || !valid_seeds) { - #ifdef __linux__ - if (afl->fsrv.nyx_mode) { - - afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner); - - } - - #endif FATAL("We need at least one valid input seed that does not crash!"); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 3ddebaad..832730fd 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1247,7 +1247,7 @@ int main(int argc, char **argv_orig, char **envp) { } - fsrv->out_dir_path = create_nyx_tmp_workdir(); + fsrv->nyx_use_tmp_workdir = true; fsrv->nyx_bind_cpu_id = 0; #endif @@ -1443,12 +1443,6 @@ int main(int argc, char **argv_orig, char **envp) { if (execute_testcases(in_dir) == 0) { -#ifdef __linux__ - if (fsrv->nyx_mode) { - remove_nyx_tmp_workdir(fsrv->out_dir_path); - fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); - } -#endif FATAL("could not read input testcases from %s", in_dir); } @@ -1528,11 +1522,6 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->target_path) { ck_free(fsrv->target_path); } -#ifdef __linux__ - if (fsrv->nyx_mode) { - remove_nyx_tmp_workdir(fsrv->out_dir_path); - } -#endif afl_fsrv_deinit(fsrv); diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 942525d4..98403049 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1130,7 +1130,7 @@ int main(int argc, char **argv_orig, char **envp) { FATAL("failed to initialize libnyx.so..."); } - fsrv->out_dir_path = create_nyx_tmp_workdir(); + fsrv->nyx_use_tmp_workdir = true; fsrv->nyx_bind_cpu_id = 0; use_argv = argv + optind; @@ -1316,11 +1316,6 @@ int main(int argc, char **argv_orig, char **envp) { OKF("We're done here. Have a nice day!\n"); -#ifdef __linux__ - if (fsrv->nyx_mode) { - remove_nyx_tmp_workdir(fsrv->out_dir_path); - } -#endif remove_shm = 0; afl_shm_deinit(&shm); -- cgit 1.4.1 From 61aeb4486310b4aab66558bd21ead8b6e35501e2 Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Sun, 16 Apr 2023 05:19:09 +0200 Subject: remove redundant access() call --- src/afl-common.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/afl-common.c b/src/afl-common.c index fe0db94d..5692e277 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -1390,10 +1390,8 @@ void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char* nyx_out_dir_path) { } } - if (access(nyx_out_dir_path, R_OK) == 0) { - if (rmdir(nyx_out_dir_path)) { - WARNF("Unable to remove nyx workdir (%s)", nyx_out_dir_path); - } + if (rmdir(nyx_out_dir_path)) { + WARNF("Unable to remove nyx workdir (%s)", nyx_out_dir_path); } ck_free(workdir_path); -- cgit 1.4.1 From d0b86bf05563dea686d27f14972f448b6f33023b Mon Sep 17 00:00:00 2001 From: Sergej Schumilo Date: Sun, 16 Apr 2023 06:23:38 +0200 Subject: pass absolute paths to libnyx --- src/afl-forkserver.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 0e705c63..fd4e213d 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -518,7 +518,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (fsrv->out_dir_path == NULL) { NYX_PRE_FATAL(fsrv, "Nyx workdir path not found..."); } } - char *workdir_path = alloc_printf("%s/workdir", fsrv->out_dir_path); + /* libnyx expects an absolute path */ + char* outdir_path_absolute = realpath(fsrv->out_dir_path, NULL); + if (outdir_path_absolute == NULL) { NYX_PRE_FATAL(fsrv, "Nyx workdir path cannot be resolved ..."); } + + char *workdir_path = alloc_printf("%s/workdir", outdir_path_absolute); if (fsrv->nyx_id == 0xFFFFFFFF) {NYX_PRE_FATAL(fsrv, "Nyx ID is not set..."); } @@ -557,8 +561,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* another sanity check to avoid passing a snapshot directory that is * located in the current workdir (the workdir will be wiped by libnyx on startup) */ - char* outdir_path_real = realpath(fsrv->out_dir_path, NULL); - char* workdir_snapshot_path = alloc_printf("%s/workdir/snapshot", outdir_path_real); + char* workdir_snapshot_path = alloc_printf("%s/workdir/snapshot", outdir_path_absolute); char* reuse_snapshot_path_real = realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL); if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0){ @@ -567,7 +570,6 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, ck_free(reuse_snapshot_path_real); ck_free(workdir_snapshot_path); - ck_free(outdir_path_real); fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(nyx_config, getenv("NYX_REUSE_SNAPSHOT")); } @@ -575,6 +577,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id); ck_free(workdir_path); + ck_free(outdir_path_absolute); if (fsrv->nyx_runner == NULL) { FATAL("Something went wrong ..."); } -- cgit 1.4.1 From 56f7e3aa088e715b054f10c01b6b5a7e5acf8931 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 16 Apr 2023 12:42:32 +0200 Subject: hidden -Y option for nyx, code format --- afl-cmin | 10 +-- afl-cmin.bash | 30 +++++--- include/common.h | 4 +- include/forkserver.h | 13 +++- src/afl-analyze.c | 29 +++++--- src/afl-common.c | 26 +++++-- src/afl-forkserver.c | 151 +++++++++++++++++++++++++++----------- src/afl-showmap.c | 54 +++++++++----- src/afl-tmin.c | 27 ++++--- utils/aflpp_driver/aflpp_driver.c | 23 +++--- 10 files changed, 243 insertions(+), 124 deletions(-) (limited to 'src') diff --git a/afl-cmin b/afl-cmin index 12791584..c5e64410 100755 --- a/afl-cmin +++ b/afl-cmin @@ -124,9 +124,9 @@ function usage() { "AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \ "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ "AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \ -"AFL_FORK_SERVER_KILL_SIGNAL: Signal delivered to fork server processes on termination\n" \ -" (default: SIGTERM). If this is not set and AFL_KILL_SIGNAL is set,\n" \ -" this will be set to the same value as AFL_KILL_SIGNAL.\n" \ +"AFL_FORK_SERVER_KILL_SIGNAL: Signal delivered to fork server processes on\n" \ +" termination (default: SIGTERM). If this is not set and AFL_KILL_SIGNAL is\n" \ +" set, this will be set to the same value as AFL_KILL_SIGNAL.\n" \ "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" \ "AFL_CMIN_ALLOW_ANY: write tuples for crashing inputs also\n" \ "AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \ @@ -157,7 +157,7 @@ BEGIN { # process options Opterr = 1 # default is to diagnose Optind = 1 # skip ARGV[0] - while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUX?")) != -1) { + while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXY?")) != -1) { if (_go_c == "i") { if (!Optarg) usage() if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} @@ -219,7 +219,7 @@ BEGIN { unicorn_mode = 1 continue } else - if (_go_c == "X") { + if (_go_c == "X" || _go_c == "Y") { if (nyx_mode) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} extra_par = extra_par " -X" nyx_mode = 1 diff --git a/afl-cmin.bash b/afl-cmin.bash index 10c9477a..bcf62eba 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -53,7 +53,7 @@ unset IN_DIR OUT_DIR STDIN_FILE EXTRA_PAR MEM_LIMIT_GIVEN \ export AFL_QUIET=1 -while getopts "+i:o:f:m:t:eOQUACh" opt; do +while getopts "+i:o:f:m:t:eOQUAChXY" opt; do case "$opt" in @@ -94,6 +94,14 @@ while getopts "+i:o:f:m:t:eOQUACh" opt; do EXTRA_PAR="$EXTRA_PAR -Q" QEMU_MODE=1 ;; + "Y") + EXTRA_PAR="$EXTRA_PAR -X" + NYX_MODE=1 + ;; + "X") + EXTRA_PAR="$EXTRA_PAR -X" + NYX_MODE=1 + ;; "U") EXTRA_PAR="$EXTRA_PAR -U" UNICORN_MODE=1 @@ -128,6 +136,7 @@ Execution control settings: -O - use binary-only instrumentation (FRIDA mode) -Q - use binary-only instrumentation (QEMU mode) -U - use unicorn-based instrumentation (Unicorn mode) + -X - use Nyx mode Minimization settings: @@ -206,16 +215,19 @@ if [ ! "$TIMEOUT" = "none" ]; then fi -if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then +if [ "$NYX_MODE" = "" ]; then + if [ ! -f "$TARGET_BIN" -o ! -x "$TARGET_BIN" ]; then - TNEW="`which "$TARGET_BIN" 2>/dev/null`" + TNEW="`which "$TARGET_BIN" 2>/dev/null`" - if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then - echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2 - exit 1 - fi + if [ ! -f "$TNEW" -o ! -x "$TNEW" ]; then + echo "[-] Error: binary '$TARGET_BIN' not found or not executable." 1>&2 + exit 1 + fi + + TARGET_BIN="$TNEW" - TARGET_BIN="$TNEW" + fi fi @@ -228,7 +240,7 @@ grep -aq AFL_DUMP_MAP_SIZE "./$TARGET_BIN" && { } } -if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" ]; then +if [ "$AFL_SKIP_BIN_CHECK" = "" -a "$QEMU_MODE" = "" -a "$FRIDA_MODE" = "" -a "$UNICORN_MODE" = "" -a "$NYX_MODE" = "" ]; then if ! grep -qF "__AFL_SHM_ID" "$TARGET_BIN"; then echo "[-] Error: binary '$TARGET_BIN' doesn't appear to be instrumented." 1>&2 diff --git a/include/common.h b/include/common.h index e03566de..8d85d201 100644 --- a/include/common.h +++ b/include/common.h @@ -149,8 +149,8 @@ void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle, #ifdef __linux__ /* Nyx helper functions to create and remove tmp workdirs */ -char* create_nyx_tmp_workdir(void); -void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char* nyx_out_dir_path); +char *create_nyx_tmp_workdir(void); +void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char *nyx_out_dir_path); #endif #endif diff --git a/include/forkserver.h b/include/forkserver.h index ba280d38..f5069ce2 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -52,20 +52,25 @@ typedef enum NyxReturnValue { } NyxReturnValue; typedef enum NyxProcessRole { + StandAlone, Parent, Child, + } NyxProcessRole; typedef struct { void *(*nyx_config_load)(const char *sharedir); void (*nyx_config_set_workdir_path)(void *config, const char *workdir); - void (*nyx_config_set_input_buffer_size)(void *config, uint32_t input_buffer_size); - void (*nyx_config_set_input_buffer_write_protection)(void *config, bool input_buffer_write_protection); + void (*nyx_config_set_input_buffer_size)(void *config, + uint32_t input_buffer_size); + void (*nyx_config_set_input_buffer_write_protection)( + void *config, bool input_buffer_write_protection); void (*nyx_config_set_hprintf_fd)(void *config, int32_t hprintf_fd); void (*nyx_config_set_process_role)(void *config, enum NyxProcessRole role); - void (*nyx_config_set_reuse_snapshot_path)(void *config, const char *reuse_snapshot_path); + void (*nyx_config_set_reuse_snapshot_path)(void *config, + const char *reuse_snapshot_path); void *(*nyx_new)(void *config, uint32_t worker_id); void (*nyx_shutdown)(void *qemu_process); @@ -191,7 +196,7 @@ typedef struct afl_forkserver { u32 nyx_bind_cpu_id; /* nyx runner cpu id */ char *nyx_aux_string; bool nyx_use_tmp_workdir; - char *nyx_tmp_workdir_path; + char *nyx_tmp_workdir_path; #endif } afl_forkserver_t; diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 0a4e7fb5..5b122741 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -815,7 +815,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_fsrv_init(&fsrv); - while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXh")) > 0) { + while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXYh")) > 0) { switch (opt) { @@ -966,8 +966,9 @@ int main(int argc, char **argv_orig, char **envp) { fsrv.mem_limit = mem_limit; break; - - #ifdef __linux__ + + case 'Y': // fallthough +#ifdef __linux__ case 'X': /* NYX mode */ if (fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); } @@ -977,11 +978,11 @@ int main(int argc, char **argv_orig, char **envp) { fsrv.nyx_standalone = true; break; - #else +#else case 'X': FATAL("Nyx mode is only availabe on linux..."); break; - #endif +#endif case 'h': usage(argv[0]); @@ -1015,12 +1016,16 @@ int main(int argc, char **argv_orig, char **envp) { set_up_environment(argv); #ifdef __linux__ - if(!fsrv.nyx_mode){ + if (!fsrv.nyx_mode) { + fsrv.target_path = find_binary(argv[optind]); - } - else{ + + } else { + fsrv.target_path = ck_strdup(argv[optind]); + } + #else fsrv.target_path = find_binary(argv[optind]); #endif @@ -1048,6 +1053,7 @@ int main(int argc, char **argv_orig, char **envp) { use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind); #ifdef __linux__ + } else if (fsrv.nyx_mode) { fsrv.nyx_id = 0; @@ -1055,7 +1061,9 @@ int main(int argc, char **argv_orig, char **envp) { u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so"); fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary); if (fsrv.nyx_handlers == NULL) { + FATAL("failed to initialize libnyx.so..."); + } fsrv.nyx_use_tmp_workdir = true; @@ -1090,9 +1098,7 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); #ifdef __linux__ - if(!fsrv.nyx_mode){ - (void)check_binary_signatures(fsrv.target_path); - } + if (!fsrv.nyx_mode) { (void)check_binary_signatures(fsrv.target_path); } #else (void)check_binary_signatures(fsrv.target_path); #endif @@ -1119,7 +1125,6 @@ int main(int argc, char **argv_orig, char **envp) { OKF("We're done here. Have a nice day!\n"); - afl_shm_deinit(&shm); afl_fsrv_deinit(&fsrv); if (fsrv.target_path) { ck_free(fsrv.target_path); } diff --git a/src/afl-common.c b/src/afl-common.c index 5692e277..a5c48e80 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -1365,36 +1365,46 @@ s32 create_file(u8 *fn) { * etc.). This helper function basically creates both a path to a tmp workdir * and the workdir itself. If the environment variable TMPDIR is set, we use * that as the base directory, otherwise we use /tmp. */ -char* create_nyx_tmp_workdir(void) { +char *create_nyx_tmp_workdir(void) { char *tmpdir = getenv("TMPDIR"); if (!tmpdir) { tmpdir = "/tmp"; } - char* nyx_out_dir_path = alloc_printf("%s/.nyx_tmp_%d/", tmpdir, (u32)getpid()); + char *nyx_out_dir_path = + alloc_printf("%s/.nyx_tmp_%d/", tmpdir, (u32)getpid()); - if (mkdir(nyx_out_dir_path, 0700)) { - PFATAL("Unable to create nyx workdir"); - } + if (mkdir(nyx_out_dir_path, 0700)) { PFATAL("Unable to create nyx workdir"); } return nyx_out_dir_path; + } /* Vice versa, we remove the tmp workdir for nyx with this helper function. */ -void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char* nyx_out_dir_path) { - char* workdir_path = alloc_printf("%s/workdir", nyx_out_dir_path); +void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char *nyx_out_dir_path) { + + char *workdir_path = alloc_printf("%s/workdir", nyx_out_dir_path); if (access(workdir_path, R_OK) == 0) { - if(fsrv->nyx_handlers->nyx_remove_work_dir(workdir_path) != true) { + + if (fsrv->nyx_handlers->nyx_remove_work_dir(workdir_path) != true) { + WARNF("Unable to remove nyx workdir (%s)", workdir_path); + } + } if (rmdir(nyx_out_dir_path)) { + WARNF("Unable to remove nyx workdir (%s)", nyx_out_dir_path); + } ck_free(workdir_path); ck_free(nyx_out_dir_path); + } + #endif + diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index fd4e213d..aa8c8622 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -50,7 +50,7 @@ #include #ifdef __linux__ -#include + #include /* function to load nyx_helper function from libnyx.so */ @@ -66,22 +66,32 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) { plugin->nyx_config_load = dlsym(handle, "nyx_config_load"); if (plugin->nyx_config_load == NULL) { goto fail; } - plugin->nyx_config_set_workdir_path = dlsym(handle, "nyx_config_set_workdir_path"); + plugin->nyx_config_set_workdir_path = + dlsym(handle, "nyx_config_set_workdir_path"); if (plugin->nyx_config_set_workdir_path == NULL) { goto fail; } - plugin->nyx_config_set_input_buffer_size = dlsym(handle, "nyx_config_set_input_buffer_size"); + plugin->nyx_config_set_input_buffer_size = + dlsym(handle, "nyx_config_set_input_buffer_size"); if (plugin->nyx_config_set_input_buffer_size == NULL) { goto fail; } - plugin->nyx_config_set_input_buffer_write_protection = dlsym(handle, "nyx_config_set_input_buffer_write_protection"); - if (plugin->nyx_config_set_input_buffer_write_protection == NULL) { goto fail; } + plugin->nyx_config_set_input_buffer_write_protection = + dlsym(handle, "nyx_config_set_input_buffer_write_protection"); + if (plugin->nyx_config_set_input_buffer_write_protection == NULL) { - plugin->nyx_config_set_hprintf_fd = dlsym(handle, "nyx_config_set_hprintf_fd"); + goto fail; + + } + + plugin->nyx_config_set_hprintf_fd = + dlsym(handle, "nyx_config_set_hprintf_fd"); if (plugin->nyx_config_set_hprintf_fd == NULL) { goto fail; } - plugin->nyx_config_set_process_role = dlsym(handle, "nyx_config_set_process_role"); + plugin->nyx_config_set_process_role = + dlsym(handle, "nyx_config_set_process_role"); if (plugin->nyx_config_set_process_role == NULL) { goto fail; } - plugin->nyx_config_set_reuse_snapshot_path = dlsym(handle, "nyx_config_set_reuse_snapshot_path"); + plugin->nyx_config_set_reuse_snapshot_path = + dlsym(handle, "nyx_config_set_reuse_snapshot_path"); if (plugin->nyx_config_set_reuse_snapshot_path == NULL) { goto fail; } plugin->nyx_new = dlsym(handle, "nyx_new"); @@ -119,7 +129,6 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) { plugin->nyx_remove_work_dir = dlsym(handle, "nyx_remove_work_dir"); if (plugin->nyx_remove_work_dir == NULL) { goto fail; } - OKF("libnyx plugin is ready!"); return plugin; @@ -131,33 +140,40 @@ fail: } -void afl_nyx_runner_kill(afl_forkserver_t *fsrv){ +void afl_nyx_runner_kill(afl_forkserver_t *fsrv) { + if (fsrv->nyx_mode) { - if (fsrv->nyx_aux_string){ - ck_free(fsrv->nyx_aux_string); - } + if (fsrv->nyx_aux_string) { ck_free(fsrv->nyx_aux_string); } /* check if we actually got a valid nyx runner */ if (fsrv->nyx_runner) { + fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner); + } /* if we have use a tmp work dir we need to remove it */ if (fsrv->nyx_use_tmp_workdir && fsrv->nyx_tmp_workdir_path) { + remove_nyx_tmp_workdir(fsrv, fsrv->nyx_tmp_workdir_path); + } + } + } -/* Wrapper for FATAL() that kills the nyx runner (and removes all created tmp - * files) before exiting. Used before "afl_fsrv_killall()" is registered as - * an atexit() handler. */ -#define NYX_PRE_FATAL(fsrv, x...) \ - do { \ - afl_nyx_runner_kill(fsrv); \ - FATAL(x); \ - } while (0) + /* Wrapper for FATAL() that kills the nyx runner (and removes all created tmp + * files) before exiting. Used before "afl_fsrv_killall()" is registered as + * an atexit() handler. */ + #define NYX_PRE_FATAL(fsrv, x...) \ + do { \ + \ + afl_nyx_runner_kill(fsrv); \ + FATAL(x); \ + \ + } while (0) #endif @@ -511,70 +527,116 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!be_quiet) { ACTF("Spinning up the NYX backend..."); } - if (fsrv->nyx_use_tmp_workdir){ + if (fsrv->nyx_use_tmp_workdir) { + fsrv->nyx_tmp_workdir_path = create_nyx_tmp_workdir(); fsrv->out_dir_path = fsrv->nyx_tmp_workdir_path; + } else { - if (fsrv->out_dir_path == NULL) { NYX_PRE_FATAL(fsrv, "Nyx workdir path not found..."); } + + if (fsrv->out_dir_path == NULL) { + + NYX_PRE_FATAL(fsrv, "Nyx workdir path not found..."); + + } + } /* libnyx expects an absolute path */ - char* outdir_path_absolute = realpath(fsrv->out_dir_path, NULL); - if (outdir_path_absolute == NULL) { NYX_PRE_FATAL(fsrv, "Nyx workdir path cannot be resolved ..."); } + char *outdir_path_absolute = realpath(fsrv->out_dir_path, NULL); + if (outdir_path_absolute == NULL) { + + NYX_PRE_FATAL(fsrv, "Nyx workdir path cannot be resolved ..."); + + } char *workdir_path = alloc_printf("%s/workdir", outdir_path_absolute); - if (fsrv->nyx_id == 0xFFFFFFFF) {NYX_PRE_FATAL(fsrv, "Nyx ID is not set..."); } + if (fsrv->nyx_id == 0xFFFFFFFF) { + + NYX_PRE_FATAL(fsrv, "Nyx ID is not set..."); + + } if (fsrv->nyx_bind_cpu_id == 0xFFFFFFFF) { + NYX_PRE_FATAL(fsrv, "Nyx CPU ID is not set..."); + } - void* nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path); + void *nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path); fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, workdir_path); fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config, MAX_FILE); - fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config, true); + fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config, + true); if (fsrv->nyx_standalone) { + fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, StandAlone); + } else { + if (fsrv->nyx_parent) { + fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Parent); + } else { + fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Child); + } + } - if (getenv("NYX_REUSE_SNAPSHOT") != NULL){ + if (getenv("NYX_REUSE_SNAPSHOT") != NULL) { if (access(getenv("NYX_REUSE_SNAPSHOT"), F_OK) == -1) { + NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not exist"); + } - /* stupid sanity check to avoid passing an empty or invalid snapshot directory */ - char* snapshot_file_path = alloc_printf("%s/global.state", getenv("NYX_REUSE_SNAPSHOT")); + /* stupid sanity check to avoid passing an empty or invalid snapshot + * directory */ + char *snapshot_file_path = + alloc_printf("%s/global.state", getenv("NYX_REUSE_SNAPSHOT")); if (access(snapshot_file_path, R_OK) == -1) { - NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot"); + + NYX_PRE_FATAL( + fsrv, + "NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot"); + } + ck_free(snapshot_file_path); /* another sanity check to avoid passing a snapshot directory that is - * located in the current workdir (the workdir will be wiped by libnyx on startup) */ - char* workdir_snapshot_path = alloc_printf("%s/workdir/snapshot", outdir_path_absolute); - char* reuse_snapshot_path_real = realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL); + * located in the current workdir (the workdir will be wiped by libnyx on + * startup) */ + char *workdir_snapshot_path = + alloc_printf("%s/workdir/snapshot", outdir_path_absolute); + char *reuse_snapshot_path_real = + realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL); + + if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0) { + + NYX_PRE_FATAL(fsrv, + "NYX_REUSE_SNAPSHOT path is located in current workdir " + "(use another output directory)"); - if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0){ - NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path is located in current workdir (use another output directory)"); } ck_free(reuse_snapshot_path_real); ck_free(workdir_snapshot_path); - fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(nyx_config, getenv("NYX_REUSE_SNAPSHOT")); + fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path( + nyx_config, getenv("NYX_REUSE_SNAPSHOT")); + } - fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id); + fsrv->nyx_runner = + fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id); ck_free(workdir_path); ck_free(outdir_path_absolute); @@ -621,7 +683,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* autodict in Nyx mode */ if (!ignore_autodict) { - char* x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path); + char *x = + alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path); int nyx_autodict_fd = open(x, O_RDONLY); ck_free(x); @@ -634,8 +697,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, u8 *dict = ck_alloc(f_len); if (dict == NULL) { - NYX_PRE_FATAL(fsrv, "Could not allocate %u bytes of autodictionary memory", - f_len); + NYX_PRE_FATAL( + fsrv, "Could not allocate %u bytes of autodictionary memory", + f_len); } @@ -652,7 +716,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } else { - NYX_PRE_FATAL(fsrv, + NYX_PRE_FATAL( + fsrv, "Reading autodictionary fail at position %u with %u bytes " "left.", offset, len); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 832730fd..df030672 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -444,8 +444,11 @@ static void showmap_run_target_nyx_mode(afl_forkserver_t *fsrv) { FSRV_RUN_ERROR) { FATAL("Error running target in Nyx mode"); + } + } + #endif /* Execute target application. */ @@ -890,7 +893,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshX")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) { switch (opt) { @@ -1078,7 +1081,8 @@ int main(int argc, char **argv_orig, char **envp) { break; - #ifdef __linux__ + case 'Y': // fallthough +#ifdef __linux__ case 'X': /* NYX mode */ if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); } @@ -1088,11 +1092,11 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->nyx_standalone = true; break; - #else +#else case 'X': FATAL("Nyx mode is only availabe on linux..."); break; - #endif +#endif case 'b': @@ -1166,12 +1170,16 @@ int main(int argc, char **argv_orig, char **envp) { set_up_environment(fsrv, argv); #ifdef __linux__ - if(!fsrv->nyx_mode){ + if (!fsrv->nyx_mode) { + fsrv->target_path = find_binary(argv[optind]); - } - else{ + + } else { + fsrv->target_path = ck_strdup(argv[optind]); + } + #else fsrv->target_path = find_binary(argv[optind]); #endif @@ -1232,11 +1240,12 @@ int main(int argc, char **argv_orig, char **envp) { get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind); #ifdef __linux__ + } else if (fsrv->nyx_mode) { use_argv = ck_alloc(sizeof(char *) * (1)); use_argv[0] = argv[0]; - + fsrv->nyx_id = 0; u8 *libnyx_binary = find_afl_binary(use_argv[0], "libnyx.so"); @@ -1288,9 +1297,12 @@ int main(int argc, char **argv_orig, char **envp) { } #ifdef __linux__ - if(!fsrv->nyx_mode && in_dir){ + if (!fsrv->nyx_mode && in_dir) { + (void)check_binary_signatures(fsrv->target_path); + } + #else if (in_dir) { (void)check_binary_signatures(fsrv->target_path); } #endif @@ -1313,14 +1325,14 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->shmem_fuzz_len = (u32 *)map; fsrv->shmem_fuzz = map + sizeof(u32); - configure_afl_kill_signals( - fsrv, NULL, NULL, (fsrv->qemu_mode || unicorn_mode - #ifdef __linux__ - || fsrv->nyx_mode - #endif - ) - ? SIGKILL - : SIGTERM); + configure_afl_kill_signals(fsrv, NULL, NULL, + (fsrv->qemu_mode || unicorn_mode +#ifdef __linux__ + || fsrv->nyx_mode +#endif + ) + ? SIGKILL + : SIGTERM); if (!fsrv->cs_mode && !fsrv->qemu_mode && !unicorn_mode) { @@ -1464,13 +1476,18 @@ int main(int argc, char **argv_orig, char **envp) { shm_fuzz = deinit_shmem(fsrv, shm_fuzz); #ifdef __linux__ - if(!fsrv->nyx_mode){ + if (!fsrv->nyx_mode) { + #endif showmap_run_target(fsrv, use_argv); #ifdef __linux__ + } else { + showmap_run_target_nyx_mode(fsrv); + } + #endif tcnt = write_results_to_file(fsrv, out_file); if (!quiet_mode) { @@ -1522,7 +1539,6 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->target_path) { ck_free(fsrv->target_path); } - afl_fsrv_deinit(fsrv); if (stdin_file) { ck_free(stdin_file); } diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 98403049..e7442d1d 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -846,7 +846,7 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n"); - while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWXHh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWXYHh")) > 0) { switch (opt) { @@ -1004,7 +1004,8 @@ int main(int argc, char **argv_orig, char **envp) { break; - #ifdef __linux__ + case 'Y': // fallthough +#ifdef __linux__ case 'X': /* NYX mode */ if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); } @@ -1014,11 +1015,11 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->nyx_standalone = true; break; - #else +#else case 'X': FATAL("Nyx mode is only availabe on linux..."); break; - #endif +#endif case 'H': /* Hang Mode */ @@ -1086,12 +1087,16 @@ int main(int argc, char **argv_orig, char **envp) { set_up_environment(fsrv, argv); #ifdef __linux__ - if(!fsrv->nyx_mode){ + if (!fsrv->nyx_mode) { + fsrv->target_path = find_binary(argv[optind]); - } - else{ + + } else { + fsrv->target_path = ck_strdup(argv[optind]); + } + #else fsrv->target_path = find_binary(argv[optind]); #endif @@ -1120,6 +1125,7 @@ int main(int argc, char **argv_orig, char **envp) { get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind); #ifdef __linux__ + } else if (fsrv->nyx_mode) { fsrv->nyx_id = 0; @@ -1127,7 +1133,9 @@ int main(int argc, char **argv_orig, char **envp) { u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so"); fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary); if (fsrv->nyx_handlers == NULL) { + FATAL("failed to initialize libnyx.so..."); + } fsrv->nyx_use_tmp_workdir = true; @@ -1207,9 +1215,7 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); #ifdef __linux__ - if(!fsrv->nyx_mode){ - (void)check_binary_signatures(fsrv->target_path); - } + if (!fsrv->nyx_mode) { (void)check_binary_signatures(fsrv->target_path); } #else (void)check_binary_signatures(fsrv->target_path); #endif @@ -1316,7 +1322,6 @@ int main(int argc, char **argv_orig, char **envp) { OKF("We're done here. Have a nice day!\n"); - remove_shm = 0; afl_shm_deinit(&shm); if (fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); diff --git a/utils/aflpp_driver/aflpp_driver.c b/utils/aflpp_driver/aflpp_driver.c index 34294809..4e8f466d 100644 --- a/utils/aflpp_driver/aflpp_driver.c +++ b/utils/aflpp_driver/aflpp_driver.c @@ -78,10 +78,10 @@ extern unsigned int __afl_map_size; on the other hand this is what Google needs to make LLVMFuzzerRunDriver() work. Choose your poison Google! */ /*__attribute__((weak))*/ int LLVMFuzzerTestOneInput(const uint8_t *Data, - size_t Size); -__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); -__attribute__((weak)) int LLVMFuzzerRunDriver( - int *argc, char ***argv, int (*callback)(const uint8_t *data, size_t size)); + size_t Size); +__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); +__attribute__((weak)) int LLVMFuzzerRunDriver( + int *argc, char ***argv, int (*callback)(const uint8_t *data, size_t size)); // Default nop ASan hooks for manual poisoning when not linking the ASan // runtime @@ -268,15 +268,16 @@ static int ExecuteFilesOnyByOne(int argc, char **argv, __attribute__((weak)) int main(int argc, char **argv) { -// Enable if LLVMFuzzerTestOneInput() has the weak attribute -/* - if (!LLVMFuzzerTestOneInput) { + // Enable if LLVMFuzzerTestOneInput() has the weak attribute + /* + if (!LLVMFuzzerTestOneInput) { - fprintf(stderr, "Error: function LLVMFuzzerTestOneInput() not found!\n"); - abort(); + fprintf(stderr, "Error: function LLVMFuzzerTestOneInput() not found!\n"); + abort(); - } -*/ + } + + */ if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) printf( -- cgit 1.4.1 From 450dbae8cd2ae278e0b381d172cb7694f40278cb Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:09:48 +0200 Subject: first version with unix domain sockets is ready for testing --- custom_mutators/atnwalk/atnwalk.c | 254 +++++++++++++++++++++++++++++++++----- src/afl-fuzz-run.c | 11 +- 2 files changed, 232 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c index cc9f9618..584add61 100644 --- a/custom_mutators/atnwalk/atnwalk.c +++ b/custom_mutators/atnwalk/atnwalk.c @@ -1,5 +1,4 @@ -#include "../../include/afl-fuzz.h" - +#include #include #include #include @@ -7,10 +6,10 @@ #include #include - #define INIT_BUF_SIZE 4096 #define SOCKET_NAME "/tmp/atnwalk.socket" + // handshake constants const uint8_t SERVER_ARE_YOU_ALIVE = 42; const uint8_t SERVER_YES_I_AM_ALIVE = 213; @@ -23,8 +22,10 @@ const uint8_t SERVER_ENCODE_BIT = 0b00001000; typedef struct atnwalk_mutator { - uint8_t *decoded_buf; - size_t decoded_size; + uint8_t *fuzz_buf; + size_t fuzz_size; + uint8_t *post_process_buf; + size_t post_process_size; } atnwalk_mutator_t; @@ -55,6 +56,32 @@ int write_all(int fd, uint8_t *buf, size_t buf_size) { return 1; } +void put_uint32(uint8_t *buf, uint32_t val) { + buf[0] = (uint8_t) (val >> 24); + buf[1] = (uint8_t) ((val & 0x00ff0000) >> 16); + buf[2] = (uint8_t) ((val & 0x0000ff00) >> 8); + buf[3] = (uint8_t) (val & 0x000000ff); +} + +uint32_t to_uint32(uint8_t *buf) { + uint32_t val = 0; + val |= (((uint32_t) buf[0]) << 24); + val |= (((uint32_t) buf[1]) << 16); + val |= (((uint32_t) buf[2]) << 8); + val |= ((uint32_t) buf[3]); + return val; +} + +void put_uint64(uint8_t *buf, uint64_t val) { + buf[0] = (uint8_t) (val >> 56); + buf[1] = (uint8_t) ((val & 0x00ff000000000000) >> 48); + buf[2] = (uint8_t) ((val & 0x0000ff0000000000) >> 40); + buf[3] = (uint8_t) ((val & 0x000000ff00000000) >> 32); + buf[4] = (uint8_t) ((val & 0x00000000ff000000) >> 24); + buf[5] = (uint8_t) ((val & 0x0000000000ff0000) >> 16); + buf[6] = (uint8_t) ((val & 0x000000000000ff00) >> 8); + buf[7] = (uint8_t) (val & 0x00000000000000ff); +} /** * Initialize this custom mutator @@ -67,19 +94,21 @@ int write_all(int fd, uint8_t *buf, size_t buf_size) { * There may be multiple instances of this mutator in one afl-fuzz run! * Return NULL on error. */ -atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { +atnwalk_mutator_t *afl_custom_init(void *afl, unsigned int seed) { srand(seed); atnwalk_mutator_t *data = (atnwalk_mutator_t *) malloc(sizeof(atnwalk_mutator_t)); if (!data) { perror("afl_custom_init alloc"); return NULL; } - data->decoded_buf = (uint8_t *) malloc(INIT_BUF_SIZE); - data->decoded_size = INIT_BUF_SIZE; + data->fuzz_buf = (uint8_t *) malloc(INIT_BUF_SIZE); + data->fuzz_size = INIT_BUF_SIZE; + data->post_process_buf = (uint8_t *) malloc(INIT_BUF_SIZE); + data->post_process_size = INIT_BUF_SIZE; return data; } -// TODO: implement + /** * Perform custom mutations on a given input * @@ -100,13 +129,12 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u uint8_t *add_buf, size_t add_buf_size, size_t max_size) { struct sockaddr_un addr; int fd_socket; - ssize_t n; - uint8_t buffer[5]; + uint8_t ctrl_buf[8]; + uint8_t wanted; // initialize the socket fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (fd_socket == -1) { - perror("socket"); *out_buf = NULL; return 0; } @@ -114,26 +142,127 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { - perror("atnwalk server is down"); + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // TODO: how to set connection deadline? maybe not required if server already closes the connection? + + // TODO: there should be some kind of loop retrying with different seeds and ultimately giving up on that input? + // maybe this is not necessary, because we may also just return a single byte in case of failure? + + // ask whether the server is alive + ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; + if (!write_all(fd_socket, ctrl_buf, 1)) { + close(fd_socket); *out_buf = NULL; return 0; } - if (!write_all(fd_socket, buffer, 5)) { - perror("write to atnwalk server failed"); + // see whether the server replies as expected + if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // tell the server what we want to do + wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT; + + // 50% chance to perform a crossover if there is an additional buffer available + if ((add_buf_size > 0) && (rand() % 2)) { + wanted |= SERVER_CROSSOVER_BIT; + } + + // tell the server what we want and how much data will be sent + ctrl_buf[0] = wanted; + put_uint32(ctrl_buf + 1, (uint32_t) buf_size); + if (!write_all(fd_socket, ctrl_buf, 5)) { + close(fd_socket); *out_buf = NULL; return 0; } - if (read_all(fd_socket, buffer, 5)) { - perror("read to atnwalk server failed"); - exit(EXIT_FAILURE); + // send the data to mutate and encode + if (!write_all(fd_socket, buf, buf_size)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + if (wanted & SERVER_CROSSOVER_BIT) { + // since we requested crossover, we will first tell how much additional data is to be expected + put_uint32(ctrl_buf, (uint32_t) add_buf_size); + if (!write_all(fd_socket, ctrl_buf, 4)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + // send the additional data for crossover + if (!write_all(fd_socket, add_buf, add_buf_size)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + // lastly, a seed is required for crossover so send one + put_uint64(ctrl_buf, (uint64_t) rand()); + if (!write_all(fd_socket, ctrl_buf, 8)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + } + + // since we requested mutation, we need to provide a seed for that + put_uint64(ctrl_buf, (uint64_t) rand()); + if (!write_all(fd_socket, ctrl_buf, 8)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + // obtain the required buffer size for the data that will be returned + if (!read_all(fd_socket, ctrl_buf, 4)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + size_t new_size = (size_t) to_uint32(ctrl_buf); + + // if the data is too large then we ignore this round + if (new_size > max_size) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + if (new_size > buf_size) { + // buf is too small, need to use data->fuzz_buf, let's see whether we need to reallocate + if (new_size > data->fuzz_size) { + data->fuzz_size = new_size << 1; + data->fuzz_buf = (uint8_t *) realloc(data->fuzz_buf, data->fuzz_size); + } + *out_buf = data->fuzz_buf; + } else { + // new_size fits into buf, so re-use it + *out_buf = buf; + } + + // obtain the encoded data + if (!read_all(fd_socket, *out_buf, new_size)) { + close(fd_socket); + *out_buf = buf; + return buf_size; } close(fd_socket); + return new_size; } -// TODO: implement + /** * A post-processing function to use right before AFL writes the test case to * disk in order to execute the target. @@ -151,23 +280,90 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u * A return of 0 indicates an error. */ size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) { - data->decoded_buf[0] = 'p'; - data->decoded_buf[1] = 'u'; - data->decoded_buf[2] = 't'; - data->decoded_buf[3] = 's'; - data->decoded_buf[4] = ' '; - data->decoded_buf[5] = ';'; - data->decoded_buf[6] = '\n'; - return 7; + struct sockaddr_un addr; + int fd_socket; + uint8_t ctrl_buf[8]; + + // initialize the socket + fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd_socket == -1) { + *out_buf = NULL; + return 0; + } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); + if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // ask whether the server is alive + ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; + if (!write_all(fd_socket, ctrl_buf, 1)) { + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // see whether the server replies as expected + if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // tell the server what we want and how much data will be sent + ctrl_buf[0] = SERVER_DECODE_BIT; + put_uint32(ctrl_buf + 1, (uint32_t) buf_size); + if (!write_all(fd_socket, ctrl_buf, 5)) { + close(fd_socket); + *out_buf = NULL; + return 0; + } + + // send the data to decode + if (!write_all(fd_socket, buf, buf_size)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + // obtain the required buffer size for the data that will be returned + if (!read_all(fd_socket, ctrl_buf, 4)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + size_t new_size = (size_t) to_uint32(ctrl_buf); + + // need to use data->post_process_buf, let's see whether we need to reallocate + if (new_size > data->post_process_size) { + data->post_process_size = new_size << 1; + data->post_process_buf = (uint8_t *) realloc(data->post_process_buf, data->post_process_size); + } + *out_buf = data->post_process_buf; + + // obtain the decoded data + if (!read_all(fd_socket, *out_buf, new_size)) { + close(fd_socket); + *out_buf = buf; + return buf_size; + } + + close(fd_socket); + return new_size; } -// TODO: implement + /** * Deinitialize everything * * @param data The data ptr from afl_custom_init */ void afl_custom_deinit(atnwalk_mutator_t *data) { - free(data->decoded_buf); + free(data->fuzz_buf); + free(data->post_process_buf); free(data); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index ee4a3298..26a1ea36 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -130,12 +130,15 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { new_size = afl->max_length; } - - if (new_mem != *mem) { *mem = new_mem; } + // TODO: think about how to enable the change without breaking other implementations + // if (new_mem != *mem) { *mem = new_mem; } /* everything as planned. use the potentially new data. */ - afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size); - len = new_size; + // TODO: think about how to enable the change without breaking other implementations + afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size); + + // TODO: think about how to enable the change without breaking other implementations + // len = new_size; } else { -- cgit 1.4.1 From 9ab902402cd33156257fc0355c0105e7e03f5ba3 Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:09:48 +0200 Subject: fixed code clones in atnwalk.c, introduced new environment variable AFL_POST_PROCESS_KEEP_ORIGINAL in AFL++ to integrate atnwalk without re-compiling afl-fuzz --- custom_mutators/atnwalk/atnwalk.c | 144 +++++++++++++------------------------- include/afl-fuzz.h | 4 +- include/envs.h | 1 + src/afl-fuzz-run.c | 11 +-- src/afl-fuzz-state.c | 7 ++ src/afl-fuzz.c | 2 + 6 files changed, 66 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c index 0194ff18..901b8a9e 100644 --- a/custom_mutators/atnwalk/atnwalk.c +++ b/custom_mutators/atnwalk/atnwalk.c @@ -1,4 +1,4 @@ -#include "../../include/afl-fuzz.h" +#include "afl-fuzz.h" #include #include @@ -9,7 +9,7 @@ #include #define BUF_SIZE_INIT 4096 -#define SOCKET_NAME "/tmp/atnwalk.socket" +#define SOCKET_NAME "./atnwalk.socket" // how many errors (e.g. timeouts) to tolerate until moving on to the next queue entry #define ATNWALK_ERRORS_MAX 1 @@ -155,6 +155,29 @@ unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data, const unsigned char return data->stage_havoc_max + data->stage_splice_max; } + +size_t fail_fatal(int fd_socket, uint8_t **out_buf) { + if (fd_socket != -1) { + close(fd_socket); + } + *out_buf = NULL; + return 0; +} + + +size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, uint8_t **out_buf) { + if (fd_socket != -1) { + close(fd_socket); + } + data->atnwalk_error_count++; + if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { + data->afl->stage_max = data->afl->stage_cur; + } + *out_buf = buf; + return buf_size; +} + + /** * Perform custom mutations on a given input * @@ -202,7 +225,7 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u } } - // keep track of found new corpus seeds per stage and run the stage twice as long as initially planned + // keep track of found new corpus seeds per stage if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) { if (data->stage_splice_cur <= 1) { data->afl->stage_finds[STAGE_HAVOC] += data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; @@ -216,38 +239,28 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u // check whether this input produces a lot of timeouts, if it does then abandon this queue entry if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) { data->afl->stage_max = data->afl->stage_cur; - *out_buf = buf; - return buf_size; + return fail_gracefully(-1, data, buf, buf_size, out_buf); } // initialize the socket fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd_socket == -1) { - *out_buf = NULL; - return 0; - } + if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // ask whether the server is alive ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; if (!write_all(fd_socket, ctrl_buf, 1)) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // see whether the server replies as expected if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // tell the server what we want to do @@ -262,88 +275,48 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u ctrl_buf[0] = wanted; put_uint32(ctrl_buf + 1, (uint32_t) buf_size); if (!write_all(fd_socket, ctrl_buf, 5)) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // send the data to mutate and encode if (!write_all(fd_socket, buf, buf_size)) { - close(fd_socket); - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } if (wanted & SERVER_CROSSOVER_BIT) { // since we requested crossover, we will first tell how much additional data is to be expected put_uint32(ctrl_buf, (uint32_t) add_buf_size); if (!write_all(fd_socket, ctrl_buf, 4)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } // send the additional data for crossover if (!write_all(fd_socket, add_buf, add_buf_size)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } // lastly, a seed is required for crossover so send one put_uint64(ctrl_buf, (uint64_t) rand()); if (!write_all(fd_socket, ctrl_buf, 8)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } } // since we requested mutation, we need to provide a seed for that put_uint64(ctrl_buf, (uint64_t) rand()); if (!write_all(fd_socket, ctrl_buf, 8)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } // obtain the required buffer size for the data that will be returned if (!read_all(fd_socket, ctrl_buf, 4)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } size_t new_size = (size_t) to_uint32(ctrl_buf); // if the data is too large then we ignore this round if (new_size > max_size) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } if (new_size > buf_size) { @@ -360,13 +333,7 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u // obtain the encoded data if (!read_all(fd_socket, *out_buf, new_size)) { - close(fd_socket); - data->atnwalk_error_count++; - if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { - data->afl->stage_max = data->afl->stage_cur; - } - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } close(fd_socket); @@ -398,54 +365,41 @@ size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf // initialize the socket fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (fd_socket == -1) { - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); if (connect(fd_socket, (const struct sockaddr *) &addr, sizeof(addr)) == -1) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // ask whether the server is alive ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; if (!write_all(fd_socket, ctrl_buf, 1)) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // see whether the server replies as expected if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_fatal(fd_socket, out_buf); } // tell the server what we want and how much data will be sent ctrl_buf[0] = SERVER_DECODE_BIT; put_uint32(ctrl_buf + 1, (uint32_t) buf_size); if (!write_all(fd_socket, ctrl_buf, 5)) { - close(fd_socket); - *out_buf = NULL; - return 0; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } // send the data to decode if (!write_all(fd_socket, buf, buf_size)) { - close(fd_socket); - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } // obtain the required buffer size for the data that will be returned if (!read_all(fd_socket, ctrl_buf, 4)) { - close(fd_socket); - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } size_t new_size = (size_t) to_uint32(ctrl_buf); @@ -458,9 +412,7 @@ size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf // obtain the decoded data if (!read_all(fd_socket, *out_buf, new_size)) { - close(fd_socket); - *out_buf = buf; - return buf_size; + return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); } close(fd_socket); diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 23c20cc4..5d9b17e7 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -386,8 +386,8 @@ typedef struct afl_env_vars { afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, afl_exit_on_seed_issues, afl_try_affinity, afl_ignore_problems, - afl_keep_timeouts, afl_pizza_mode, afl_no_crash_readme, - afl_no_startup_calibration; + afl_keep_timeouts, afl_pizza_mode, afl_post_process_keep_original, + afl_no_crash_readme, afl_no_startup_calibration; 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 2204a100..1527dfcb 100644 --- a/include/envs.h +++ b/include/envs.h @@ -177,6 +177,7 @@ static char *afl_environment_variables[] = { "AFL_PATH", "AFL_PERFORMANCE_FILE", "AFL_PERSISTENT_RECORD", + "AFL_POST_PROCESS_KEEP_ORIGINAL", "AFL_PRELOAD", "AFL_TARGET_ENV", "AFL_PYTHON_MODULE", diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 26a1ea36..3c3d4817 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -130,15 +130,16 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { new_size = afl->max_length; } - // TODO: think about how to enable the change without breaking other implementations - // if (new_mem != *mem) { *mem = new_mem; } /* everything as planned. use the potentially new data. */ - // TODO: think about how to enable the change without breaking other implementations afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size); - // TODO: think about how to enable the change without breaking other implementations - // len = new_size; + if (likely(!afl->afl_env.afl_post_process_keep_original)) { + + if (new_mem != *mem) { *mem = new_mem; } + len = new_size; + + } } else { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 0576f84f..10bc2768 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -377,6 +377,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_statsd = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_POST_PROCESS_KEEP_ORIGINAL", + + afl_environment_variable_len)) { + + afl->afl_env.afl_post_process_keep_original = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TMPDIR", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 1f0fcab1..b83af257 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -284,6 +284,8 @@ static void usage(u8 *argv0, int more_help) { PERSISTENT_MSG + "AFL_POST_PROCESS_KEEP_ORIGINAL: save the file as it was prior post-processing to the queue,\n" + " but execute the post-processed one\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_TARGET_ENV: pass extra environment variables to target\n" "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" -- cgit 1.4.1 From 4e5f42cab6b8c501eeaf76ec7ca920089f6e0f3a Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 20 Apr 2023 10:39:23 +0200 Subject: afl-showmap custom mutator support --- GNUmakefile | 2 +- TODO.md | 4 +-- afl-cmin | 2 ++ afl-cmin.bash | 2 ++ docs/Changelog.md | 3 +- include/afl-fuzz.h | 8 +++-- src/afl-showmap.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 107 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/GNUmakefile b/GNUmakefile index 5bc3f9d5..0f890308 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -453,7 +453,7 @@ afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/ $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) diff --git a/TODO.md b/TODO.md index e7789cf6..dba75070 100644 --- a/TODO.md +++ b/TODO.md @@ -3,14 +3,14 @@ ## Should - splicing selection weighted? - - support afl_custom_{send,post_process}, persistent and deferred fork - server in afl-showmap + - support persistent and deferred fork server in afl-showmap? - better autodetection of shifting runtime timeout values - Update afl->pending_not_fuzzed for MOpt - afl-plot to support multiple plot_data - parallel builds for source-only targets - get rid of check_binary, replace with more forkserver communication - first fuzzer should be a main automatically? not sure. + - reload fuzz binary on signal ## Maybe diff --git a/afl-cmin b/afl-cmin index c5e64410..e2c26d91 100755 --- a/afl-cmin +++ b/afl-cmin @@ -133,6 +133,8 @@ function usage() { "AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \ "printed to stdout\n" \ "AFL_SKIP_BIN_CHECK: skip afl instrumentation checks for target binary\n" +"AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send)\n" +"AFL_PYTHON_MODULE: custom mutator library (post_process and send)\n" exit 1 } diff --git a/afl-cmin.bash b/afl-cmin.bash index bcf62eba..5258758e 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -151,6 +151,8 @@ AFL_KEEP_TRACES: leave the temporary \.traces directory AFL_NO_FORKSRV: run target via execve instead of using the forkserver AFL_PATH: last resort location to find the afl-showmap binary AFL_SKIP_BIN_CHECK: skip check for target binary +AFL_CUSTOM_MUTATOR_LIBRARY: custom mutator library (post_process and send) +AFL_PYTHON_MODULE: custom mutator library (post_process and send) _EOF_ exit 1 fi diff --git a/docs/Changelog.md b/docs/Changelog.md index 30e76f2c..5ed5ef2b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -4,7 +4,8 @@ release of the tool. See README.md for the general instruction manual. ### Version ++4.07a (dev) - - soon :) + - afl-showmap: + - added custom mutator post_process and send support ### Version ++4.06c (release) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 8b6502b4..ec69ba17 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1103,7 +1103,6 @@ u32 count_bits(afl_state_t *, u8 *); u32 count_bytes(afl_state_t *, u8 *); u32 count_non_255_bytes(afl_state_t *, u8 *); void simplify_trace(afl_state_t *, u8 *); -void classify_counts(afl_forkserver_t *); #ifdef WORD_SIZE_64 void discover_word(u8 *ret, u64 *current, u64 *virgin); #else @@ -1117,6 +1116,9 @@ u8 *describe_op(afl_state_t *, u8, size_t); u8 save_if_interesting(afl_state_t *, void *, u32, u8); u8 has_new_bits(afl_state_t *, u8 *); u8 has_new_bits_unclassified(afl_state_t *, u8 *); +#ifndef AFL_SHOWMAP +void classify_counts(afl_forkserver_t *); +#endif /* Extras */ @@ -1192,11 +1194,13 @@ void fix_up_sync(afl_state_t *); void check_asan_opts(afl_state_t *); void check_binary(afl_state_t *, u8 *); void check_if_tty(afl_state_t *); -void setup_signal_handlers(void); void save_cmdline(afl_state_t *, u32, char **); void read_foreign_testcases(afl_state_t *, int); void write_crash_readme(afl_state_t *afl); u8 check_if_text_buf(u8 *buf, u32 len); +#ifndef AFL_SHOWMAP +void setup_signal_handlers(void); +#endif /* CmpLog */ diff --git a/src/afl-showmap.c b/src/afl-showmap.c index df030672..b5a61de5 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -30,8 +30,10 @@ */ #define AFL_MAIN +#define AFL_SHOWMAP #include "config.h" +#include "afl-fuzz.h" #include "types.h" #include "debug.h" #include "alloc-inl.h" @@ -62,6 +64,8 @@ #include #include +static afl_state_t *afl; + static char *stdin_file; /* stdin file */ static u8 *in_dir = NULL, /* input folder */ @@ -308,12 +312,73 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { } +void pre_afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *mem, u32 len) { + + static u8 buf[MAX_FILE]; + u32 sent = 0; + + if (unlikely(afl->custom_mutators_count)) { + + ssize_t new_size = len; + u8 *new_mem = mem; + u8 *new_buf = NULL; + + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + if (el->afl_custom_post_process) { + + new_size = + el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); + + if (unlikely(!new_buf || new_size <= 0)) { + + return; + + } else { + + new_mem = new_buf; + len = new_size; + + } + + } + + }); + + if (new_mem != mem && new_mem != NULL) { + + mem = buf; + memcpy(mem, new_mem, new_size); + + } + + if (unlikely(afl->custom_mutators_count)) { + + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + if (el->afl_custom_fuzz_send) { + + el->afl_custom_fuzz_send(el->data, mem, len); + sent = 1; + + } + + }); + + } + + } + + if (likely(!sent)) { afl_fsrv_write_to_testcase(fsrv, mem, len); } + +} + /* Execute target application. */ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, u32 len) { - afl_fsrv_write_to_testcase(fsrv, mem, len); + pre_afl_fsrv_write_to_testcase(fsrv, mem, len); if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); } @@ -835,6 +900,10 @@ static void usage(u8 *argv0) { "This tool displays raw tuple data captured by AFL instrumentation.\n" "For additional help, consult %s/README.md.\n\n" + "If you use -i mode, then custom mutator post_process send send " + "functionality\n" + "is supported.\n\n" + "Environment variables used:\n" "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n" "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing " @@ -1266,6 +1335,8 @@ int main(int argc, char **argv_orig, char **envp) { } + afl = calloc(1, sizeof(afl_state_t)); + if (getenv("AFL_FORKSRV_INIT_TMOUT")) { s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT")); @@ -1380,6 +1451,26 @@ int main(int argc, char **argv_orig, char **envp) { } + if (in_dir) { + + afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY); + afl->afl_env.afl_custom_mutator_library = + getenv("AFL_CUSTOM_MUTATOR_LIBRARY"); + afl->afl_env.afl_python_module = getenv("AFL_PYTHON_MODULE"); + setup_custom_mutators(afl); + + } else { + + if (getenv("AFL_CUSTOM_MUTATOR_LIBRARY") || getenv("AFL_PYTHON_MODULE")) { + + WARNF( + "Custom mutator environment detected, this is only supported in -i " + "mode!\n"); + + } + + } + if (in_dir) { DIR *dir_in, *dir_out = NULL; -- cgit 1.4.1 From 0a297ed9ef48c1eaf69fdc13bd1016f8f29124be Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 21 Apr 2023 15:09:35 +0200 Subject: dummy function for afl-showmap --- src/afl-showmap.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index b5a61de5..affad7d6 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -140,6 +140,15 @@ static void kill_child() { } +/* dummy function */ +u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) { + + (void)afl; + (void)mem; + return a + b; + +} + static void classify_counts(afl_forkserver_t *fsrv) { u8 *mem = fsrv->trace_bits; -- cgit 1.4.1 From 7a8d0a10ce25d20bdd2021920b0b5ebbc0d3f3a6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 21 Apr 2023 15:21:11 +0200 Subject: add dummy functions to afl-showmap for old gcc compilers --- src/afl-showmap.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index affad7d6..0b9fc211 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -140,7 +140,7 @@ static void kill_child() { } -/* dummy function */ +/* dummy functions */ u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) { (void)afl; @@ -149,7 +149,30 @@ u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) { } -static void classify_counts(afl_forkserver_t *fsrv) { +void show_stats(afl_state_t *afl) { + + (void)afl; + +} + +void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { + + (void)afl; + (void)q; + +} + +fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, + u32 i) { + + (void)afl; + (void)fsrv; + (void)i; + return 0; + +} + +void classify_counts(afl_forkserver_t *fsrv) { u8 *mem = fsrv->trace_bits; const u8 *map = binary_mode ? count_class_binary : count_class_human; -- cgit 1.4.1 From 779a72ef8c2457430b824f7830eba731745fb6ee Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Fri, 21 Apr 2023 16:46:15 +0200 Subject: fixed AFL_POST_PROCESS_KEEP_ORIGINAL for version 4.07a --- src/afl-fuzz-run.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 2d53de93..ac4fb4a9 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -133,14 +133,22 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { } - if (new_mem != *mem && new_mem != NULL && new_size > 0 - && !afl->afl_env.afl_post_process_keep_original) { + if (new_mem != *mem && new_mem != NULL && new_size > 0) { - u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size); - if (unlikely(!new_buf)) { PFATAL("alloc"); } - *mem = new_buf; - memcpy(*mem, new_mem, new_size); - afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); + new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size); + if (unlikely(!new_buf)) { PFATAL("alloc"); } + memcpy(new_buf, new_mem, new_size); + + /* if AFL_POST_PROCESS_KEEP_ORIGINAL is set then save the original memory + prior post-processing in new_mem to restore it later */ + if (unlikely(afl->afl_env.afl_post_process_keep_original)) { + + new_mem = *mem; + + } + + *mem = new_buf; + afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); } @@ -162,17 +170,19 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) { if (likely(!sent)) { /* everything as planned. use the potentially new data. */ + afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size); if (likely(!afl->afl_env.afl_post_process_keep_original)) { - afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size); + len = new_size; } else { - afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size); + /* restore the original memory which was saved in new_mem */ + *mem = new_mem; + afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch)); } - len = new_size; } -- cgit 1.4.1 From 228e9527cb0c00644e9601afc0449c586b468576 Mon Sep 17 00:00:00 2001 From: Maik Betka <9078425+voidptr127@users.noreply.github.com> Date: Fri, 21 Apr 2023 17:19:37 +0200 Subject: fixed formatting with make code-format --- src/afl-fuzz-state.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index cccebeb9..5e736029 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -396,10 +396,10 @@ void read_afl_environment(afl_state_t *afl, char **envp) { } else if (!strncmp(env, "AFL_POST_PROCESS_KEEP_ORIGINAL", - afl_environment_variable_len)) { + afl_environment_variable_len)) { - afl->afl_env.afl_post_process_keep_original = - get_afl_env(afl_environment_variables[i]) ? 1 : 0; + afl->afl_env.afl_post_process_keep_original = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; } else if (!strncmp(env, "AFL_TMPDIR", -- cgit 1.4.1 From 599b4631a3a40930e54e103f8ad1a69499fd1c8b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 22 Apr 2023 11:31:21 +0200 Subject: typo --- src/afl-fuzz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index f6628851..394f33f9 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -326,7 +326,7 @@ static void usage(u8 *argv0, int more_help) { } #ifdef USE_PYTHON - SAYF("Compiled with %s module support, see docs/custom_mutator.md\n", + SAYF("Compiled with %s module support, see docs/custom_mutators.md\n", (char *)PYTHON_VERSION); #else SAYF("Compiled without Python module support.\n"); -- cgit 1.4.1 From 8c228b0d23e303499dccf3df77c5d0b3a8b59b7b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 24 Apr 2023 18:08:27 +0200 Subject: afl-showmap -I option --- afl-cmin | 2 +- docs/Changelog.md | 1 + src/afl-showmap.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 156 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/afl-cmin b/afl-cmin index e2c26d91..6b36c261 100755 --- a/afl-cmin +++ b/afl-cmin @@ -234,7 +234,7 @@ BEGIN { } # while options if (!mem_limit) mem_limit = "none" - if (!timeout) timeout = "none" + if (!timeout) timeout = "5000" # get program args i = 0 diff --git a/docs/Changelog.md b/docs/Changelog.md index f33acff9..d4e68036 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,7 @@ data before post process on finds - afl-showmap: - added custom mutator post_process and send support + - add `-I filelist` option, an alternative to `-i in_dir` - a new grammar custom mutator atnwalk was submitted by @voidptr127 ! diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 0b9fc211..09a1d2dc 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -69,7 +69,9 @@ static afl_state_t *afl; static char *stdin_file; /* stdin file */ static u8 *in_dir = NULL, /* input folder */ - *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */ + *out_file = NULL, /* output file or directory */ + *at_file = NULL, /* Substitution string for @@ */ + *in_filelist = NULL; /* input file list */ static u8 outfile[PATH_MAX]; @@ -878,6 +880,104 @@ u32 execute_testcases(u8 *dir) { } +u32 execute_testcases_filelist(u8 *fn) { + + u32 done = 0; + u8 buf[4096]; + u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX]; + FILE *f; + + if (!be_quiet) { ACTF("Reading from '%s'...", fn); } + + if ((f = fopen(fn, "r")) == NULL) { FATAL("could not open '%s'", fn); } + + while (fgets(buf, sizeof(buf), f) != NULL) { + + struct stat st; + + u8 *fn2 = buf, *fn3; + ; + + while (*fn2 == ' ') { + + ++fn2; + + } + + if (*fn2) { + + while (fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' || + fn2[strlen(fn2) - 1] == ' ') { + + fn2[strlen(fn2) - 1] = 0; + + } + + } + + if (debug) { printf("Getting coverage for '%s'\n", fn2); } + + if (!*fn2) { continue; } + + if (lstat(fn2, &st) || access(fn2, R_OK)) { + + WARNF("Unable to access '%s'", fn2); + continue; + + } + + if (!S_ISREG(st.st_mode) || !st.st_size) { continue; } + + if ((fn3 = strrchr(fn2, '/'))) { + + ++fn3; + + } else { + + fn3 = fn2; + + } + + if (st.st_size > MAX_FILE && !be_quiet && !quiet_mode) { + + WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2, + stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), + stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); + + } + + if (!collect_coverage) + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, fn3); + + if (read_file(fn2)) { + + if (wait_for_gdb) { + + fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid); + fprintf(stderr, "exec: kill -CONT %d\n", getpid()); + kill(0, SIGSTOP); + + } + + showmap_run_target_forkserver(fsrv, in_data, in_len); + ck_free(in_data); + ++done; + + if (child_crashed && debug) { WARNF("crashed: %s", fn2); } + + if (collect_coverage) + analyze_results(fsrv); + else + tcnt = write_results_to_file(fsrv, outfile); + + } + + } + + return done; + +} + /* Show banner. */ static void show_banner(void) { @@ -920,6 +1020,7 @@ static void usage(u8 *argv0) { " With -C, -o is a file, without -C it must be a " "directory\n" " and each bitmap will be written there individually.\n" + " -I filelist - alternatively to -i, -I is a list of files\n" " -C - collect coverage, writes all edges to -o and gives a " "summary\n" " Must be combined with -i.\n" @@ -932,7 +1033,7 @@ static void usage(u8 *argv0) { "This tool displays raw tuple data captured by AFL instrumentation.\n" "For additional help, consult %s/README.md.\n\n" - "If you use -i mode, then custom mutator post_process send send " + "If you use -i/-I mode, then custom mutator post_process send send " "functionality\n" "is supported.\n\n" @@ -994,7 +1095,7 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) { + while ((opt = getopt(argc, argv, "+i:I:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) { switch (opt) { @@ -1012,6 +1113,11 @@ int main(int argc, char **argv_orig, char **envp) { in_dir = optarg; break; + case 'I': + if (in_filelist) { FATAL("Multiple -I options not supported"); } + in_filelist = optarg; + break; + case 'o': if (out_file) { FATAL("Multiple -o options not supported"); } @@ -1234,10 +1340,12 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !out_file) { usage(argv[0]); } - if (in_dir) { + if (in_dir && in_filelist) { FATAL("you can only specify either -i or -I"); } + + if (in_dir || in_filelist) { if (!out_file && !collect_coverage) - FATAL("for -i you need to specify either -C and/or -o"); + FATAL("for -i/-I you need to specify either -C and/or -o"); } @@ -1294,7 +1402,7 @@ int main(int argc, char **argv_orig, char **envp) { } - if (in_dir) { + if (in_dir || in_filelist) { /* If we don't have a file name chosen yet, use a safe default. */ u8 *use_dir = "."; @@ -1400,7 +1508,7 @@ int main(int argc, char **argv_orig, char **envp) { } #ifdef __linux__ - if (!fsrv->nyx_mode && in_dir) { + if (!fsrv->nyx_mode && (in_dir || in_filelist)) { (void)check_binary_signatures(fsrv->target_path); @@ -1483,7 +1591,7 @@ int main(int argc, char **argv_orig, char **envp) { } - if (in_dir) { + if (in_dir || in_filelist) { afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY); afl->afl_env.afl_custom_mutator_library = @@ -1496,33 +1604,46 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_CUSTOM_MUTATOR_LIBRARY") || getenv("AFL_PYTHON_MODULE")) { WARNF( - "Custom mutator environment detected, this is only supported in -i " - "mode!\n"); + "Custom mutator environment detected, this is only supported in " + "-i/-I mode!\n"); } } - if (in_dir) { + if (in_dir || in_filelist) { DIR *dir_in, *dir_out = NULL; + u8 *dn = NULL; if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } - // if a queue subdirectory exists switch to that - u8 *dn = alloc_printf("%s/queue", in_dir); - if ((dir_in = opendir(dn)) != NULL) { + if (in_filelist) { + + if (!be_quiet) ACTF("Reading from file list '%s'...", in_filelist); + + } else { + + // if a queue subdirectory exists switch to that + dn = alloc_printf("%s/queue", in_dir); + + if ((dir_in = opendir(dn)) != NULL) { + + closedir(dir_in); + in_dir = dn; + + } else { + + ck_free(dn); - closedir(dir_in); - in_dir = dn; + } - } else + if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir); - ck_free(dn); - if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir); + } if (!collect_coverage) { @@ -1576,9 +1697,21 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - if (execute_testcases(in_dir) == 0) { + if (in_dir) { + + if (execute_testcases(in_dir) == 0) { + + FATAL("could not read input testcases from %s", in_dir); + + } + + } else { - FATAL("could not read input testcases from %s", in_dir); + if (execute_testcases_filelist(in_filelist) == 0) { + + FATAL("could not read input testcases from %s", in_filelist); + + } } -- cgit 1.4.1 From 7c3c0b26d1ae477fbae6944c0de18256621e1993 Mon Sep 17 00:00:00 2001 From: Keno Hassler <40292329+kenohassler@users.noreply.github.com> Date: Mon, 24 Apr 2023 20:21:54 +0200 Subject: document new env var --- docs/env_variables.md | 6 ++++-- src/afl-cc.c | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/docs/env_variables.md b/docs/env_variables.md index c5995d13..087ccdb7 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -156,7 +156,7 @@ Available options: - LTO - LTO instrumentation - NATIVE - clang's original pcguard based instrumentation - NGRAM-x - deeper previous location coverage (from NGRAM-2 up to NGRAM-16) - - PCGUARD - our own pcgard based instrumentation (default) + - PCGUARD - our own pcguard based instrumentation (default) #### CMPLOG @@ -240,7 +240,9 @@ combined. the default `0x10000`. A value of 0 or empty sets the map address to be dynamic (the original AFL way, which is slower). - `AFL_LLVM_MAP_DYNAMIC` sets the shared memory address to be dynamic. - + - `AFL_LLVM_LTO_SKIPINIT` skips adding initialization code. Some global vars + (e.g. the highest location ID) are not injected. Needed to instrument with + [WAFL](https://github.com/fgsect/WAFL.git). For more information, see [instrumentation/README.lto.md](../instrumentation/README.lto.md). diff --git a/src/afl-cc.c b/src/afl-cc.c index 7f15ad76..d1001187 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -2099,6 +2099,8 @@ int main(int argc, char **argv, char **envp) { "bb\n" " AFL_REAL_LD: use this lld linker instead of the compiled in " "path\n" + " AFL_LLVM_LTO_SKIPINIT: don't inject initialization code " + "(used in WAFL mode)\n" "If anything fails - be sure to read README.lto.md!\n"); #endif -- cgit 1.4.1 From c0ecf7cf61fdca901b041d57e7e2bb78bc8fcf80 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 Apr 2023 08:33:51 +0200 Subject: only reverse reading the queue on restart --- docs/Changelog.md | 4 ++++ src/afl-fuzz-init.c | 30 ++++++++++++++++++++---------- 2 files changed, 24 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index d4e68036..14323ae0 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -7,6 +7,10 @@ - afl-fuzz: - new env `AFL_POST_PROCESS_KEEP_ORIGINAL` to keep the orignal data before post process on finds + - reverse reading the seeds only on restarts + - afl-cc: + - new env `AFL_LLVM_LTO_SKIPINIT` to support the AFL++ based WASM + (https://github.com/fgsect/WAFL) project - afl-showmap: - added custom mutator post_process and send support - add `-I filelist` option, an alternative to `-i in_dir` diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 01d1e82e..002a26f8 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -718,10 +718,21 @@ void read_testcases(afl_state_t *afl, u8 *directory) { if (nl_cnt) { - i = nl_cnt; + u32 done = 0; + + if (unlikely(afl->in_place_resume)) { + + i = nl_cnt; + + } else { + + i = 0; + + } + do { - --i; + if (unlikely(afl->in_place_resume)) { --i; } struct stat st; u8 dfn[PATH_MAX]; @@ -801,18 +812,17 @@ void read_testcases(afl_state_t *afl, u8 *directory) { } - /* - if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { + if (unlikely(afl->in_place_resume)) { - u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, - HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE; - afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1; + if (unlikely(i == 0)) { done = 1; } - } + } else { + + if (unlikely(++i == (u32)nl_cnt)) { done = 1; } - */ + } - } while (i > 0); + } while (!done); } -- cgit 1.4.1 From bc969f78f634035abf88bc73a5076848660901e7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 Apr 2023 11:56:50 +0200 Subject: fixes --- afl-cmin.bash | 9 +++++++-- src/afl-fuzz-init.c | 7 ++++--- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/afl-cmin.bash b/afl-cmin.bash index ba7083fa..0e2d973d 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -316,12 +316,16 @@ if [ ! "$T_ARG" = "" ]; then if [ "$T_ARG" = "all" ]; then THREADS=$(nproc) else - if [ "$T_ARG" -gt 0 -a "$T_ARG" -le "$(nproc)" ]; then + if [ "$T_ARG" -gt 1 -a "$T_ARG" -le "$(nproc)" ]; then THREADS=$T_ARG else - echo "[-] Error: -T parameter must between 1 and $(nproc) or \"all\"." 1>&2 + echo "[-] Error: -T parameter must between 2 and $(nproc) or \"all\"." 1>&2 fi fi +else + if [ "$F_ARG" = ""]; then + echo "[*] Are you aware of the '-T all' parallelize option that massively improves the speed?" + fi fi IN_COUNT=$((`ls -- "$IN_DIR" 2>/dev/null | wc -l`)) @@ -332,6 +336,7 @@ if [ "$IN_COUNT" = "0" ]; then exit 1 fi +echo "[*] Are you aware that afl-cmin is faster than this afl-cmin.bash script?" echo "[+] Found $IN_COUNT files for minimizing." FIRST_FILE=`ls "$IN_DIR" | head -1` diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 002a26f8..bd591c8f 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -756,7 +756,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) { free(nl[i]); /* not tracked */ read_testcases(afl, fn2); ck_free(fn2); - continue; + goto next_entry; } @@ -765,7 +765,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) { if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { ck_free(fn2); - continue; + goto next_entry; } @@ -812,13 +812,14 @@ void read_testcases(afl_state_t *afl, u8 *directory) { } + next_entry: if (unlikely(afl->in_place_resume)) { if (unlikely(i == 0)) { done = 1; } } else { - if (unlikely(++i == (u32)nl_cnt)) { done = 1; } + if (unlikely(++i >= (u32)nl_cnt)) { done = 1; } } -- cgit 1.4.1 From d822181467ec41f1ee2d840c3c5b1918c72ffc86 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 Apr 2023 13:13:43 +0200 Subject: afl-cmin -T support --- afl-cmin | 143 ++++++++++++++++++++++++++++++++++++++++++------------ docs/Changelog.md | 2 +- src/afl-showmap.c | 23 +++++---- 3 files changed, 124 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/afl-cmin b/afl-cmin index 6b36c261..c8bbd8d7 100755 --- a/afl-cmin +++ b/afl-cmin @@ -103,9 +103,10 @@ function usage() { " -o dir - output directory for minimized files\n" \ "\n" \ "Execution control settings:\n" \ +" -T tasks - how many parallel tasks to run (default: 1, all=nproc)\n" \ " -f file - location read by the fuzzed program (stdin)\n" \ " -m megs - memory limit for child process ("mem_limit" MB)\n" \ -" -t msec - run time limit for child process (default: none)\n" \ +" -t msec - run time limit for child process (default: 5000)\n" \ " -O - use binary-only instrumentation (FRIDA mode)\n" \ " -Q - use binary-only instrumentation (QEMU mode)\n" \ " -U - use unicorn-based instrumentation (unicorn mode)\n" \ @@ -119,7 +120,6 @@ function usage() { "For additional tips, please consult README.md\n" \ "\n" \ "Environment variables used:\n" \ -"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \ "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \ "AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \ "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ @@ -159,13 +159,19 @@ BEGIN { # process options Opterr = 1 # default is to diagnose Optind = 1 # skip ARGV[0] - while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXY?")) != -1) { + while ((_go_c = getopt(ARGC, ARGV, "hi:o:f:m:t:eACOQUXYT:?")) != -1) { if (_go_c == "i") { if (!Optarg) usage() if (in_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} in_dir = Optarg continue } else + if (_go_c == "T") { + if (!Optarg) usage() + if (threads) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} + threads = Optarg + continue + } else if (_go_c == "o") { if (!Optarg) usage() if (out_dir) { print "Option "_go_c" is only allowed once" > "/dev/stderr"} @@ -253,21 +259,30 @@ BEGIN { # Do a sanity check to discourage the use of /tmp, since we can't really # handle this safely from an awk script. - if (!ENVIRON["AFL_ALLOW_TMP"]) { - dirlist[0] = in_dir - dirlist[1] = target_bin - dirlist[2] = out_dir - dirlist[3] = stdin_file - "pwd" | getline dirlist[4] # current directory - for (dirind in dirlist) { - dir = dirlist[dirind] - - if (dir ~ /^(\/var)?\/tmp/) { - print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr" - exit 1 - } - } - delete dirlist + #if (!ENVIRON["AFL_ALLOW_TMP"]) { + # dirlist[0] = in_dir + # dirlist[1] = target_bin + # dirlist[2] = out_dir + # dirlist[3] = stdin_file + # "pwd" | getline dirlist[4] # current directory + # for (dirind in dirlist) { + # dir = dirlist[dirind] + # + # if (dir ~ /^(\/var)?\/tmp/) { + # print "[-] Error: do not use this script in /tmp or /var/tmp." > "/dev/stderr" + # exit 1 + # } + # } + # delete dirlist + #} + + if (threads && stdin_file) { + print "[-] Error: -T and -f cannot be used together." > "/dev/stderr" + exit 1 + } + + if (!threads && !stdin_file) { + print "[*] Are you aware of the '-T all' parallelize option that massively improves the speed for large corpuses?" } # If @@ is specified, but there's no -f, let's come up with a temporary input @@ -350,6 +365,18 @@ BEGIN { exit 1 } + if (threads) { + "nproc" | getline nproc + if (threads == "all") { + threads = nproc + } else { + if (!(threads > 1 && threads <= nproc)) { + print "[-] Error: -T option must be between 1 and "nproc" or \"all\"." > "/dev/stderr" + exit 1 + } + } + } + # Check for the more efficient way to copy files... if (0 != system("mkdir -p -m 0700 "trace_dir)) { print "[-] Error: Cannot create directory "trace_dir > "/dev/stderr" @@ -459,27 +486,81 @@ BEGIN { # STEP 1: Collecting traces # ############################# + if (threads) { + + inputsperfile = in_count / threads + if (in_count % threads) { + inputsperfile++; + } + + cnt = 0; + tmpfile=out_dir "/.filelist" + for (instance = 1; instance < threads; instance++) { + for (i = 0; i < inputsperfile; i++) { + print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."instance + cnt++ + } + } + for (; cnt < in_count; cnt++) { + print in_dir"/"infilesSmallToBigFull[cnt] >> tmpfile"."threads + } + + print "ls -l "tmpfile"*" + + } + print "[*] Obtaining traces for "in_count" input files in '"in_dir"'." cur = 0; - if (!stdin_file) { - print " Processing "in_count" files (forkserver mode)..." -# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string - retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string) + + if (threads > 1) { + + print "[*] Creating " threads " parallel tasks with about " inputsperfile " each." + for (i = 1; i <= threads; i++) { + + if (!stdin_file) { +# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &" + retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -- \""target_bin"\" "prog_args_string"; > "tmpfile"."i".done ; } &") + } else { + stdin_file=tmpfile"."i".stdin" +# print " { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" "tmpfile"."i".done ; } &" + retval = system(" { "AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -I \""tmpfile"."i"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" "tmpfile"."i".done ; } &") + } + } + print "[*] Waiting for parallel tasks to complete ..." + # wait for all processes to finish + ok=0 + while (ok < threads) { + ok=0 + for (i = 1; i <= threads; i++) { + if (system("test -f "tmpfile"."i".done") == 0) { + ok++ + } + } + } + print "[*] Done!" + system("rm -f "tmpfile"*") } else { - print " Processing "in_count" files (forkserver mode)..." + if (!stdin_file) { + print " Processing "in_count" files (forkserver mode)..." +# print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string + retval = system(AFL_MAP_SIZE AFL_CMIN_ALLOW_ANY AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -- \""target_bin"\" "prog_args_string) + } else { + print " Processing "in_count" files (forkserver mode)..." # print AFL_CMIN_CRASHES_ONLY"\""showmap"\" -m "mem_limit" -t "timeout" -o \""trace_dir"\" -Z "extra_par" -i \""in_dir"\" -H \""stdin_file"\" -- \""target_bin"\" "prog_args_string" /dev/null") - system("rmdir "out_dir) + if (!ENVIRON["AFL_KEEP_TRACES"]) { + system("rm -rf "trace_dir" 2>/dev/null") + system("rmdir "out_dir) + } + exit retval } - exit retval + } ####################################################### diff --git a/docs/Changelog.md b/docs/Changelog.md index 816a864d..667fd634 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -14,7 +14,7 @@ - afl-showmap: - added custom mutator post_process and send support - add `-I filelist` option, an alternative to `-i in_dir` - - afl-cmin.bash: + - afl-cmin + afl-cmin.bash: - `-T threads` parallel task support, huge speedup! - a new grammar custom mutator atnwalk was submitted by @voidptr127 ! diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 09a1d2dc..d0e01cb1 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -894,9 +894,7 @@ u32 execute_testcases_filelist(u8 *fn) { while (fgets(buf, sizeof(buf), f) != NULL) { struct stat st; - - u8 *fn2 = buf, *fn3; - ; + u8 *fn2 = buf, *fn3; while (*fn2 == ' ') { @@ -904,14 +902,11 @@ u32 execute_testcases_filelist(u8 *fn) { } - if (*fn2) { - - while (fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' || - fn2[strlen(fn2) - 1] == ' ') { - - fn2[strlen(fn2) - 1] = 0; + while (*fn2 && + (fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' || + fn2[strlen(fn2) - 1] == ' ')) { - } + fn2[strlen(fn2) - 1] = 0; } @@ -926,6 +921,8 @@ u32 execute_testcases_filelist(u8 *fn) { } + ++done; + if (!S_ISREG(st.st_mode) || !st.st_size) { continue; } if ((fn3 = strrchr(fn2, '/'))) { @@ -946,9 +943,12 @@ u32 execute_testcases_filelist(u8 *fn) { } - if (!collect_coverage) + if (!collect_coverage) { + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, fn3); + } + if (read_file(fn2)) { if (wait_for_gdb) { @@ -961,7 +961,6 @@ u32 execute_testcases_filelist(u8 *fn) { showmap_run_target_forkserver(fsrv, in_data, in_len); ck_free(in_data); - ++done; if (child_crashed && debug) { WARNF("crashed: %s", fn2); } -- cgit 1.4.1 From 21865c622483d2e2285de3dfad4626c28ca27843 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 Apr 2023 16:47:37 +0200 Subject: rename env to AFL_IGNORE_PROBLEMS_COVERAGE --- docs/FAQ.md | 3 ++- docs/env_variables.md | 3 ++- include/envs.h | 1 + instrumentation/afl-compiler-rt.o.c | 4 ++-- src/afl-fuzz.c | 2 ++ 5 files changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/docs/FAQ.md b/docs/FAQ.md index 4a9080f8..76350c79 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -229,7 +229,8 @@ If you find an interesting or important question missing, submit it via If this is not a viable option, you can set `AFL_IGNORE_PROBLEMS=1` but then the existing map will be used also for the newly loaded libraries, which allows it to work, however, the efficiency of the fuzzing will be partially - degraded. + degraded. Note that there is additionally `AFL_IGNORE_PROBLEMS_COVERAGE` to + additionally tell AFL++ to ignore any coverage from the late loaded libaries.

diff --git a/docs/env_variables.md b/docs/env_variables.md index 087ccdb7..b1f23159 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -406,7 +406,8 @@ checks or alter some of the more exotic semantics of the tool: - If afl-fuzz encounters an incorrect fuzzing setup during a fuzzing session (not at startup), it will terminate. If you do not want this, then you can - set `AFL_IGNORE_PROBLEMS`. + set `AFL_IGNORE_PROBLEMS`. If you additionally want to also ignore coverage + from late loaded libraries, you can set `AFL_IGNORE_PROBLEMS_COVERAGE`. - When running in the `-M` or `-S` mode, setting `AFL_IMPORT_FIRST` causes the fuzzer to import test cases from other instances before doing anything else. diff --git a/include/envs.h b/include/envs.h index 5e68c80b..fe5ee0e3 100644 --- a/include/envs.h +++ b/include/envs.h @@ -106,6 +106,7 @@ static char *afl_environment_variables[] = { "AFL_HARDEN", "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES", "AFL_IGNORE_PROBLEMS", + "AFL_IGNORE_PROBLEMS_COVERAGE", "AFL_IGNORE_TIMEOUTS", "AFL_IGNORE_UNKNOWN_ENVS", "AFL_IMPORT_FIRST", diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 74506e4c..0912e52b 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1565,13 +1565,13 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { "be able to fuzz them or LD_PRELOAD to run outside of afl-fuzz.\n" "To ignore this set AFL_IGNORE_PROBLEMS=1 but this will lead to " "ambiguous coverage data.\n" - "In addition, you can set AFL_LLVM_IGNORE_PROBLEMS_COVERAGE=1 to " + "In addition, you can set AFL_IGNORE_PROBLEMS_COVERAGE=1 to " "ignore the additional coverage instead (use with caution!).\n"); abort(); } else { - u8 ignore_dso_after_fs = !!getenv("AFL_LLVM_IGNORE_PROBLEMS_COVERAGE"); + u8 ignore_dso_after_fs = !!getenv("AFL_IGNORE_PROBLEMS_COVERAGE"); if (__afl_debug && ignore_dso_after_fs) { fprintf(stderr, "Ignoring coverage from dynamically loaded code\n"); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index ebdbb3fa..c44144f5 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -259,6 +259,8 @@ static void usage(u8 *argv0, int more_help) { "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n" "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n" "AFL_IGNORE_PROBLEMS: do not abort fuzzing if an incorrect setup is detected\n" + "AFL_IGNORE_PROBLEMS_COVERAGE: if set in addition to AFL_IGNORE_PROBLEMS - also\n + " ignore those libs for coverage\n" "AFL_IGNORE_TIMEOUTS: do not process or save any timeouts\n" "AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n" "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n" -- cgit 1.4.1 From 96848398d45e08eaa69be245c986375808d2b3a7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 Apr 2023 17:56:36 +0200 Subject: fix --- src/afl-fuzz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index c44144f5..71d2afd8 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -259,7 +259,7 @@ static void usage(u8 *argv0, int more_help) { "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n" "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n" "AFL_IGNORE_PROBLEMS: do not abort fuzzing if an incorrect setup is detected\n" - "AFL_IGNORE_PROBLEMS_COVERAGE: if set in addition to AFL_IGNORE_PROBLEMS - also\n + "AFL_IGNORE_PROBLEMS_COVERAGE: if set in addition to AFL_IGNORE_PROBLEMS - also\n" " ignore those libs for coverage\n" "AFL_IGNORE_TIMEOUTS: do not process or save any timeouts\n" "AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n" -- cgit 1.4.1 From 3e84d6a2ae7df5f6b9073a91ccc6acef50b45aab Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 27 Apr 2023 11:49:00 +0200 Subject: afl++ -> AFL++ --- Dockerfile | 4 ++-- GNUmakefile | 12 ++++++------ GNUmakefile.gcc_plugin | 6 +++--- GNUmakefile.llvm | 6 +++--- afl-cmin | 2 +- docs/Changelog.md | 2 +- docs/INSTALL.md | 2 +- include/alloc-inl.h | 2 +- instrumentation/SanitizerCoverageLTO.so.cc | 30 +++++++++++++++--------------- instrumentation/afl-llvm-common.cc | 2 +- instrumentation/afl-llvm-dict2file.so.cc | 2 +- qemu_mode/build_qemu_support.sh | 4 ++-- src/afl-cc.c | 2 +- src/afl-forkserver.c | 6 +++--- src/afl-fuzz.c | 10 +++++----- src/afl-ld-lto.c | 4 ++-- test/test-dlopen.c | 2 +- test/test-gcc-plugin.sh | 2 +- test/test-performance.sh | 4 ++-- test/test-pre.sh | 2 +- unicorn_mode/build_unicorn_support.sh | 2 +- 21 files changed, 54 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/Dockerfile b/Dockerfile index 4e53de40..1b5ffd28 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ # FROM ubuntu:22.04 AS aflplusplus -LABEL "maintainer"="afl++ team " +LABEL "maintainer"="AFL++ team " LABEL "about"="AFLplusplus container image" ### Comment out to enable these features @@ -94,4 +94,4 @@ RUN sed -i.bak 's/^ -/ /g' GNUmakefile && \ RUN echo "set encoding=utf-8" > /root/.vimrc && \ echo ". /etc/bash_completion" >> ~/.bashrc && \ echo 'alias joe="joe --wordwrap --joe_state -nobackup"' >> ~/.bashrc && \ - echo "export PS1='"'[afl++ \h] \w \$ '"'" >> ~/.bashrc + echo "export PS1='"'[AFL++ \h] \w \$ '"'" >> ~/.bashrc diff --git a/GNUmakefile b/GNUmakefile index 23cae65d..5900ad61 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -39,7 +39,7 @@ ASAN_OPTIONS=detect_leaks=0 SYS = $(shell uname -s) ARCH = $(shell uname -m) -$(info [*] Compiling afl++ for OS $(SYS) on ARCH $(ARCH)) +$(info [*] Compiling AFL++ for OS $(SYS) on ARCH $(ARCH)) ifdef NO_SPLICING override CFLAGS_OPT += -DNO_SPLICING @@ -359,7 +359,7 @@ performance-test: source-only help: @echo "HELP --- the following make targets exist:" @echo "==========================================" - @echo "all: the main afl++ binaries and llvm/gcc instrumentation" + @echo "all: the main AFL++ binaries and llvm/gcc instrumentation" @echo "binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode, qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator, libtokencap" @echo "source-only: everything for source code fuzzing: nyx_mode, libdislocator, libtokencap" @echo "distrib: everything (for both binary-only and source code fuzzing)" @@ -367,7 +367,7 @@ help: @echo "install: installs everything you have compiled with the build option above" @echo "clean: cleans everything compiled (not downloads when on a checkout)" @echo "deepclean: cleans everything including downloads" - @echo "uninstall: uninstall afl++ from the system" + @echo "uninstall: uninstall AFL++ from the system" @echo "code-format: format the code, do this before you commit and send a PR please!" @echo "tests: this runs the test framework. It is more catered for the developers, but if you run into problems this helps pinpointing the problem" @echo "unit: perform unit tests (based on cmocka and GNU linker)" @@ -749,7 +749,7 @@ endif @echo %.8: % - @echo .TH $* 8 $(BUILD_DATE) "afl++" > $@ + @echo .TH $* 8 $(BUILD_DATE) "AFL++" > $@ @echo .SH NAME >> $@ @echo .B $* >> $@ @echo >> $@ @@ -761,8 +761,8 @@ endif @./$* -hh 2>&1 | tail -n +4 >> $@ @echo >> $@ @echo .SH AUTHOR >> $@ - @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse , Heiko \"hexcoder-\" Eissfeldt , Andrea Fioraldi and Dominik Maier " >> $@ - @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> $@ + @echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse , Dominik Maier , Andrea Fioraldi and Heiko \"hexcoder-\" Eissfeldt " >> $@ + @echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> $@ @echo >> $@ @echo .SH LICENSE >> $@ @echo Apache License Version 2.0, January 2004 >> $@ diff --git a/GNUmakefile.gcc_plugin b/GNUmakefile.gcc_plugin index 4c4e10c4..41face4c 100644 --- a/GNUmakefile.gcc_plugin +++ b/GNUmakefile.gcc_plugin @@ -175,7 +175,7 @@ all_done: test_build .NOTPARALLEL: clean %.8: % - @echo .TH $* 8 `date "+%Y-%m-%d"` "afl++" > ./$@ + @echo .TH $* 8 `date "+%Y-%m-%d"` "AFL++" > ./$@ @echo .SH NAME >> ./$@ @echo .B $* >> ./$@ @echo >> ./$@ @@ -187,8 +187,8 @@ all_done: test_build @./$* -h 2>&1 | tail -n +4 >> ./$@ @echo >> ./$@ @echo .SH AUTHOR >> ./$@ - @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse , Heiko \"hexcoder-\" Eissfeldt , Andrea Fioraldi and Dominik Maier " >> ./$@ - @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@ + @echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse , Dominik Maier , Andrea Fioraldi and Heiko \"hexcoder-\" Eissfeldt " >> ./$@ + @echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@ @echo >> ./$@ @echo .SH LICENSE >> ./$@ @echo Apache License Version 2.0, January 2004 >> ./$@ diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index a053403b..c1b006ba 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -510,7 +510,7 @@ install: all install -m 644 instrumentation/README.*.md $${DESTDIR}$(DOC_PATH)/ %.8: % - @echo .TH $* 8 $(BUILD_DATE) "afl++" > ./$@ + @echo .TH $* 8 $(BUILD_DATE) "AFL++" > ./$@ @echo .SH NAME >> ./$@ @printf "%s" ".B $* \- " >> ./$@ @./$* -h 2>&1 | head -n 1 | sed -e "s/$$(printf '\e')[^m]*m//g" >> ./$@ @@ -524,8 +524,8 @@ install: all @./$* -h 2>&1 | tail -n +4 >> ./$@ @echo >> ./$@ @echo .SH AUTHOR >> ./$@ - @echo "afl++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse , Heiko \"hexcoder-\" Eissfeldt , Andrea Fioraldi and Dominik Maier " >> ./$@ - @echo The homepage of afl++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@ + @echo "AFL++ was written by Michal \"lcamtuf\" Zalewski and is maintained by Marc \"van Hauser\" Heuse , Dominik Maier , Andrea Fioraldi and Heiko \"hexcoder-\" Eissfeldt " >> ./$@ + @echo The homepage of AFL++ is: https://github.com/AFLplusplus/AFLplusplus >> ./$@ @echo >> ./$@ @echo .SH LICENSE >> ./$@ @echo Apache License Version 2.0, January 2004 >> ./$@ diff --git a/afl-cmin b/afl-cmin index 63cfdd7e..ae723c1b 100755 --- a/afl-cmin +++ b/afl-cmin @@ -149,7 +149,7 @@ BEGIN { redirected = 0 } - print "corpus minimization tool for afl++ (awk version)\n" + print "corpus minimization tool for AFL++ (awk version)\n" # defaults extra_par = "" diff --git a/docs/Changelog.md b/docs/Changelog.md index 20b915fa..cd5ed9fc 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -229,7 +229,7 @@ afl-showmap and other tools. - afl-cc: - detect overflow reads on initial input buffer for asan - - new cmplog mode (incompatible with older afl++ versions) + - new cmplog mode (incompatible with older AFL++ versions) - support llvm IR select instrumentation for default PCGUARD and LTO - fix for shared linking on MacOS - better selective instrumentation AFL_LLVM_{ALLOW|DENY}LIST diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 591b7ded..c54cb9ad 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -51,7 +51,7 @@ make source-only These build targets exist: -* all: the main afl++ binaries and llvm/gcc instrumentation +* all: the main AFL++ binaries and llvm/gcc instrumentation * binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode, qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator, libtokencap diff --git a/include/alloc-inl.h b/include/alloc-inl.h index ae37028e..bbb42e88 100644 --- a/include/alloc-inl.h +++ b/include/alloc-inl.h @@ -42,7 +42,7 @@ // Be careful! _WANT_ORIGINAL_AFL_ALLOC is not compatible with custom mutators #ifndef _WANT_ORIGINAL_AFL_ALLOC - // afl++ stuff without memory corruption checks - for speed + // AFL++ stuff without memory corruption checks - for speed /* User-facing macro to sprintf() to a dynamically allocated buffer. */ diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 42583f9e..6a719737 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1,4 +1,4 @@ -/* SanitizeCoverage.cpp ported to afl++ LTO :-) */ +/* SanitizeCoverage.cpp ported to AFL++ LTO :-) */ #define AFL_LLVM_PASS @@ -234,7 +234,7 @@ class ModuleSanitizerCoverageLTO SanitizerCoverageOptions Options; - // afl++ START + // AFL++ START // const SpecialCaseList * Allowlist; // const SpecialCaseList * Blocklist; uint32_t autodictionary = 1; @@ -260,7 +260,7 @@ class ModuleSanitizerCoverageLTO Value *MapPtrFixed = NULL; std::ofstream dFile; size_t found = 0; - // afl++ END + // AFL++ END }; @@ -404,7 +404,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( Int8Ty = IRB.getInt8Ty(); Int1Ty = IRB.getInt1Ty(); - /* afl++ START */ + /* AFL++ START */ char *ptr; LLVMContext &Ctx = M.getContext(); Ct = &Ctx; @@ -978,7 +978,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( } - // afl++ END + // AFL++ END SanCovTracePCIndir = M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy); @@ -1002,7 +1002,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( for (auto &F : M) instrumentFunction(F, DTCallback, PDTCallback); - // afl++ START + // AFL++ START if (dFile.is_open()) dFile.close(); if (!getenv("AFL_LLVM_LTO_SKIPINIT") && @@ -1156,7 +1156,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( } - // afl++ END + // AFL++ END // We don't reference these arrays directly in any of our runtime functions, // so we need to prevent them from being dead stripped. @@ -1213,10 +1213,10 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, // (catchswitch blocks). if (BB->getFirstInsertionPt() == BB->end()) return false; - // afl++ START + // AFL++ START if (!Options.NoPrune && &F.getEntryBlock() == BB && F.size() > 1) return false; - // afl++ END + // AFL++ END if (Options.NoPrune || &F.getEntryBlock() == BB) return true; @@ -1258,10 +1258,10 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( // if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName())) // return; - // afl++ START + // AFL++ START if (!F.size()) return; if (!isInInstrumentList(&F, FMNAME)) return; - // afl++ END + // AFL++ END if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge) SplitAllCriticalEdges( @@ -1559,7 +1559,7 @@ bool ModuleSanitizerCoverageLTO::InjectCoverage( for (size_t i = 0, N = AllBlocks.size(); i < N; i++) { - // afl++ START + // AFL++ START if (BlockList.size()) { int skip = 0; @@ -1581,7 +1581,7 @@ bool ModuleSanitizerCoverageLTO::InjectCoverage( } - // afl++ END + // AFL++ END InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc); @@ -1647,7 +1647,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F, if (Options.TracePCGuard) { - // afl++ START + // AFL++ START ++afl_global_id; if (dFile.is_open()) { @@ -1711,7 +1711,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F, // done :) inst++; - // afl++ END + // AFL++ END /* XXXXXXXXXXXXXXXXXXX diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc index 5d82aa25..7f17b02d 100644 --- a/instrumentation/afl-llvm-common.cc +++ b/instrumentation/afl-llvm-common.cc @@ -584,7 +584,7 @@ bool isInInstrumentList(llvm::Function *F, std::string Filename) { } // Calculate the number of average collisions that would occur if all -// location IDs would be assigned randomly (like normal afl/afl++). +// location IDs would be assigned randomly (like normal afl/AFL++). // This uses the "balls in bins" algorithm. unsigned long long int calculateCollisions(uint32_t edges) { diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index 97f1d47f..cf368e35 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -744,7 +744,7 @@ static void registerAFLdict2filePass(const PassManagerBuilder &, } static RegisterPass X("afl-dict2file", - "afl++ dict2file instrumentation pass", + "AFL++ dict2file instrumentation pass", false, false); static RegisterStandardPasses RegisterAFLdict2filePass( diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index a064fe58..f59cba78 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -356,7 +356,7 @@ fi if ! command -v "$CROSS" > /dev/null ; then if [ "$CPU_TARGET" = "$(uname -m)" ] ; then - echo "[+] Building afl++ qemu support libraries with CC=$CC" + echo "[+] Building AFL++ qemu support libraries with CC=$CC" echo "[+] Building libcompcov ..." make -C libcompcov && echo "[+] libcompcov ready" echo "[+] Building unsigaction ..." @@ -371,7 +371,7 @@ if ! command -v "$CROSS" > /dev/null ; then echo "[!] Cross compiler $CROSS could not be found, cannot compile libcompcov libqasan and unsigaction" fi else - echo "[+] Building afl++ qemu support libraries with CC=\"$CROSS $CROSS_FLAGS\"" + echo "[+] Building AFL++ qemu support libraries with CC=\"$CROSS $CROSS_FLAGS\"" echo "[+] Building libcompcov ..." make -C libcompcov CC="$CROSS $CROSS_FLAGS" && echo "[+] libcompcov ready" echo "[+] Building unsigaction ..." diff --git a/src/afl-cc.c b/src/afl-cc.c index d1001187..99ce39d4 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -642,7 +642,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { } //#if LLVM_MAJOR >= 13 - // // Use the old pass manager in LLVM 14 which the afl++ passes still + // // Use the old pass manager in LLVM 14 which the AFL++ passes still // use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager"; //#endif diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index aa8c8622..30c8901c 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -489,7 +489,7 @@ static void report_error_and_exit(int error) { break; case FS_ERROR_OLD_CMPLOG: FATAL( - "the -c cmplog target was instrumented with an too old afl++ " + "the -c cmplog target was instrumented with an too old AFL++ " "version, you need to recompile it."); break; case FS_ERROR_OLD_CMPLOG_QEMU: @@ -987,7 +987,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { - // workaround for recent afl++ versions + // workaround for recent AFL++ versions if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND) status = (status & 0xf0ffffff); @@ -1059,7 +1059,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, FATAL( "Target's coverage map size of %u is larger than the one this " - "afl++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart " + "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart " " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile " "afl-fuzz", tmp_map_size, fsrv->map_size, tmp_map_size); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 71d2afd8..646dc50b 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1280,16 +1280,16 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260; - OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" " - "Eißfeldt, Andrea Fioraldi and Dominik Maier"); - OKF("afl++ is open source, get it at " + OKF("AFL++ is maintained by Marc \"van Hauser\" Heuse, Dominik Maier, Andrea " + "Fioraldi and Heiko \"hexcoder\" Eißfeldt"); + OKF("AFL++ is open source, get it at " "https://github.com/AFLplusplus/AFLplusplus"); - OKF("NOTE: afl++ >= v3 has changed defaults and behaviours - see README.md"); + OKF("NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md"); #ifdef __linux__ if (afl->fsrv.nyx_mode) { - OKF("afl++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)"); + OKF("AFL++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)"); OKF("Nyx is open source, get it at https://github.com/Nyx-Fuzz"); } diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c index 5438bd9f..420dd817 100644 --- a/src/afl-ld-lto.c +++ b/src/afl-ld-lto.c @@ -2,7 +2,7 @@ american fuzzy lop++ - wrapper for llvm 11+ lld ----------------------------------------------- - Written by Marc Heuse for afl++ + Written by Marc Heuse for AFL++ Maintained by Marc Heuse , Heiko Eißfeldt @@ -210,7 +210,7 @@ static void edit_params(int argc, char **argv) { if (strcmp(argv[i], "--afl") == 0) { - if (!be_quiet) OKF("afl++ test command line flag detected, exiting."); + if (!be_quiet) OKF("AFL++ test command line flag detected, exiting."); exit(0); } diff --git a/test/test-dlopen.c b/test/test-dlopen.c index b81bab13..39442f93 100644 --- a/test/test-dlopen.c +++ b/test/test-dlopen.c @@ -28,7 +28,7 @@ int main(int argc, char **argv) { } - // must use deferred forkserver as otherwise afl++ instrumentation aborts + // must use deferred forkserver as otherwise AFL++ instrumentation aborts // because all dlopen() of instrumented libs must be before the forkserver __AFL_INIT(); diff --git a/test/test-gcc-plugin.sh b/test/test-gcc-plugin.sh index 54e6987f..3690a80a 100755 --- a/test/test-gcc-plugin.sh +++ b/test/test-gcc-plugin.sh @@ -23,7 +23,7 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && { $ECHO "$GREEN[+] gcc_plugin run reported $TUPLES instrumented locations which is fine" } || { $ECHO "$RED[!] gcc_plugin instrumentation produces a weird numbers: $TUPLES" - $ECHO "$YELLOW[-] this is a known issue in gcc, not afl++. It is not flagged as an error because travis builds would all fail otherwise :-(" + $ECHO "$YELLOW[-] this is a known issue in gcc, not AFL++. It is not flagged as an error because travis builds would all fail otherwise :-(" #CODE=1 } test "$TUPLES" -lt 2 && SKIP=1 diff --git a/test/test-performance.sh b/test/test-performance.sh index d61e2f2a..50957141 100755 --- a/test/test-performance.sh +++ b/test/test-performance.sh @@ -7,7 +7,7 @@ FILE=$AFL_PERFORMANCE_FILE test -z "$FILE" && FILE=.afl_performance test -e $FILE || { - echo Warning: This script measure the performance of afl++ and saves the result for future comparisons into $FILE + echo Warning: This script measure the performance of AFL++ and saves the result for future comparisons into $FILE echo Press ENTER to continue or CONTROL-C to abort read IN } @@ -74,7 +74,7 @@ afl-system-config > /dev/null 2>&1 echo Performance settings applied. echo -$ECHO "${RESET}${GREY}[*] starting afl++ performance test framework ..." +$ECHO "${RESET}${GREY}[*] starting AFL++ performance test framework ..." $ECHO "$BLUE[*] Testing: ${AFL_GCC}" GCC=x diff --git a/test/test-pre.sh b/test/test-pre.sh index b8b286e5..1ca9dfb5 100755 --- a/test/test-pre.sh +++ b/test/test-pre.sh @@ -133,7 +133,7 @@ MEM_LIMIT=none export PATH="${PATH}:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin" -$ECHO "${RESET}${GREY}[*] starting afl++ test framework ..." +$ECHO "${RESET}${GREY}[*] starting AFL++ test framework ..." test -z "$SYS" && $ECHO "$YELLOW[-] uname -m did not succeed" diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh index 53ec2481..d3d16ad5 100755 --- a/unicorn_mode/build_unicorn_support.sh +++ b/unicorn_mode/build_unicorn_support.sh @@ -182,7 +182,7 @@ git pull sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null git checkout "$UNICORNAFL_VERSION" || exit 1 -echo "[*] making sure afl++ header files match" +echo "[*] making sure AFL++ header files match" cp "../../include/config.h" "./include" || exit 1 echo "[*] Configuring Unicorn build..." -- cgit 1.4.1 From e983e2e9cfb9e4c8489dc35f28bca502ec241c27 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 27 Apr 2023 16:24:43 +0200 Subject: more debug --- src/afl-fuzz-init.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index bd591c8f..baf56a5f 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -716,6 +716,8 @@ void read_testcases(afl_state_t *afl, u8 *directory) { } + // if (getenv("MYTEST")) afl->in_place_resume = 1; + if (nl_cnt) { u32 done = 0; @@ -827,6 +829,8 @@ void read_testcases(afl_state_t *afl, u8 *directory) { } + // if (getenv("MYTEST")) afl->in_place_resume = 0; + free(nl); /* not tracked */ if (!afl->queued_items && directory == NULL) { @@ -908,8 +912,10 @@ void perform_dry_run(afl_state_t *afl) { if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) { - SAYF(cGRA " len = %u, map size = %u, exec speed = %llu us\n" cRST, - q->len, q->bitmap_size, q->exec_us); + SAYF(cGRA + " len = %u, map size = %u, exec speed = %llu us, hash = " + "%016llx\n" cRST, + q->len, q->bitmap_size, q->exec_us, q->exec_cksum); } @@ -1164,14 +1170,14 @@ void perform_dry_run(afl_state_t *afl) { u32 duplicates = 0, i; - for (idx = 0; idx < afl->queued_items; idx++) { + for (idx = 0; idx < afl->queued_items - 1; idx++) { q = afl->queue_buf[idx]; if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; } - u32 done = 0; + for (i = idx + 1; - i < afl->queued_items && !done && likely(afl->queue_buf[i]); i++) { + likely(i < afl->queued_items && afl->queue_buf[i] && !done); ++i) { struct queue_entry *p = afl->queue_buf[i]; if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; } @@ -1194,6 +1200,13 @@ void perform_dry_run(afl_state_t *afl) { p->disabled = 1; p->perf_score = 0; + if (afl->debug) { + + WARNF("Same coverage - %s is kept active, %s is disabled.", + q->fname, p->fname); + + } + } else { if (!q->was_fuzzed) { @@ -1207,7 +1220,14 @@ void perform_dry_run(afl_state_t *afl) { q->disabled = 1; q->perf_score = 0; - done = 1; + if (afl->debug) { + + WARNF("Same coverage - %s is kept active, %s is disabled.", + p->fname, q->fname); + + } + + done = 1; // end inner loop because outer loop entry is disabled now } -- cgit 1.4.1 From a2daef29f9c323c0a6a7a64013aadb79ffd3e534 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 27 Apr 2023 17:57:22 +0200 Subject: slightly different weighting algo (#1719) * better seed selection * slightly different weighting calculation * remove unnecessary memset --- include/afl-fuzz.h | 4 +-- src/afl-fuzz-queue.c | 92 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 831a0dbc..8fb7ecb1 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1223,7 +1223,7 @@ double rand_next_percent(afl_state_t *afl); static inline u32 rand_below(afl_state_t *afl, u32 limit) { - if (limit <= 1) return 0; + if (unlikely(limit <= 1)) return 0; /* The boundary not being necessarily a power of 2, we need to ensure the result uniformity. */ @@ -1256,7 +1256,7 @@ static inline u32 rand_below(afl_state_t *afl, u32 limit) { expand havoc mode */ static inline u32 rand_below_datalen(afl_state_t *afl, u32 limit) { - if (limit <= 1) return 0; + if (unlikely(limit <= 1)) return 0; switch (rand_below(afl, 3)) { diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 8ad7cd97..b10bf749 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -49,11 +49,13 @@ inline u32 select_next_queue_entry(afl_state_t *afl) { u32 s = rand_below(afl, afl->queued_items); double p = rand_next_percent(afl); + /* fprintf(stderr, "select: p=%f s=%u ... p < prob[s]=%f ? s=%u : alias[%u]=%u" " ==> %u\n", p, s, afl->alias_probability[s], s, s, afl->alias_table[s], p < afl->alias_probability[s] ? s : afl->alias_table[s]); */ + return (p < afl->alias_probability[s] ? s : afl->alias_table[s]); } @@ -87,25 +89,28 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q, void create_alias_table(afl_state_t *afl) { - u32 n = afl->queued_items, i = 0, a, g; + u32 n = afl->queued_items, i = 0, nSmall = 0, nLarge = n - 1; double sum = 0; + double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double)); + u32 *Small = (int *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32)); + u32 *Large = (int *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32)); + afl->alias_table = (u32 *)afl_realloc((void **)&afl->alias_table, n * sizeof(u32)); afl->alias_probability = (double *)afl_realloc( (void **)&afl->alias_probability, n * sizeof(double)); - double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double)); - int *S = (int *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32)); - int *L = (int *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32)); - if (!P || !S || !L || !afl->alias_table || !afl->alias_probability) { + if (!P || !Small || !Large || !afl->alias_table || !afl->alias_probability) { FATAL("could not acquire memory for alias table"); } - memset((void *)afl->alias_table, 0, n * sizeof(u32)); memset((void *)afl->alias_probability, 0, n * sizeof(double)); + memset((void *)afl->alias_table, 0, n * sizeof(u32)); + memset((void *)Small, 0, n * sizeof(u32)); + memset((void *)Large, 0, n * sizeof(u32)); if (likely(afl->schedule < RARE)) { @@ -166,7 +171,15 @@ void create_alias_table(afl_state_t *afl) { for (i = 0; i < n; i++) { // weight is always 0 for disabled entries - P[i] = (afl->queue_buf[i]->weight * n) / sum; + if (unlikely(afl->queue_buf[i]->disabled)) { + + P[i] = 0; + + } else { + + P[i] = (afl->queue_buf[i]->weight * n) / sum; + + } } @@ -176,60 +189,81 @@ void create_alias_table(afl_state_t *afl) { struct queue_entry *q = afl->queue_buf[i]; - if (likely(!q->disabled)) { q->perf_score = calculate_score(afl, q); } + if (likely(!q->disabled)) { + + q->perf_score = calculate_score(afl, q); + sum += q->perf_score; - sum += q->perf_score; + } } for (i = 0; i < n; i++) { // perf_score is always 0 for disabled entries - P[i] = (afl->queue_buf[i]->perf_score * n) / sum; + if (unlikely(afl->queue_buf[i]->disabled)) { + + P[i] = 0; + + } else { + + P[i] = (afl->queue_buf[i]->perf_score * n) / sum; + + } } } - int nS = 0, nL = 0, s; - for (s = (s32)n - 1; s >= 0; --s) { + // Done collecting weightings in P, now create the arrays. + + for (s32 j = (s32)(n - 1); j >= 0; j--) { - if (P[s] < 1) { + if (P[j] < 1) { - S[nS++] = s; + Small[nSmall++] = (u32)j; } else { - L[nL++] = s; + Large[nLarge--] = (u32)j; } } - while (nS && nL) { + while (nSmall && nLarge != n - 1) { + + u32 small = Small[--nSmall]; + u32 large = Large[++nLarge]; + + afl->alias_probability[small] = P[small]; + afl->alias_table[small] = large; - a = S[--nS]; - g = L[--nL]; - afl->alias_probability[a] = P[a]; - afl->alias_table[a] = g; - P[g] = P[g] + P[a] - 1; - if (P[g] < 1) { + P[large] = P[large] - (1 - P[small]); - S[nS++] = g; + if (P[large] < 1) { + + Small[nSmall++] = large; } else { - L[nL++] = g; + Large[nLarge--] = large; } } - while (nL) - afl->alias_probability[L[--nL]] = 1; + while (nSmall) { + + afl->alias_probability[Small[--nSmall]] = 1; + + } - while (nS) - afl->alias_probability[S[--nS]] = 1; + while (nLarge != n - 1) { + + afl->alias_probability[Large[++nLarge]] = 1; + + } afl->reinit_table = 0; @@ -264,7 +298,7 @@ void create_alias_table(afl_state_t *afl) { */ /* fprintf(stderr, " entry alias probability perf_score weight - filename\n"); for (u32 i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u + filename\n"); for (i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u %0.9f %0.9f %s\n", i, afl->alias_table[i], afl->alias_probability[i], afl->queue_buf[i]->perf_score, afl->queue_buf[i]->weight, afl->queue_buf[i]->fname); -- cgit 1.4.1 From 6cad585bdc5c335cc2894c97e9aaf6d5fff88e1f Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 27 Apr 2023 18:57:28 +0200 Subject: nits --- src/afl-showmap.c | 2 +- test/test-llvm.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index d0e01cb1..f60acb2d 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1287,7 +1287,7 @@ int main(int argc, char **argv_orig, char **envp) { break; - case 'Y': // fallthough + case 'Y': // fallthrough #ifdef __linux__ case 'X': /* NYX mode */ diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 0e66cc97..714bda93 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -263,7 +263,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { { mkdir -p in echo 00000000000000000000000000000000 > in/in - AFL_BENCH_UNTIL_CRASH=1 ../afl-fuzz -m none -V15 -i in -o out -c./test-cmplog -- ./test-c >>errors 2>&1 + AFL_BENCH_UNTIL_CRASH=1 ../afl-fuzz -m none -V30 -i in -o out -c./test-cmplog -- ./test-c >>errors 2>&1 } >>errors 2>&1 test -n "$( ls out/default/crashes/id:000000* out/default/hangs/id:000000* 2>/dev/null )" && { $ECHO "$GREEN[+] afl-fuzz is working correctly with llvm_mode cmplog" -- cgit 1.4.1 From 41b0fe7280372031753fc5f11b9a03b214189155 Mon Sep 17 00:00:00 2001 From: Nick Potenski Date: Thu, 27 Apr 2023 11:57:55 -0500 Subject: afl-showmap: Start a only a single fork server (#1718) A forkserver is started by afl_fsrv_get_mapsize() when dynamically finding the map size. When an input directory option is specified a second fork server was also started. This commit re-arranges the inits for several forkserver struct members so that we can re-use the server started by the get_mapsize() call when not in coresight/qemu/unicorn modes and just start the server otherwise. --- src/afl-showmap.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/afl-showmap.c b/src/afl-showmap.c index f60acb2d..9c029035 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -1421,6 +1421,14 @@ int main(int argc, char **argv_orig, char **envp) { // If @@ are in the target args, replace them and also set use_stdin=false. detect_file_args(argv + optind, stdin_file, &fsrv->use_stdin); + fsrv->dev_null_fd = open("/dev/null", O_RDWR); + if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } + + fsrv->out_file = stdin_file; + fsrv->out_fd = + open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", stdin_file); } + } else { // If @@ are in the target args, replace them and also set use_stdin=false. @@ -1588,6 +1596,14 @@ int main(int argc, char **argv_orig, char **envp) { fsrv->map_size = map_size; + } else { + + afl_fsrv_start(fsrv, use_argv, &stop_soon, + (get_afl_env("AFL_DEBUG_CHILD") || + get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) + ? 1 + : 0); + } if (in_dir || in_filelist) { @@ -1617,9 +1633,6 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; - fsrv->dev_null_fd = open("/dev/null", O_RDWR); - if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } - if (in_filelist) { if (!be_quiet) ACTF("Reading from file list '%s'...", in_filelist); @@ -1666,10 +1679,6 @@ int main(int argc, char **argv_orig, char **envp) { } atexit(at_exit_handler); - fsrv->out_file = stdin_file; - fsrv->out_fd = - open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); - if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); } if (get_afl_env("AFL_DEBUG")) { @@ -1685,12 +1694,6 @@ int main(int argc, char **argv_orig, char **envp) { } - afl_fsrv_start(fsrv, use_argv, &stop_soon, - (get_afl_env("AFL_DEBUG_CHILD") || - get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) - ? 1 - : 0); - map_size = fsrv->map_size; if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) -- cgit 1.4.1 From e956f23a77b776a5c11344889503c833adbf1052 Mon Sep 17 00:00:00 2001 From: "Christian Holler (:decoder)" Date: Fri, 28 Apr 2023 11:35:22 +0200 Subject: Source Code Coverage support for Nyx (Part 1) (#1720) * Additional source code reformatting in afl-compiler-rt * Add source code coverage support to afl-compiler-rt (for use with Nyx) --- GNUmakefile.llvm | 5 + instrumentation/README.llvm.md | 24 ++++ instrumentation/afl-compiler-rt.o.c | 261 +++++++++++++++++++++++++++++++++++- src/afl-cc.c | 26 +++- 4 files changed, 308 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index c1b006ba..2bb4e7f8 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -274,6 +274,11 @@ ifndef LLVM_DEBUG CFLAGS_SAFE += -Wno-deprecated endif +ifdef CODE_COVERAGE + override CFLAGS_SAFE += -D__AFL_CODE_COVERAGE=1 + override LDFLAGS += -ldl +endif + override CFLAGS += $(CFLAGS_SAFE) ifdef AFL_TRACE_PC diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index c0677474..126cf1a2 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -280,3 +280,27 @@ Please note that the default counter implementations are not thread safe! Support for thread safe counters in mode LLVM CLASSIC can be activated with setting `AFL_LLVM_THREADSAFE_INST=1`. + +## 8) Source code coverage through instrumentation + +Measuring source code coverage is a common task in fuzzing, but it is very +difficut to do in some situations (e.g. when using snapshot fuzzing). + +When using the `AFL_LLVM_INSTRUMENT=llvm-codecov` option, afl-cc will use +native trace-pc-guard instrumentation but additionally select options that +are required to utilize the instrumentation for source code coverage. + +In particular, it will switch the instrumentation to be per basic block +instead of instrumenting edges, disable all guard pruning and enable the +experimental pc-table support that allows the runtime to gather 100% of +instrumented basic blocks at start, including their locations. + +Note: You must compile AFL with the `CODE_COVERAGE=1` option to enable the +respective parts in the AFL compiler runtime. Support is currently only +implemented for Nyx, but can in theory also work without Nyx. + +Note: You might have to adjust `MAP_SIZE_POW2` in include/config.h to ensure +that your coverage map is large enough to hold all basic blocks of your +target program without any collisions. + +More documentation on how to utilize this with Nyx will follow. diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 0912e52b..3f8b519b 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -14,6 +14,16 @@ */ +#ifdef __AFL_CODE_COVERAGE + #ifndef _GNU_SOURCE + #define _GNU_SOURCE + #endif + #ifndef __USE_GNU + #define __USE_GNU + #endif + #include +#endif + #ifdef __ANDROID__ #include "android-ashmem.h" #endif @@ -105,6 +115,44 @@ u32 __afl_dictionary_len; u64 __afl_map_addr; u32 __afl_first_final_loc; +#ifdef __AFL_CODE_COVERAGE +typedef struct afl_module_info_t afl_module_info_t; + +struct afl_module_info_t { + + // A unique id starting with 0 + u32 id; + + // Name and base address of the module + char *name; + uintptr_t base_address; + + // PC Guard start/stop + u32 start; + u32 stop; + + // PC Table begin/end + const uintptr_t *pcs_beg; + const uintptr_t *pcs_end; + + u8 mapped; + + afl_module_info_t *next; + +}; + +typedef struct { + + uintptr_t PC, PCFlags; + +} PCTableEntry; + +afl_module_info_t *__afl_module_info = NULL; + +u32 __afl_pcmap_size = 0; +uintptr_t *__afl_pcmap_ptr = NULL; +#endif // __AFL_CODE_COVERAGE + /* 1 if we are running in afl, and the forkserver was started, else 0 */ u32 __afl_connected = 0; @@ -496,11 +544,12 @@ static void __afl_map_shm(void) { if (__afl_map_size && __afl_map_size > MAP_SIZE) { - u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE"); - if (!map_env || atoi((char *)map_env) < MAP_SIZE) { + u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE"); + if (!map_env || atoi((char *)map_env) < MAP_SIZE) { - send_forkserver_error(FS_ERROR_MAP_SIZE); - _exit(1); + fprintf(stderr, "FS_ERROR_MAP_SIZE\n"); + send_forkserver_error(FS_ERROR_MAP_SIZE); + _exit(1); } @@ -512,13 +561,13 @@ static void __afl_map_shm(void) { if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) { - if (__afl_map_addr) + if (__afl_map_addr) send_forkserver_error(FS_ERROR_MAP_ADDR); else send_forkserver_error(FS_ERROR_SHMAT); perror("shmat for map"); - _exit(1); + _exit(1); } @@ -678,6 +727,27 @@ static void __afl_map_shm(void) { } +#ifdef __AFL_CODE_COVERAGE + char *pcmap_id_str = getenv("__AFL_PCMAP_SHM_ID"); + + if (pcmap_id_str) { + + __afl_pcmap_size = __afl_map_size * sizeof(void *); + u32 shm_id = atoi(pcmap_id_str); + + __afl_pcmap_ptr = (uintptr_t *)shmat(shm_id, NULL, 0); + + if (__afl_debug) { + + fprintf(stderr, "DEBUG: Received %p via shmat for pcmap\n", + __afl_pcmap_ptr); + + } + + } + +#endif // __AFL_CODE_COVERAGE + } /* unmap SHM. */ @@ -686,6 +756,17 @@ static void __afl_unmap_shm(void) { if (!__afl_already_initialized_shm) return; +#ifdef __AFL_CODE_COVERAGE + if (__afl_pcmap_size) { + + shmdt((void *)__afl_pcmap_ptr); + __afl_pcmap_ptr = NULL; + __afl_pcmap_size = 0; + + } + +#endif // __AFL_CODE_COVERAGE + char *id_str = getenv(SHM_ENV_VAR); if (id_str) { @@ -1507,6 +1588,102 @@ void __sanitizer_cov_trace_pc_guard(uint32_t *guard) { } +#ifdef __AFL_CODE_COVERAGE +void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, + const uintptr_t *pcs_end) { + + if (__afl_debug) { + + fprintf(stderr, "DEBUG: __sanitizer_cov_pcs_init called\n"); + + } + + // If for whatever reason, we cannot get dlinfo here, then pc_guard_init also + // couldn't get it and we'd end up attributing to the wrong module. + Dl_info dlinfo; + if (!dladdr(__builtin_return_address(0), &dlinfo)) { + + fprintf(stderr, + "WARNING: Ignoring __sanitizer_cov_pcs_init callback due to " + "missing module info\n"); + return; + + } + + afl_module_info_t *last_module_info = __afl_module_info; + while (last_module_info && last_module_info->next) { + + last_module_info = last_module_info->next; + + } + + if (!last_module_info) { + + fprintf(stderr, + "ERROR: __sanitizer_cov_pcs_init called with no module info?!\n"); + abort(); + + } + + last_module_info->pcs_beg = pcs_beg; + last_module_info->pcs_end = pcs_end; + + // Now update the pcmap. If this is the last module coming in, after all + // pre-loaded code, then this will also map all of our delayed previous + // modules. + + if (!__afl_pcmap_ptr) { return; } + + for (afl_module_info_t *mod_info = __afl_module_info; mod_info; + mod_info = mod_info->next) { + + if (mod_info->mapped) { continue; } + + PCTableEntry *start = (PCTableEntry *)(mod_info->pcs_beg); + PCTableEntry *end = (PCTableEntry *)(mod_info->pcs_end); + + u32 in_module_index = 0; + + while (start < end) { + + if (mod_info->start + in_module_index >= __afl_map_size) { + + fprintf(stderr, "ERROR: __sanitizer_cov_pcs_init out of bounds?!\n"); + abort(); + + } + + uintptr_t PC = start->PC; + + // This is what `GetPreviousInstructionPc` in sanitizer runtime does + // for x86/x86-64. Needs more work for ARM and other archs. + PC = PC - 1; + + // Calculate relative offset in module + PC = PC - mod_info->base_address; + + __afl_pcmap_ptr[mod_info->start + in_module_index] = PC; + + start++; + in_module_index++; + + } + + mod_info->mapped = 1; + + if (__afl_debug) { + + fprintf(stderr, "DEBUG: __sanitizer_cov_pcs_init initialized %u PCs\n", + in_module_index); + + } + + } + +} + +#endif // __AFL_CODE_COVERAGE + /* Init callback. Populates instrumentation IDs. Note that we're using ID of 0 as a special value to indicate non-instrumented bits. That may still touch the bitmap, but in a fairly harmless way. */ @@ -1538,6 +1715,62 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { if (start == stop || *start) { return; } +#ifdef __AFL_CODE_COVERAGE + u32 *orig_start = start; + afl_module_info_t *mod_info = NULL; + + Dl_info dlinfo; + if (dladdr(__builtin_return_address(0), &dlinfo)) { + + if (__afl_already_initialized_forkserver) { + + fprintf(stderr, "[pcmap] Error: Module was not preloaded: %s\n", + dlinfo.dli_fname); + + } else { + + afl_module_info_t *last_module_info = __afl_module_info; + while (last_module_info && last_module_info->next) { + + last_module_info = last_module_info->next; + + } + + mod_info = malloc(sizeof(afl_module_info_t)); + + mod_info->id = last_module_info ? last_module_info->id + 1 : 0; + mod_info->name = strdup(dlinfo.dli_fname); + mod_info->base_address = (uintptr_t)dlinfo.dli_fbase; + mod_info->start = 0; + mod_info->stop = 0; + mod_info->pcs_beg = NULL; + mod_info->pcs_end = NULL; + mod_info->mapped = 0; + mod_info->next = NULL; + + if (last_module_info) { + + last_module_info->next = mod_info; + + } else { + + __afl_module_info = mod_info; + + } + + fprintf(stderr, "[pcmap] Module: %s Base Address: %p\n", dlinfo.dli_fname, + dlinfo.dli_fbase); + + } + + } else { + + fprintf(stderr, "[pcmap] dladdr call failed\n"); + + } + +#endif // __AFL_CODE_COVERAGE + x = getenv("AFL_INST_RATIO"); if (x) { @@ -1625,6 +1858,22 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { } +#ifdef __AFL_CODE_COVERAGE + if (mod_info) { + + mod_info->start = *orig_start; + mod_info->stop = *(stop - 1); + if (__afl_debug) { + + fprintf(stderr, "DEBUG: [pcmap] Start Index: %u Stop Index: %u\n", + mod_info->start, mod_info->stop); + + } + + } + +#endif // __AFL_CODE_COVERAGE + if (__afl_debug) { fprintf(stderr, diff --git a/src/afl-cc.c b/src/afl-cc.c index 99ce39d4..b11a041d 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -76,6 +76,7 @@ enum { INSTRUMENT_OPT_NGRAM = 16, INSTRUMENT_OPT_CALLER = 32, INSTRUMENT_OPT_CTX_K = 64, + INSTRUMENT_OPT_CODECOV = 128, }; @@ -751,7 +752,15 @@ static void edit_params(u32 argc, char **argv, char **envp) { } else if (instrument_mode == INSTRUMENT_LLVMNATIVE) { #if LLVM_MAJOR >= 4 - cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; + if (instrument_opt_mode & INSTRUMENT_OPT_CODECOV) { + #if LLVM_MAJOR >= 6 + 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+"); + #endif + } else { + cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; + } #else FATAL("pcguard instrumentation requires llvm 4.0.1+"); #endif @@ -1682,6 +1691,18 @@ int main(int argc, char **argv, char **envp) { } + if (strncasecmp(ptr2, "llvmcodecov", strlen("llvmcodecov")) == 0 || + strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) { + + if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE) { + instrument_mode = INSTRUMENT_LLVMNATIVE; + instrument_opt_mode |= INSTRUMENT_OPT_CODECOV; + } else + FATAL("main instrumentation mode already set with %s", + instrument_mode_string[instrument_mode]); + + } + if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 || strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) { @@ -2241,7 +2262,8 @@ int main(int argc, char **argv, char **envp) { "(requires LLVM 11 or higher)"); #endif - if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC) + if (instrument_opt_mode && instrument_opt_mode != INSTRUMENT_OPT_CODECOV && + instrument_mode != INSTRUMENT_CLASSIC) FATAL( "CALLER, CTX and NGRAM instrumentation options can only be used with " "the LLVM CLASSIC instrumentation mode."); -- cgit 1.4.1 From 5813a4319c88848b2a1c47c12fe27f5e14dcad44 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 28 Apr 2023 11:42:21 +0200 Subject: doc, code format --- GNUmakefile | 3 ++- docs/INSTALL.md | 10 ++++------ instrumentation/afl-compiler-rt.o.c | 14 +++++++------- src/afl-cc.c | 31 +++++++++++++++++++++++-------- 4 files changed, 36 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/GNUmakefile b/GNUmakefile index 5900ad61..56b8bb42 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -379,6 +379,7 @@ help: @echo Known build environment options: @echo "==========================================" @echo STATIC - compile AFL++ static + @echo CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md) @echo ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes @echo UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes @echo DEBUG - no optimization, -ggdb3, all warnings and -Werror @@ -394,7 +395,7 @@ help: @echo AFL_NO_X86 - if compiling on non-intel/amd platforms @echo "LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian)" @echo "==========================================" - @echo e.g.: make ASAN_BUILD=1 + @echo e.g.: make LLVM_CONFIG=llvm-config-16 .PHONY: test_x86 ifndef AFL_NO_X86 diff --git a/docs/INSTALL.md b/docs/INSTALL.md index c54cb9ad..637e8658 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -79,22 +79,20 @@ make STATIC=1 These build options exist: * STATIC - compile AFL++ static +* CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md) * ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes -* UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for - debug purposes +* UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes * DEBUG - no optimization, -ggdb3, all warnings and -Werror * LLVM_DEBUG - shows llvm deprecation warnings * PROFILING - compile afl-fuzz with profiling information * INTROSPECTION - compile afl-fuzz with mutation introspection * NO_PYTHON - disable python support -* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for - normal fuzzing +* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing * NO_NYX - disable building nyx mode dependencies * NO_CORESIGHT - disable building coresight (arm64 only) * NO_UNICORN_ARM64 - disable building unicorn on arm64 * AFL_NO_X86 - if compiling on non-intel/amd platforms -* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config - (e.g., Debian) +* LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g., Debian) e.g.: `make LLVM_CONFIG=llvm-config-14` diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 3f8b519b..5372fae0 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -544,12 +544,12 @@ static void __afl_map_shm(void) { if (__afl_map_size && __afl_map_size > MAP_SIZE) { - u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE"); - if (!map_env || atoi((char *)map_env) < MAP_SIZE) { + u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE"); + if (!map_env || atoi((char *)map_env) < MAP_SIZE) { - fprintf(stderr, "FS_ERROR_MAP_SIZE\n"); - send_forkserver_error(FS_ERROR_MAP_SIZE); - _exit(1); + fprintf(stderr, "FS_ERROR_MAP_SIZE\n"); + send_forkserver_error(FS_ERROR_MAP_SIZE); + _exit(1); } @@ -561,13 +561,13 @@ static void __afl_map_shm(void) { if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) { - if (__afl_map_addr) + if (__afl_map_addr) send_forkserver_error(FS_ERROR_MAP_ADDR); else send_forkserver_error(FS_ERROR_SHMAT); perror("shmat for map"); - _exit(1); + _exit(1); } diff --git a/src/afl-cc.c b/src/afl-cc.c index b11a041d..19314555 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -752,15 +752,21 @@ static void edit_params(u32 argc, char **argv, char **envp) { } else if (instrument_mode == INSTRUMENT_LLVMNATIVE) { #if LLVM_MAJOR >= 4 - if (instrument_opt_mode & INSTRUMENT_OPT_CODECOV) { + if (instrument_opt_mode & INSTRUMENT_OPT_CODECOV) { + #if LLVM_MAJOR >= 6 - cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table"; + 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+"); #endif - } else { + + } else { + cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; - } + + } + #else FATAL("pcguard instrumentation requires llvm 4.0.1+"); #endif @@ -1660,13 +1666,17 @@ int main(int argc, char **argv, char **envp) { instrument_mode = INSTRUMENT_CLASSIC; lto_mode = 1; - } else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL) + } else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL) { instrument_mode = INSTRUMENT_AFL; - else + + } else { + FATAL("main instrumentation mode already set with %s", instrument_mode_string[instrument_mode]); + } + } if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 || @@ -1695,12 +1705,17 @@ int main(int argc, char **argv, char **envp) { strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE) { + instrument_mode = INSTRUMENT_LLVMNATIVE; - instrument_opt_mode |= INSTRUMENT_OPT_CODECOV; - } else + instrument_opt_mode |= INSTRUMENT_OPT_CODECOV; + + } else { + FATAL("main instrumentation mode already set with %s", instrument_mode_string[instrument_mode]); + } + } if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 || -- cgit 1.4.1 From 9065d4ba86ecdafeade50e5235ee1e99f4179692 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 1 May 2023 08:38:13 +0200 Subject: fix effector map --- src/afl-fuzz-one.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index ee562f96..442240a9 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -842,6 +842,7 @@ u8 fuzz_one_original(afl_state_t *afl) { eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len)); if (unlikely(!eff_map)) { PFATAL("alloc"); } + memset(eff_map, 0, sizeof(len)); eff_map[0] = 1; if (EFF_APOS(len - 1) != 0) { @@ -3570,6 +3571,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len)); if (unlikely(!eff_map)) { PFATAL("alloc"); } + memset(eff_map, 0, sizeof(len)); eff_map[0] = 1; if (EFF_APOS(len - 1) != 0) { -- cgit 1.4.1 From 2cd07abca9c7b843bbd2085e0e4d852d41169092 Mon Sep 17 00:00:00 2001 From: lazymio Date: Mon, 1 May 2023 13:12:05 +0200 Subject: Should memset EFF_ALEN(len) of eff_map (#1722) --- src/afl-fuzz-one.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 442240a9..a9902087 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -842,7 +842,7 @@ u8 fuzz_one_original(afl_state_t *afl) { eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len)); if (unlikely(!eff_map)) { PFATAL("alloc"); } - memset(eff_map, 0, sizeof(len)); + memset(eff_map, 0, EFF_ALEN(len)); eff_map[0] = 1; if (EFF_APOS(len - 1) != 0) { @@ -3571,7 +3571,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len)); if (unlikely(!eff_map)) { PFATAL("alloc"); } - memset(eff_map, 0, sizeof(len)); + memset(eff_map, 0, EFF_ALEN(len)); eff_map[0] = 1; if (EFF_APOS(len - 1) != 0) { -- cgit 1.4.1 From 22db79aefafb48fed48199a86a39babdee795870 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 1 May 2023 15:07:49 +0200 Subject: fix reallocs --- include/alloc-inl.h | 7 +++---- src/afl-fuzz.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/include/alloc-inl.h b/include/alloc-inl.h index bbb42e88..1e9a192b 100644 --- a/include/alloc-inl.h +++ b/include/alloc-inl.h @@ -704,12 +704,11 @@ static inline void *afl_realloc(void **buf, size_t size_needed) { *buf = NULL; return NULL; - } else { - - new_buf = newer_buf; - } + new_buf = newer_buf; + memset(((u8 *)new_buf) + current_size, 0, next_size - current_size); + new_buf->complete_size = next_size; *buf = (void *)(new_buf->buf); return *buf; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 646dc50b..c02479cf 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1979,6 +1979,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->non_instrumented_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) { + u32 old_map_size = map_size; map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE; afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size); afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size); @@ -1990,6 +1991,18 @@ int main(int argc, char **argv_orig, char **envp) { afl->first_trace = ck_realloc(afl->first_trace, map_size); afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, map_size); + if (old_map_size < map_size) { + + memset(afl->var_bytes + old_map_size, 0, map_size - old_map_size); + memset(afl->top_rated + old_map_size, 0, map_size - old_map_size); + memset(afl->clean_trace + old_map_size, 0, map_size - old_map_size); + memset(afl->clean_trace_custom + old_map_size, 0, + map_size - old_map_size); + memset(afl->first_trace + old_map_size, 0, map_size - old_map_size); + memset(afl->map_tmp_buf + old_map_size, 0, map_size - old_map_size); + + } + } afl->argv = use_argv; @@ -2017,6 +2030,7 @@ int main(int argc, char **argv_orig, char **envp) { OKF("Re-initializing maps to %u bytes", new_map_size); + u32 old_map_size = map_size; afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size); afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size); afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size); @@ -2029,6 +2043,18 @@ int main(int argc, char **argv_orig, char **envp) { afl->first_trace = ck_realloc(afl->first_trace, new_map_size); afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size); + if (old_map_size < new_map_size) { + + memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size); + memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size); + memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size); + memset(afl->clean_trace_custom + old_map_size, 0, + new_map_size - old_map_size); + memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size); + memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size); + + } + afl_fsrv_kill(&afl->fsrv); afl_shm_deinit(&afl->shm); afl->fsrv.map_size = new_map_size; @@ -2079,6 +2105,7 @@ int main(int argc, char **argv_orig, char **envp) { OKF("Re-initializing maps to %u bytes due cmplog", new_map_size); + u32 old_map_size = map_size; afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size); afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size); afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size); @@ -2091,6 +2118,18 @@ int main(int argc, char **argv_orig, char **envp) { afl->first_trace = ck_realloc(afl->first_trace, new_map_size); afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size); + if (old_map_size < new_map_size) { + + memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size); + memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size); + memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size); + memset(afl->clean_trace_custom + old_map_size, 0, + new_map_size - old_map_size); + memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size); + memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size); + + } + afl_fsrv_kill(&afl->fsrv); afl_fsrv_kill(&afl->cmplog_fsrv); afl_shm_deinit(&afl->shm); -- cgit 1.4.1 From f516926f006545d45162eaef723d786a427721f8 Mon Sep 17 00:00:00 2001 From: Moshe Kaplan Date: Thu, 4 May 2023 11:23:30 -0400 Subject: afl-fuzz.c: Document -i - in --help (#1725) afl-fuzz.c: Document `-i -` in `--help`, to write that `-i` can be passed '-' to resume the prior fuzzing job. Also reference AFL_AUTORESUME so users know they can set that parameter to sidestep the issue entirely. --- src/afl-fuzz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index c02479cf..c5206282 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -124,7 +124,7 @@ static void usage(u8 *argv0, int more_help) { "\n%s [ options ] -- /path/to/fuzzed_app [ ... ]\n\n" "Required parameters:\n" - " -i dir - input directory with test cases\n" + " -i dir - input directory with test cases (or '-' to resume, also see AFL_AUTORESUME)\n" " -o dir - output directory for fuzzer findings\n\n" "Execution control settings:\n" -- cgit 1.4.1 From 396157dedae2049f830c49eb81ef9617275333ee Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 May 2023 13:52:54 +0200 Subject: tritondse custom mutator attempt --- custom_mutators/aflpp_tritondse/README.md | 17 ++++ custom_mutators/aflpp_tritondse/aflpp_tritondse.py | 106 +++++++++++++++++++++ src/afl-fuzz-one.c | 16 ++-- 3 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 custom_mutators/aflpp_tritondse/README.md create mode 100644 custom_mutators/aflpp_tritondse/aflpp_tritondse.py (limited to 'src') diff --git a/custom_mutators/aflpp_tritondse/README.md b/custom_mutators/aflpp_tritondse/README.md new file mode 100644 index 00000000..8a5dd02b --- /dev/null +++ b/custom_mutators/aflpp_tritondse/README.md @@ -0,0 +1,17 @@ +# An AFL++ custom mutator using TritonDSE + +## Installing the requirements + +`pip3 install tritondse` + +## How to run with an example + +``` +../../afl-cc -o ../../test-instr ../../test-instr.c +mkdir -p in +echo aaaa > in/in +TRITON_DSE_TARGET=../../test-instr AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr +``` + +Note that this custom mutator works differently, new finds are synced +after 10-60 seconds to the fuzzing instance. diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py new file mode 100644 index 00000000..33bf8a9f --- /dev/null +++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py @@ -0,0 +1,106 @@ +import sys +import os +import logging + +from tritondse import Config +from tritondse import CoverageStrategy +from tritondse import ProcessState +from tritondse import Program +from tritondse import Seed +from tritondse import SeedFormat +from tritondse import SymbolicExecutor +from tritondse import SymbolicExplorator + + +#logging.basicConfig(level=logging.INFO) + +is_debug = False +out_path = "out/tritondse/queue" +input_file = None +prog = None +config = None +dse = None +cycle = 0 +count = 0 +hashes = set() + +def pre_exec_hook(se: SymbolicExecutor, state: ProcessState): + #logging.info(f"[PRE-EXEC] Processing seed: {se.seed.hash}, \ + # ({repr(se.seed.content)})") + global count + global hasshes + if se.seed.hash not in hashes: + hashes.add(se.seed.hash) + filename = out_path + "/id:" + f"{count:06}" + "," + se.seed.hash + if not os.path.exists(filename): + with open(filename, 'wb') as file: + file.write(se.seed.content) + count += 1 + if input_file: + with open(input_file, 'wb') as file: + file.write(se.seed.content) + + +def init(seed): + global prog + global config + global dse + global input_file + global is_debug + # Load the program (LIEF-based program loader). + prog = Program(os.environ['TRITON_DSE_TARGET']) + # Set the configuration. + argv = None + try: + foo = os.environ['AFL_DEBUG'] + is_debug = True + except KeyError: + pass + try: + argv_list = os.environ['TRITON_DSE_TARGET_ARGV'] + argv = argv_list.split() + except KeyError: + pass + try: + foo = os.environ['TRITON_DSE_TARGET_INPUT'] + input_file = foo + except KeyError: + pass + config = Config(coverage_strategy = CoverageStrategy.PATH, + debug = is_debug, + pipe_stdout = is_debug, + pipe_stderr = is_debug, + execution_timeout = 1, + program_argv = argv, + smt_timeout= 50, + seed_format = SeedFormat.RAW) + # Create an instance of the Symbolic Explorator + dse = SymbolicExplorator(config, prog) + # Add callbacks. + dse.callback_manager.register_pre_execution_callback(pre_exec_hook) + # Create the output directory + os.makedirs(out_path, exist_ok=True) + + +#def fuzz(buf, add_buf, max_size): +# return b"" + + +def queue_new_entry(filename_new_queue, filename_orig_queue): + global dse + global cycle + # Add seed to the worklist. + with open(filename_new_queue, "rb") as file: + seed = file.read() + seed = Seed(seed) + dse.add_input_seed(seed) + if is_debug: + print("NEW FILE " + filename_new_queue + " count " + str(cycle)) + cycle += 1 + # Start exploration! + #dse.step() + dse.explore() + pass + +def splice_optout(): + pass diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index a9902087..c6e9a295 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2048,20 +2048,22 @@ custom_mutator_stage: afl->queue_cur->stats_mutated += afl->stage_max; #endif - if (likely(afl->custom_only)) { + /**************** + * RANDOM HAVOC * + ****************/ + +havoc_stage: + + if (unlikely(afl->custom_only)) { + /* Force UI update */ + show_stats(afl); /* Skip other stages */ ret_val = 0; goto abandon_entry; } - /**************** - * RANDOM HAVOC * - ****************/ - -havoc_stage: - afl->stage_cur_byte = -1; /* The havoc stage mutation code is also invoked when splicing files; if the -- cgit 1.4.1 From c97caa6e1095a4bce8f0c32108e6e33f7ac240e4 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 9 May 2023 14:17:09 +0200 Subject: fix makefile --- GNUmakefile | 2 +- src/afl-fuzz.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/GNUmakefile b/GNUmakefile index 794ebeab..31374c10 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -379,7 +379,7 @@ help: @echo Known build environment options: @echo "==========================================" @echo STATIC - compile AFL++ static - @echo CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md) + @echo "CODE_COVERAGE - compile the target for code coverage (see docs/instrumentation/README.llvm.md)" @echo ASAN_BUILD - compiles AFL++ with memory sanitizer for debug purposes @echo UBSAN_BUILD - compiles AFL++ tools with undefined behaviour sanitizer for debug purposes @echo DEBUG - no optimization, -ggdb3, all warnings and -Werror diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index c5206282..f982258f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -124,7 +124,8 @@ static void usage(u8 *argv0, int more_help) { "\n%s [ options ] -- /path/to/fuzzed_app [ ... ]\n\n" "Required parameters:\n" - " -i dir - input directory with test cases (or '-' to resume, also see AFL_AUTORESUME)\n" + " -i dir - input directory with test cases (or '-' to resume, " + "also see AFL_AUTORESUME)\n" " -o dir - output directory for fuzzer findings\n\n" "Execution control settings:\n" -- cgit 1.4.1 From 70da0c2e405102dc044cb4bed0f4f1e847c90d0b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 10 May 2023 16:09:18 +0200 Subject: better tritondse support --- custom_mutators/aflpp_tritondse/aflpp_tritondse.py | 54 ++++++++++--- docs/custom_mutators.md | 28 +++++++ include/envs.h | 4 + src/afl-fuzz.c | 91 ++++++++++++++++------ 4 files changed, 145 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py index 49f67d75..9584b368 100644 --- a/custom_mutators/aflpp_tritondse/aflpp_tritondse.py +++ b/custom_mutators/aflpp_tritondse/aflpp_tritondse.py @@ -7,6 +7,7 @@ from tritondse import Config from tritondse import CoverageStrategy from tritondse import ProcessState from tritondse import Program +from tritondse import CleLoader from tritondse import Seed from tritondse import SeedFormat from tritondse import SymbolicExecutor @@ -16,7 +17,7 @@ from tritondse import SymbolicExplorator #logging.basicConfig(level=logging.INFO) is_debug = False -out_path = "out/tritondse/queue" +out_path = "" input_file = None prog = None config = None @@ -29,28 +30,38 @@ def pre_exec_hook(se: SymbolicExecutor, state: ProcessState): #logging.info(f"[PRE-EXEC] Processing seed: {se.seed.hash}, \ # ({repr(se.seed.content)})") global count - global hasshes + global hashes + print('DEBUG - prehook') if se.seed.hash not in hashes: hashes.add(se.seed.hash) filename = out_path + "/id:" + f"{count:06}" + "," + se.seed.hash if not os.path.exists(filename): + if is_debug: + print('Creating queue input ' + filename) with open(filename, 'wb') as file: file.write(se.seed.content) count += 1 + else: + print('has hash: ' + se.seed.hash) if input_file: + if is_debug: + print('Writing to ' + input_file + ' the content: ' + str(se.seed.content)) with open(input_file, 'wb') as file: file.write(se.seed.content) + else: + print('no input!') def init(seed): global prog global config global dse + global out_path global input_file global is_debug # Load the program (LIEF-based program loader). - prog = Program(os.environ['TRITON_DSE_TARGET']) - # Set the configuration. + prog = CleLoader(os.environ['AFL_CUSTOM_INFO_PROGRAM']) + # Process other configuration environment variables. argv = None try: foo = os.environ['AFL_DEBUG'] @@ -58,15 +69,42 @@ def init(seed): except KeyError: pass try: - argv_list = os.environ['TRITON_DSE_TARGET_ARGV'] - argv = argv_list.split() + foo = os.environ['AFL_CUSTOM_INFO_OUT'] + out_path = foo + '/../tritondse/queue' except KeyError: pass try: - foo = os.environ['TRITON_DSE_TARGET_INPUT'] + foo = os.environ['AFL_CUSTOM_INFO_PROGRAM_INPUT'] input_file = foo except KeyError: pass + try: + argv_list = os.environ['AFL_CUSTOM_INFO_PROGRAM_ARGV'] + argv_tmp = [ os.environ['AFL_CUSTOM_INFO_PROGRAM'] ] + argv_tmp += argv_list.split() + argv = [] + # now check for @@ + for item in argv_tmp: + if "@@" in item: + input_file = out_path + '/../.input' + argv.append(input_file) + else: + argv.append(item) + except KeyError: + pass + # Create the output directory + os.makedirs(out_path, exist_ok=True) + # Debug + if is_debug: + print('DEBUG target: ' + os.environ['AFL_CUSTOM_INFO_PROGRAM']) + if argv: + print('DEBUG argv: ') + print(argv) + if input_file: + print('DEBUG input_file: ' + input_file) + print('DEBUG out_path: ' + out_path) + print('') + # Now set up TritonDSE config = Config(coverage_strategy = CoverageStrategy.PATH, debug = is_debug, pipe_stdout = is_debug, @@ -79,8 +117,6 @@ def init(seed): dse = SymbolicExplorator(config, prog) # Add callbacks. dse.callback_manager.register_pre_execution_callback(pre_exec_hook) - # Create the output directory - os.makedirs(out_path, exist_ok=True) #def fuzz(buf, add_buf, max_size): diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index a1de479e..3f7e9e6e 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -304,6 +304,34 @@ Note: for some distributions, you might also need the package `python[3]-apt`. In case your setup is different, set the necessary variables like this: `PYTHON_INCLUDE=/path/to/python/include LDFLAGS=-L/path/to/python/lib make`. +### Helpers + +For C/C++ custom mutators you get a pointer to `afl_state_t *afl` in the +`afl_custom_init()` which contains all information that you need. +Note that if you access it, you need to recompile your custom mutator if +you update AFL++ because the structure might have changed! + +For mutators written in Python, Rust, GO, etc. there are a few environment +variables set to help you to get started: + +`AFL_CUSTOM_INFO_PROGRAM` - the program name of the target that is executed. +If your custom mutator is used with modes like Qemu (`-Q`), this will still +contain the target program, not afl-qemu-trace. + +`AFL_CUSTOM_INFO_PROGRAM_INPUT` - if the `-f` parameter is used with afl-fuzz +then this value is found in this environment variable. + +`AFL_CUSTOM_INFO_PROGRAM_ARGV` - this contains the parameters given to the +target program and still has the `@@` identifier in there. + +Note: If `AFL_CUSTOM_INFO_PROGRAM_INPUT` is empty and `AFL_CUSTOM_INFO_PROGRAM_ARGV` +is either empty or does not contain `@@` then the target gets the input via +`stdin`. + +`AFL_CUSTOM_INFO_OUT` - This is the output directory for this fuzzer instance, +so if `afl-fuzz` was called with `-o out -S foobar`, then this will be set to +`out/foobar`. + ### Custom Mutator Preparation For C/C++ mutators, the source code must be compiled as a shared object: diff --git a/include/envs.h b/include/envs.h index fe5ee0e3..edfd06e4 100644 --- a/include/envs.h +++ b/include/envs.h @@ -37,6 +37,10 @@ static char *afl_environment_variables[] = { "AFL_CRASH_EXITCODE", "AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_ONLY", + "AFL_CUSTOM_INFO_PROGRAM", + "AFL_CUSTOM_INFO_PROGRAM_ARGV", + "AFL_CUSTOM_INFO_PROGRAM_INPUT", + "AFL_CUSTOM_INFO_OUT", "AFL_CXX", "AFL_CYCLE_SCHEDULES", "AFL_DEBUG", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index f982258f..4339ddd2 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1530,29 +1530,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (afl->limit_time_sig > 0 && afl->custom_mutators_count) { - - if (afl->custom_only) { - - FATAL("Custom mutators are incompatible with MOpt (-L)"); - - } - - u32 custom_fuzz = 0; - LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { - - if (el->afl_custom_fuzz) { custom_fuzz = 1; } - - }); - - if (custom_fuzz) { - - WARNF("afl_custom_fuzz is incompatible with MOpt (-L)"); - - } - - } - if (afl->afl_env.afl_max_det_extras) { s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras); @@ -1827,8 +1804,76 @@ int main(int argc, char **argv_orig, char **envp) { printf("DEBUG: rand %06d is %u\n", counter, rand_below(afl, 65536)); #endif + if (!getenv("AFL_CUSTOM_INFO_PROGRAM")) { + + setenv("AFL_CUSTOM_INFO_PROGRAM", argv[optind], 1); + + } + + if (!getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT") && afl->fsrv.out_file) { + + setenv("AFL_CUSTOM_INFO_PROGRAM_INPUT", afl->fsrv.out_file, 1); + + } + + { + + u8 envbuf[8096] = "", tmpbuf[8096] = ""; + for (s32 i = optind + 1; i < argc; ++i) { + + strcpy(tmpbuf, envbuf); + if (strchr(argv[i], ' ') && !strchr(argv[i], '"') && + !strchr(argv[i], '\'')) { + + if (!strchr(argv[i], '\'')) { + + snprintf(envbuf, sizeof(tmpbuf), "%s '%s'", tmpbuf, argv[i]); + + } else { + + snprintf(envbuf, sizeof(tmpbuf), "%s \"%s\"", tmpbuf, argv[i]); + + } + + } else { + + snprintf(envbuf, sizeof(tmpbuf), "%s %s", tmpbuf, argv[i]); + + } + + } + + setenv("AFL_CUSTOM_INFO_PROGRAM_ARGV", envbuf + 1, 1); + + } + + setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR + setup_custom_mutators(afl); + if (afl->limit_time_sig > 0 && afl->custom_mutators_count) { + + if (afl->custom_only) { + + FATAL("Custom mutators are incompatible with MOpt (-L)"); + + } + + u32 custom_fuzz = 0; + LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, { + + if (el->afl_custom_fuzz) { custom_fuzz = 1; } + + }); + + if (custom_fuzz) { + + WARNF("afl_custom_fuzz is incompatible with MOpt (-L)"); + + } + + } + write_setup_file(afl, argc, argv); setup_cmdline_file(afl, argv + optind); -- cgit 1.4.1 From 93c821aaa3df0cf20f892ce72447ff022161c8ab Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 12 May 2023 08:39:11 +0200 Subject: afl-clang-lto incomptable with -flto=thin --- docs/Changelog.md | 1 + src/afl-cc.c | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index e85de763..799c13af 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -13,6 +13,7 @@ - afl-cc: - 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 - afl-showmap: - added custom mutator post_process and send support - add `-I filelist` option, an alternative to `-i in_dir` diff --git a/src/afl-cc.c b/src/afl-cc.c index 19314555..13ca751e 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -853,6 +853,15 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (cur[0] != '-') { non_dash = 1; } if (!strncmp(cur, "--afl", 5)) continue; + + if (lto_mode && !strncmp(cur, "-flto=thin", 10)) { + + FATAL( + "afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or " + "use afl-clang-fast!"); + + } + if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue; if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue; if (!strncmp(cur, "-fno-unroll", 11)) continue; -- cgit 1.4.1 From 7f636dbfc247fbe75910fa8fb681ea55d230ba79 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 12 May 2023 15:58:20 +0200 Subject: add @responsefile support for afl-cc --- docs/Changelog.md | 1 + src/afl-cc.c | 460 +++++++++++++++++++++++++++++++++++------------------- 2 files changed, 300 insertions(+), 161 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index 799c13af..3602af50 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -11,6 +11,7 @@ - new env `AFL_IGNORE_PROBLEMS_COVERAGE` to ignore coverage from loaded libs after forkserver initialization (required by Mozilla) - afl-cc: + - added @responsefile support - 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 diff --git a/src/afl-cc.c b/src/afl-cc.c index 13ca751e..972ac8cd 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #if (LLVM_MAJOR - 0 == 0) #undef LLVM_MAJOR @@ -376,15 +378,304 @@ void parse_fsanitize(char *string) { } +static u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, + shared_linking = 0, preprocessor_only = 0, have_unroll = 0, + have_o = 0, have_pic = 0, have_c = 0, partial_linking = 0, + non_dash = 0; + +static void process_params(u32 argc, char **argv) { + + if (cc_par_cnt + argc >= 1024) { FATAL("Too many command line parameters"); } + + if (lto_mode && argc > 1) { + + u32 idx; + for (idx = 1; idx < argc; idx++) { + + if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1; + + } + + } + + // for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]); + + /* Process the argument list. */ + + u8 skip_next = 0; + while (--argc) { + + u8 *cur = *(++argv); + + if (skip_next) { + + skip_next = 0; + continue; + + } + + if (cur[0] != '-') { non_dash = 1; } + if (!strncmp(cur, "--afl", 5)) continue; + + if (lto_mode && !strncmp(cur, "-flto=thin", 10)) { + + FATAL( + "afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or " + "use afl-clang-fast!"); + + } + + if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue; + if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue; + if (!strncmp(cur, "-fno-unroll", 11)) continue; + if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue; + if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") || + !strcmp(cur, "--no-undefined")) { + + continue; + + } + + if (compiler_mode == GCC_PLUGIN && !strcmp(cur, "-pipe")) { continue; } + + if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) { + + u8 *param = *(argv + 1); + if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) { + + skip_next = 1; + continue; + + } + + } + + if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) && + !strncmp(cur, "-stdlib=", 8)) { + + if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); } + continue; + + } + + if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) { + + have_instr_list = 1; + + } + + if (!strncmp(cur, "-fsanitize=", strlen("-fsanitize=")) && + strchr(cur, ',')) { + + parse_fsanitize(cur); + if (!cur || strlen(cur) <= strlen("-fsanitize=")) { continue; } + + } else if ((!strncmp(cur, "-fsanitize=fuzzer-", + + strlen("-fsanitize=fuzzer-")) || + !strncmp(cur, "-fsanitize-coverage", + strlen("-fsanitize-coverage"))) && + (strncmp(cur, "sanitize-coverage-allow", + strlen("sanitize-coverage-allow")) && + strncmp(cur, "sanitize-coverage-deny", + strlen("sanitize-coverage-deny")) && + instrument_mode != INSTRUMENT_LLVMNATIVE)) { + + if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); } + continue; + + } + + if (need_aflpplib || !strcmp(cur, "-fsanitize=fuzzer")) { + + u8 *afllib = find_object("libAFLDriver.a", argv[0]); + + if (!be_quiet) { + + OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a"); + + } + + if (!afllib) { + + if (!be_quiet) { + + WARNF( + "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in " + "the flags - this will fail!"); + + } + + } else { + + cc_params[cc_par_cnt++] = afllib; + +#ifdef __APPLE__ + cc_params[cc_par_cnt++] = "-undefined"; + cc_params[cc_par_cnt++] = "dynamic_lookup"; +#endif + + } + + if (need_aflpplib) { + + need_aflpplib = 0; + + } else { + + continue; + + } + + } + + if (!strcmp(cur, "-m32")) bit_mode = 32; + if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; + if (!strcmp(cur, "-m64")) bit_mode = 64; + + if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) + asan_set = 1; + + if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; + + if (!strcmp(cur, "-x")) x_set = 1; + if (!strcmp(cur, "-E")) preprocessor_only = 1; + if (!strcmp(cur, "-shared")) shared_linking = 1; + if (!strcmp(cur, "-dynamiclib")) shared_linking = 1; + if (!strcmp(cur, "--target=wasm32-wasi")) passthrough = 1; + if (!strcmp(cur, "-Wl,-r")) partial_linking = 1; + if (!strcmp(cur, "-Wl,-i")) partial_linking = 1; + if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1; + if (!strcmp(cur, "-r")) partial_linking = 1; + if (!strcmp(cur, "--relocatable")) partial_linking = 1; + if (!strcmp(cur, "-c")) have_c = 1; + + if (!strncmp(cur, "-O", 2)) have_o = 1; + if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1; + + if (*cur == '@') { + + // response file support. + // we have two choices - move everything to the command line or + // rewrite the response files to temporary files and delete them + // afterwards. We choose the first for easiness. + // We do *not* support quotes in the rsp files to cope with spaces in + // filenames etc! If you need that then send a patch! + u8 *filename = cur + 1; + if (debug) { DEBUGF("response file=%s\n", filename); } + FILE *f = fopen(filename, "r"); + struct stat st; + + // Check not found or empty? let the compiler complain if so. + if (!f || fstat(fileno(f), &st) < 0 || st.st_size < 1) { + + cc_params[cc_par_cnt++] = cur; + continue; + + } + + u8 *tmpbuf = malloc(st.st_size + 1), *ptr; + char **args = malloc(sizeof(char *) * (st.st_size >> 1)); + int count = 1, cont = 0, cont_act = 0; + + while (fgets(tmpbuf, st.st_size, f)) { + + ptr = tmpbuf; + // no leading whitespace + while (isspace(*ptr)) { + + ++ptr; + cont_act = 0; + + } + + // no comments, no empty lines + if (*ptr == '#' || *ptr == '\n' || !*ptr) { continue; } + // remove LF + if (ptr[strlen(ptr) - 1] == '\n') { ptr[strlen(ptr) - 1] = 0; } + // remove CR + if (*ptr && ptr[strlen(ptr) - 1] == '\r') { ptr[strlen(ptr) - 1] = 0; } + // handle \ at end of line + if (*ptr && ptr[strlen(ptr) - 1] == '\\') { + + cont = 1; + ptr[strlen(ptr) - 1] = 0; + + } + + // remove whitespace at end + while (*ptr && isspace(ptr[strlen(ptr) - 1])) { + + ptr[strlen(ptr) - 1] = 0; + cont = 0; + + } + + if (*ptr) { + + do { + + u8 *value = ptr; + while (*ptr && !isspace(*ptr)) { + + ++ptr; + + } + + while (*ptr && isspace(*ptr)) { + + *ptr++ = 0; + + } + + if (cont_act) { + + u32 len = strlen(args[count - 1]) + strlen(value) + 1; + u8 *tmp = malloc(len); + snprintf(tmp, len, "%s%s", args[count - 1], value); + free(args[count - 1]); + args[count - 1] = tmp; + cont_act = 0; + + } else { + + args[count++] = strdup(value); + + } + + } while (*ptr); + + } + + if (cont) { + + cont_act = 1; + cont = 0; + + } + + } + + if (count) { process_params(count, args); } + + // we cannot free args[] + free(tmpbuf); + + continue; + + } + + cc_params[cc_par_cnt++] = cur; + + } + +} + /* Copy argv to cc_params, making the necessary edits. */ static void edit_params(u32 argc, char **argv, char **envp) { - u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0, shared_linking = 0, - preprocessor_only = 0, have_unroll = 0, have_o = 0, have_pic = 0, - have_c = 0, partial_linking = 0; - - cc_params = ck_alloc((argc + 128) * sizeof(u8 *)); + cc_params = ck_alloc(1024 * sizeof(u8 *)); if (lto_mode) { @@ -831,168 +1122,15 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - if (!have_pic) cc_params[cc_par_cnt++] = "-fPIC"; - } } - /* Detect stray -v calls from ./configure scripts. */ - - u8 skip_next = 0, non_dash = 0; - while (--argc) { - - u8 *cur = *(++argv); - - if (skip_next) { - - skip_next = 0; - continue; - - } - - if (cur[0] != '-') { non_dash = 1; } - if (!strncmp(cur, "--afl", 5)) continue; - - if (lto_mode && !strncmp(cur, "-flto=thin", 10)) { - - FATAL( - "afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or " - "use afl-clang-fast!"); - - } - - if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue; - if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue; - if (!strncmp(cur, "-fno-unroll", 11)) continue; - if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue; - if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") || - !strcmp(cur, "--no-undefined")) { - - continue; - - } + /* Inspect the command line parameters. */ - if (compiler_mode == GCC_PLUGIN && !strcmp(cur, "-pipe")) { continue; } - - if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) { + process_params(argc, argv); - u8 *param = *(argv + 1); - if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) { - - skip_next = 1; - continue; - - } - - } - - if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) && - !strncmp(cur, "-stdlib=", 8)) { - - if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); } - continue; - - } - - if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) { - - have_instr_list = 1; - - } - - if (!strncmp(cur, "-fsanitize=", strlen("-fsanitize=")) && - strchr(cur, ',')) { - - parse_fsanitize(cur); - if (!cur || strlen(cur) <= strlen("-fsanitize=")) { continue; } - - } else if ((!strncmp(cur, "-fsanitize=fuzzer-", - - strlen("-fsanitize=fuzzer-")) || - !strncmp(cur, "-fsanitize-coverage", - strlen("-fsanitize-coverage"))) && - (strncmp(cur, "sanitize-coverage-allow", - strlen("sanitize-coverage-allow")) && - strncmp(cur, "sanitize-coverage-deny", - strlen("sanitize-coverage-deny")) && - instrument_mode != INSTRUMENT_LLVMNATIVE)) { - - if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); } - continue; - - } - - if (need_aflpplib || !strcmp(cur, "-fsanitize=fuzzer")) { - - u8 *afllib = find_object("libAFLDriver.a", argv[0]); - - if (!be_quiet) { - - OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a"); - - } - - if (!afllib) { - - if (!be_quiet) { - - WARNF( - "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in " - "the flags - this will fail!"); - - } - - } else { - - cc_params[cc_par_cnt++] = afllib; - -#ifdef __APPLE__ - cc_params[cc_par_cnt++] = "-undefined"; - cc_params[cc_par_cnt++] = "dynamic_lookup"; -#endif - - } - - if (need_aflpplib) { - - need_aflpplib = 0; - - } else { - - continue; - - } - - } - - if (!strcmp(cur, "-m32")) bit_mode = 32; - if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32; - if (!strcmp(cur, "-m64")) bit_mode = 64; - - if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory")) - asan_set = 1; - - if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; - - if (!strcmp(cur, "-x")) x_set = 1; - if (!strcmp(cur, "-E")) preprocessor_only = 1; - if (!strcmp(cur, "-shared")) shared_linking = 1; - if (!strcmp(cur, "-dynamiclib")) shared_linking = 1; - if (!strcmp(cur, "--target=wasm32-wasi")) passthrough = 1; - if (!strcmp(cur, "-Wl,-r")) partial_linking = 1; - if (!strcmp(cur, "-Wl,-i")) partial_linking = 1; - if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1; - if (!strcmp(cur, "-r")) partial_linking = 1; - if (!strcmp(cur, "--relocatable")) partial_linking = 1; - if (!strcmp(cur, "-c")) have_c = 1; - - if (!strncmp(cur, "-O", 2)) have_o = 1; - if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1; - - cc_params[cc_par_cnt++] = cur; - - } + if (!have_pic) { cc_params[cc_par_cnt++] = "-fPIC"; } // in case LLVM is installed not via a package manager or "make install" // e.g. compiled download or compiled from github then its ./lib directory -- cgit 1.4.1 From abd6eace9d767e4db6019e8eb69080d2352015c9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 18 May 2023 10:32:15 +0200 Subject: improved symqemu custom mutator --- custom_mutators/symqemu/README.md | 2 +- custom_mutators/symqemu/symqemu.c | 239 +++++++++++++++----------------------- include/afl-fuzz.h | 1 + src/afl-fuzz-one.c | 1 + 4 files changed, 98 insertions(+), 145 deletions(-) (limited to 'src') diff --git a/custom_mutators/symqemu/README.md b/custom_mutators/symqemu/README.md index 55ce05c5..b7702c06 100644 --- a/custom_mutators/symqemu/README.md +++ b/custom_mutators/symqemu/README.md @@ -8,4 +8,4 @@ on how to build symqemu-x86_x64 and put it in your `PATH`. just type `make` to build this custom mutator. -```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_SYNC_TIME=1 AFL_DISABLE_TRIM=1 afl-fuzz ...``` +```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_DISABLE_TRIM=1 afl-fuzz ...``` diff --git a/custom_mutators/symqemu/symqemu.c b/custom_mutators/symqemu/symqemu.c index 9030397b..163ae240 100644 --- a/custom_mutators/symqemu/symqemu.c +++ b/custom_mutators/symqemu/symqemu.c @@ -13,6 +13,9 @@ afl_state_t *afl_struct; static u32 debug = 0; +static u32 found_items = 0; + +#define SYMQEMU_LOCATION "symqemu" #define DBG(x...) \ if (debug) { fprintf(stderr, x); } @@ -22,7 +25,6 @@ typedef struct my_mutator { afl_state_t *afl; u8 *mutator_buf; u8 *out_dir; - u8 *queue_dir; u8 *target; u8 *symqemu; u8 *input_file; @@ -67,8 +69,13 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { if (!data->symqemu) FATAL("symqemu binary %s not found", exec_name); DBG("Found %s\n", data->symqemu); - if (getenv("AFL_CUSTOM_MUTATOR_ONLY")) - FATAL("the symqemu module cannot be used with AFL_CUSTOM_MUTATOR_ONLY."); + if (getenv("AFL_CUSTOM_MUTATOR_ONLY")) { + + WARNF( + "the symqemu module is not very effective with " + "AFL_CUSTOM_MUTATOR_ONLY."); + + } if ((data->mutator_buf = malloc(MAX_FILE)) == NULL) { @@ -84,14 +91,11 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { u32 len = strlen(path_tmp) + 32; u8 *symqemu_path = malloc(len); data->out_dir = malloc(len); - data->queue_dir = malloc(len); - snprintf(symqemu_path, len, "%s/../symqemu", path_tmp); - snprintf(data->out_dir, len, "%s/../symqemu/out", path_tmp); - snprintf(data->queue_dir, len, "%s/../symqemu/queue", path_tmp); + snprintf(symqemu_path, len, "%s/%s", path_tmp, SYMQEMU_LOCATION); + snprintf(data->out_dir, len, "%s/out", symqemu_path, path_tmp); - mkdir(symqemu_path, 0755); - mkdir(data->out_dir, 0755); - mkdir(data->queue_dir, 0755); + (void)mkdir(symqemu_path, 0755); + (void)mkdir(data->out_dir, 0755); setenv("SYMCC_OUTPUT_DIR", data->out_dir, 1); @@ -153,8 +157,8 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { data->argv[0] = data->symqemu; data->argv[1] = data->target; - DBG("out_dir=%s, queue_dir=%s, target=%s, input_file=%s, argc=%u\n", - data->out_dir, data->queue_dir, data->target, + DBG("out_dir=%s, target=%s, input_file=%s, argc=%u\n", data->out_dir, + data->target, data->input_file ? (char *)data->input_file : (char *)"", data->argc); @@ -174,29 +178,39 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { } - OKF("Custom mutator symqemu loaded - note that the initial startup of " - "afl-fuzz will be delayed the more starting seeds are present. This is " - "fine, do not worry!"); - return data; } -/* When a new queue entry is added we run this input with the symqemu - instrumented binary */ -uint8_t afl_custom_queue_new_entry(my_mutator_t *data, - const uint8_t *filename_new_queue, - const uint8_t *filename_orig_queue) { +/* No need to receive a splicing item */ +void afl_custom_splice_optout(void *data) { + + (void)(data); + +} + +u32 afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, size_t buf_size) { + + if (likely(!afl_struct->queue_cur->favored || + afl_struct->queue_cur->was_fuzzed)) { + + return 0; + + } int pipefd[2]; struct stat st; - if (data->afl->afl_env.afl_no_ui) - ACTF("Sending to symqemu: %s", filename_new_queue); - u8 *fn = alloc_printf("%s", filename_new_queue); - if (!(stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size)) { - ck_free(fn); - PFATAL("Couldn't find enqueued file: %s", fn); + if (afl_struct->afl_env.afl_no_ui) { + + ACTF("Sending to symqemu: %s", afl_struct->queue_cur->fname); + + } + + if (!(stat(afl_struct->queue_cur->fname, &st) == 0 && S_ISREG(st.st_mode) && + st.st_size)) { + + PFATAL("Couldn't find enqueued file: %s", afl_struct->queue_cur->fname); } @@ -204,7 +218,6 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, if (pipe(pipefd) == -1) { - ck_free(fn); PFATAL( "Couldn't create a pipe for interacting with symqemu child process"); @@ -212,19 +225,12 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, } - int fd = open(fn, O_RDONLY); - if (fd < 0) return 0; - ssize_t r = read(fd, data->mutator_buf, MAX_FILE); - DBG("fn=%s, fd=%d, size=%ld\n", fn, fd, r); - ck_free(fn); - close(fd); - if (data->input_file) { - fd = open(data->input_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); - ssize_t s = write(fd, data->mutator_buf, r); + int fd = open(data->input_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + ssize_t s = write(fd, buf, buf_size); close(fd); - DBG("wrote %zd/%zd to %s\n", s, r, data->input_file); + DBG("wrote %zd/%zd to %s\n", s, buf_size, data->input_file); } @@ -232,35 +238,20 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, if (pid == -1) return 0; - if (pid) { + if (likely(pid)) { if (!data->input_file || afl_struct->fsrv.use_stdin) { close(pipefd[0]); - if (fd >= 0) { - - if (r <= 0) { - - close(pipefd[1]); - return 0; - - } + if (fcntl(pipefd[1], F_GETPIPE_SZ)) { - if (r > fcntl(pipefd[1], F_GETPIPE_SZ)) - fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE); - ck_write(pipefd[1], data->mutator_buf, r, filename_new_queue); - - } else { - - ck_free(fn); - close(pipefd[1]); - PFATAL( - "Something happened to the enqueued file before sending its " - "contents to symqemu binary"); + fcntl(pipefd[1], F_SETPIPE_SZ, MAX_FILE); } + ck_write(pipefd[1], buf, buf_size, data->input_file); + close(pipefd[1]); } @@ -268,46 +259,6 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, pid = waitpid(pid, NULL, 0); DBG("symqemu finished executing!\n"); - // At this point we need to transfer files to output dir, since their names - // collide and symqemu will just overwrite them - - struct dirent **nl; - int32_t items = scandir(data->out_dir, &nl, NULL, NULL); - u8 *origin_name = basename(filename_new_queue); - u8 source_name[4096], destination_name[4096]; - int32_t i; - - if (items > 0) { - - for (i = 0; i < (u32)items; ++i) { - - // symqemu output files start with a digit - if (!isdigit(nl[i]->d_name[0])) continue; - - struct stat st; - snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir, - nl[i]->d_name); - DBG("file=%s\n", source_name); - - if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { - - snprintf(destination_name, sizeof(destination_name), "%s/id:%06u,%s", - data->queue_dir, data->counter++, nl[i]->d_name); - DBG("src=%s dst=%s\n", source_name, destination_name); - rename(source_name, destination_name); - - } - - free(nl[i]); - - } - - free(nl); - - } - - DBG("Done!\n"); - } else /* (pid == 0) */ { // child if (afl_struct->fsrv.use_stdin) { @@ -338,33 +289,31 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data, } - return 0; - -} - -/* -uint32_t afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, - size_t buf_size) { + /* back in mother process */ - uint32_t count = 0, i; struct dirent **nl; - int32_t items = scandir(data->out_dir, &nl, NULL, NULL); + s32 i, items = scandir(data->out_dir, &nl, NULL, NULL); + found_items = 0; + char source_name[4096]; if (items > 0) { for (i = 0; i < (u32)items; ++i) { + // symqemu output files start with a digit + if (!isdigit(nl[i]->d_name[0])) continue; + struct stat st; - u8 * fn = alloc_printf("%s/%s", data->out_dir, nl[i]->d_name); - DBG("test=%s\n", fn); - if (stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { + snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir, + nl[i]->d_name); + DBG("file=%s\n", source_name); + + if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { - DBG("found=%s\n", fn); - count++; + ++found_items; } - ck_free(fn); free(nl[i]); } @@ -373,65 +322,67 @@ uint32_t afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, } - DBG("dir=%s, count=%u\n", data->out_dir, count); - return count; + DBG("Done, found %u items!\n", found_items); -} + return found_items; -*/ +} -// here we actually just read the files generated from symqemu -/* -size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, - u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, +size_t afl_custom_fuzz(my_mutator_t *data, u8 *buf, size_t buf_size, + u8 **out_buf, u8 *add_buf, size_t add_buf_size, size_t max_size) { struct dirent **nl; - int32_t i, done = 0, items = scandir(data->out_dir, &nl, NULL, NULL); - ssize_t size = 0; + s32 done = 0, i, items = scandir(data->out_dir, &nl, NULL, NULL); + char source_name[4096]; - if (items <= 0) return 0; + if (items > 0) { - for (i = 0; i < (u32)items; ++i) { + for (i = 0; i < (u32)items; ++i) { - struct stat st; - u8 * fn = alloc_printf("%s/%s", data->out_dir, nl[i]->d_name); + // symqemu output files start with a digit + if (!isdigit(nl[i]->d_name[0])) continue; - if (done == 0) { + struct stat st; + snprintf(source_name, sizeof(source_name), "%s/%s", data->out_dir, + nl[i]->d_name); + DBG("file=%s\n", source_name); - if (stat(fn, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { + if (stat(source_name, &st) == 0 && S_ISREG(st.st_mode) && st.st_size) { - int fd = open(fn, O_RDONLY); + int fd = open(source_name, O_RDONLY); + if (fd < 0) { goto got_an_issue; } - if (fd >= 0) { + ssize_t r = read(fd, data->mutator_buf, MAX_FILE); + close(fd); - size = read(fd, data->mutator_buf, max_size); - *out_buf = data->mutator_buf; + DBG("fn=%s, fd=%d, size=%ld\n", source_name, fd, r); - close(fd); - done = 1; + if (r < 1) { goto got_an_issue; } - } + done = 1; + --found_items; + unlink(source_name); + + *out_buf = data->mutator_buf; + return (u32)r; } - unlink(fn); + free(nl[i]); } - ck_free(fn); - free(nl[i]); + free(nl); } - free(nl); - DBG("FUZZ size=%lu\n", size); - return (uint32_t)size; +got_an_issue: + *out_buf = NULL; + return 0; } -*/ - /** * Deinitialize everything * diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 8fb7ecb1..beb2de2a 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -184,6 +184,7 @@ struct queue_entry { handicap, /* Number of queue cycles behind */ depth, /* Path depth */ exec_cksum, /* Checksum of the execution trace */ + custom, /* Marker for custom mutators */ stats_mutated; /* stats: # of mutations performed */ u8 *trace_mini; /* Trace bytes, if kept */ diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index c6e9a295..5c71fc59 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1912,6 +1912,7 @@ custom_mutator_stage: afl->stage_name = "custom mutator"; afl->stage_short = "custom"; + afl->stage_cur = 0; afl->stage_val_type = STAGE_VAL_NONE; bool has_custom_fuzz = false; u32 shift = unlikely(afl->custom_only) ? 7 : 8; -- cgit 1.4.1 From 401d7617efbd2f38d9132eabfd1b1152abceda52 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 18 May 2023 10:50:10 +0200 Subject: symqemu mutator options --- custom_mutators/aflpp_tritondse/README.md | 7 +++-- custom_mutators/symqemu/README.md | 10 ++++++- custom_mutators/symqemu/symqemu.c | 44 +++++++++++++++++++++++++------ src/afl-common.c | 2 +- 4 files changed, 51 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/custom_mutators/aflpp_tritondse/README.md b/custom_mutators/aflpp_tritondse/README.md index 8a5dd02b..608c2624 100644 --- a/custom_mutators/aflpp_tritondse/README.md +++ b/custom_mutators/aflpp_tritondse/README.md @@ -10,8 +10,11 @@ ../../afl-cc -o ../../test-instr ../../test-instr.c mkdir -p in echo aaaa > in/in -TRITON_DSE_TARGET=../../test-instr AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr +AFL_DISABLE_TRIM=1 AFL_CUSTOM_MUTATOR_ONLY=1 AFL_SYNC_TIME=1 AFL_PYTHON_MODULE=aflpp_tritondse PYTHONPATH=. ../../afl-fuzz -i in -o out -- ../../test-instr ``` Note that this custom mutator works differently, new finds are synced -after 10-60 seconds to the fuzzing instance. +after 10-60 seconds to the fuzzing instance. This is necessary because only +C/C++ mutators have access to the internal AFL++ state. + +Hence the symqemu customer mutator is more effective. diff --git a/custom_mutators/symqemu/README.md b/custom_mutators/symqemu/README.md index b7702c06..c3071afc 100644 --- a/custom_mutators/symqemu/README.md +++ b/custom_mutators/symqemu/README.md @@ -2,10 +2,18 @@ This uses the symcc to find new paths into the target. +## How to build and use + To use this custom mutator follow the steps in the symqemu repository [https://github.com/eurecom-s3/symqemu/](https://github.com/eurecom-s3/symqemu/) on how to build symqemu-x86_x64 and put it in your `PATH`. -just type `make` to build this custom mutator. +Just type `make` to build this custom mutator. ```AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/symqemu/symqemu-mutator.so AFL_DISABLE_TRIM=1 afl-fuzz ...``` + +## Options + +`SYMQEMU_ALL=1` - use concolic solving on **all** queue items, not only interesting/favorite ones. + +`SYMQEMU_LATE=1` - use concolic solving only after there have been no finds for 5 minutes. diff --git a/custom_mutators/symqemu/symqemu.c b/custom_mutators/symqemu/symqemu.c index 163ae240..e2b07af6 100644 --- a/custom_mutators/symqemu/symqemu.c +++ b/custom_mutators/symqemu/symqemu.c @@ -23,6 +23,8 @@ static u32 found_items = 0; typedef struct my_mutator { afl_state_t *afl; + u32 all; + u32 late; u8 *mutator_buf; u8 *out_dir; u8 *target; @@ -156,18 +158,19 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { data->argv[0] = data->symqemu; data->argv[1] = data->target; + data->afl = afl; + data->seed = seed; + afl_struct = afl; + + if (getenv("SYMQEMU_ALL")) { data->all = 1; } + if (getenv("SYMQEMU_LATE")) { data->late = 1; } + if (data->input_file) { setenv("SYMCC_INPUT_FILE", data->input_file, 1); } DBG("out_dir=%s, target=%s, input_file=%s, argc=%u\n", data->out_dir, data->target, data->input_file ? (char *)data->input_file : (char *)"", data->argc); - if (data->input_file) { setenv("SYMCC_INPUT_FILE", data->input_file, 1); } - - data->afl = afl; - data->seed = seed; - afl_struct = afl; - if (debug) { fprintf(stderr, "["); @@ -189,15 +192,40 @@ void afl_custom_splice_optout(void *data) { } +/* Get unix time in milliseconds */ + +inline u64 get_cur_time(void) { + + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + + return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000); + +} + u32 afl_custom_fuzz_count(my_mutator_t *data, const u8 *buf, size_t buf_size) { - if (likely(!afl_struct->queue_cur->favored || - afl_struct->queue_cur->was_fuzzed)) { + if (likely((!afl_struct->queue_cur->favored || + afl_struct->queue_cur->was_fuzzed) && + !data->all)) { return 0; } + if (likely(data->late)) { + + if (unlikely(get_cur_time() - afl_struct->last_find_time <= + 10 * 60 * 1000)) { + + return 0; + + } + + } + int pipefd[2]; struct stat st; diff --git a/src/afl-common.c b/src/afl-common.c index a5c48e80..84ddefd8 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -949,7 +949,7 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) { /* Get unix time in milliseconds */ -u64 get_cur_time(void) { +inline u64 get_cur_time(void) { struct timeval tv; struct timezone tz; -- cgit 1.4.1 From 53a869b757287e8bebdfcbc96b8abe1729955171 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 18 May 2023 14:45:45 +0200 Subject: act on invalid AFL_CUSTOM_MUTATOR_ONLY usage --- src/afl-fuzz.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 4339ddd2..e2d8dea5 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1748,6 +1748,23 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->afl_env.afl_custom_mutator_only) { + if (!afl->custom_mutators_count) { + + if (afl->shm.cmplog_mode) { + + WARNF( + "No custom mutator loaded, using AFL_CUSTOM_MUTATOR_ONLY is " + "pointless and only allowed now to allow experiments with CMPLOG."); + + } else { + + FATAL( + "No custom mutator loaded but AFL_CUSTOM_MUTATOR_ONLY specified."); + + } + + } + /* This ensures we don't proceed to havoc/splice */ afl->custom_only = 1; -- cgit 1.4.1 From 9a6c0ec0c0af42d33e4350ee2958b58fef1c39dd Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 21 May 2023 13:04:17 +0200 Subject: make AFL_CUSTOM_INFO overridable --- custom_mutators/symqemu/Makefile | 2 +- src/afl-fuzz.c | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/custom_mutators/symqemu/Makefile b/custom_mutators/symqemu/Makefile index 3361ab0f..958aec19 100644 --- a/custom_mutators/symqemu/Makefile +++ b/custom_mutators/symqemu/Makefile @@ -8,7 +8,7 @@ all: symqemu-mutator.so CFLAGS += -O3 -funroll-loops symqemu-mutator.so: symqemu.c - $(CC) $(CFLAGS) $(CPPFLAGS) -g -I../../include -shared -fPIC -o symqemu-mutator.so symqemu.c + $(CC) -g $(CFLAGS) $(CPPFLAGS) -g -I../../include -shared -fPIC -o symqemu-mutator.so symqemu.c clean: rm -f symqemu-mutator.so *.o *~ core diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index e2d8dea5..a61718a7 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1833,7 +1833,7 @@ int main(int argc, char **argv_orig, char **envp) { } - { + if (!getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) { u8 envbuf[8096] = "", tmpbuf[8096] = ""; for (s32 i = optind + 1; i < argc; ++i) { @@ -1864,7 +1864,11 @@ int main(int argc, char **argv_orig, char **envp) { } - setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR + if (!getenv("AFL_CUSTOM_INFO_OUT") { + + setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR + + } setup_custom_mutators(afl); -- cgit 1.4.1 From d4085314c1c1d4e8bbe4159216f8cb83e0804ea7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 21 May 2023 13:44:07 +0200 Subject: fix --- src/afl-fuzz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a61718a7..559a7326 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1864,7 +1864,7 @@ int main(int argc, char **argv_orig, char **envp) { } - if (!getenv("AFL_CUSTOM_INFO_OUT") { + if (!getenv("AFL_CUSTOM_INFO_OUT")) { setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR -- cgit 1.4.1 From 029e039cbcbf9e30f35eb255162679b8d609d25d Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 21 May 2023 17:49:14 +0200 Subject: code format --- .custom-format.py | 2 +- frida_mode/src/lib/lib_apple.c | 4 +-- include/config.h | 2 +- instrumentation/SanitizerCoverageLTO.so.cc | 4 +-- instrumentation/SanitizerCoveragePCGUARD.so.cc | 4 +-- instrumentation/afl-compiler-rt.o.c | 14 +++++----- instrumentation/afl-llvm-lto-instrumentlist.so.cc | 2 +- instrumentation/cmplog-routines-pass.cc | 4 +-- instrumentation/compare-transform-pass.so.cc | 2 +- instrumentation/split-compares-pass.so.cc | 2 +- qemu_mode/libcompcov/libcompcov.so.c | 6 ++++- src/afl-cc.c | 8 +++--- src/afl-fuzz-redqueen.c | 32 +++++++++++------------ utils/afl_untracer/afl-untracer.c | 2 +- utils/libtokencap/libtokencap.so.c | 6 ++++- utils/socket_fuzzing/socketfuzz.c | 3 ++- 16 files changed, 53 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/.custom-format.py b/.custom-format.py index 1295ce55..1d5c8839 100755 --- a/.custom-format.py +++ b/.custom-format.py @@ -24,7 +24,7 @@ import importlib.metadata # string_re = re.compile('(\\"(\\\\.|[^"\\\\])*\\")') # TODO: for future use -CURRENT_LLVM = os.getenv('LLVM_VERSION', 14) +CURRENT_LLVM = os.getenv('LLVM_VERSION', 15) CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN", "") diff --git a/frida_mode/src/lib/lib_apple.c b/frida_mode/src/lib/lib_apple.c index 634e0e30..d29d0303 100644 --- a/frida_mode/src/lib/lib_apple.c +++ b/frida_mode/src/lib/lib_apple.c @@ -17,8 +17,8 @@ static gboolean lib_get_main_module(const GumModuleDetails *details, GumDarwinModule **ret = (GumDarwinModule **)user_data; GumDarwinModule *module = gum_darwin_module_new_from_memory( - details->path, mach_task_self(), details->range->base_address, - GUM_DARWIN_MODULE_FLAGS_NONE, NULL); + details->path, mach_task_self(), details->range->base_address, + GUM_DARWIN_MODULE_FLAGS_NONE, NULL); FVERBOSE("Found main module: %s", module->name); diff --git a/include/config.h b/include/config.h index 764c29dc..194786f7 100644 --- a/include/config.h +++ b/include/config.h @@ -81,7 +81,7 @@ will be kept and written to the crash/ directory as RECORD:... files. Note that every crash will be written, not only unique ones! */ -//#define AFL_PERSISTENT_RECORD +// #define AFL_PERSISTENT_RECORD /* console output colors: There are three ways to configure its behavior * 1. default: colored outputs fixed on: defined USE_COLOR && defined diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index b3b0d2cd..d7b03634 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1478,8 +1478,8 @@ GlobalVariable *ModuleSanitizerCoverageLTO::CreateFunctionLocalArrayInSection( ArrayType *ArrayTy = ArrayType::get(Ty, NumElements); auto Array = new GlobalVariable( - *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage, - Constant::getNullValue(ArrayTy), "__sancov_gen_"); + *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage, + Constant::getNullValue(ArrayTy), "__sancov_gen_"); #if LLVM_VERSION_MAJOR >= 13 if (TargetTriple.supportsCOMDAT() && diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 41c38283..8fed2042 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -714,8 +714,8 @@ GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection( ArrayType *ArrayTy = ArrayType::get(Ty, NumElements); auto Array = new GlobalVariable( - *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage, - Constant::getNullValue(ArrayTy), "__sancov_gen_"); + *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage, + Constant::getNullValue(ArrayTy), "__sancov_gen_"); #if LLVM_VERSION_MAJOR >= 13 if (TargetTriple.supportsCOMDAT() && diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 5372fae0..3f8b519b 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -544,12 +544,12 @@ static void __afl_map_shm(void) { if (__afl_map_size && __afl_map_size > MAP_SIZE) { - u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE"); - if (!map_env || atoi((char *)map_env) < MAP_SIZE) { + u8 *map_env = (u8 *)getenv("AFL_MAP_SIZE"); + if (!map_env || atoi((char *)map_env) < MAP_SIZE) { - fprintf(stderr, "FS_ERROR_MAP_SIZE\n"); - send_forkserver_error(FS_ERROR_MAP_SIZE); - _exit(1); + fprintf(stderr, "FS_ERROR_MAP_SIZE\n"); + send_forkserver_error(FS_ERROR_MAP_SIZE); + _exit(1); } @@ -561,13 +561,13 @@ static void __afl_map_shm(void) { if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) { - if (__afl_map_addr) + if (__afl_map_addr) send_forkserver_error(FS_ERROR_MAP_ADDR); else send_forkserver_error(FS_ERROR_SHMAT); perror("shmat for map"); - _exit(1); + _exit(1); } diff --git a/instrumentation/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc index db5bd55e..61f97d77 100644 --- a/instrumentation/afl-llvm-lto-instrumentlist.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc @@ -45,7 +45,7 @@ #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" -//#include "llvm/Transforms/IPO/PassManagerBuilder.h" +// #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/IR/PassManager.h" diff --git a/instrumentation/cmplog-routines-pass.cc b/instrumentation/cmplog-routines-pass.cc index 39db5aa4..c3fbed8d 100644 --- a/instrumentation/cmplog-routines-pass.cc +++ b/instrumentation/cmplog-routines-pass.cc @@ -542,7 +542,7 @@ bool CmpLogRoutines::hookRtns(Module &M) { Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); Value *v3Pbitcast = IRB.CreateBitCast( - v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits())); + v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits())); Value *v3Pcasted = IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false); args.push_back(v1Pcasted); @@ -608,7 +608,7 @@ bool CmpLogRoutines::hookRtns(Module &M) { Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy); Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy); Value *v3Pbitcast = IRB.CreateBitCast( - v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits())); + v3P, IntegerType::get(C, v3P->getType()->getPrimitiveSizeInBits())); Value *v3Pcasted = IRB.CreateIntCast(v3Pbitcast, IntegerType::get(C, 64), false); args.push_back(v1Pcasted); diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index efc99d20..5dd705cf 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -623,7 +623,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, IRBuilder<> cur_lenchk_IRB(&*(cur_lenchk_bb->getFirstInsertionPt())); Value *icmp = cur_lenchk_IRB.CreateICmpEQ( - sizedValue, ConstantInt::get(sizedValue->getType(), i)); + sizedValue, ConstantInt::get(sizedValue->getType(), i)); cur_lenchk_IRB.CreateCondBr(icmp, end_bb, cur_cmp_bb); cur_lenchk_bb->getTerminator()->eraseFromParent(); diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 8a07610c..aec6758e 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -60,7 +60,7 @@ using namespace llvm; // uncomment this toggle function verification at each step. horribly slow, but // helps to pinpoint a potential problem in the splitting code. -//#define VERIFY_TOO_MUCH 1 +// #define VERIFY_TOO_MUCH 1 namespace { diff --git a/qemu_mode/libcompcov/libcompcov.so.c b/qemu_mode/libcompcov/libcompcov.so.c index b6ee0019..b57e9701 100644 --- a/qemu_mode/libcompcov/libcompcov.so.c +++ b/qemu_mode/libcompcov/libcompcov.so.c @@ -68,7 +68,11 @@ static int debug_fd = -1; #define MAX_MAPPINGS 1024 -static struct mapping { void *st, *en; } __compcov_ro[MAX_MAPPINGS]; +static struct mapping { + + void *st, *en; + +} __compcov_ro[MAX_MAPPINGS]; static u32 __compcov_ro_cnt; diff --git a/src/afl-cc.c b/src/afl-cc.c index 972ac8cd..e3cc04dd 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -933,10 +933,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - //#if LLVM_MAJOR >= 13 - // // Use the old pass manager in LLVM 14 which the AFL++ passes still - // use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager"; - //#endif + // #if LLVM_MAJOR >= 13 + // // Use the old pass manager in LLVM 14 which the AFL++ passes still + // use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager"; + // #endif if (lto_mode && !have_c) { diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 6e4a655b..d9dc50df 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -28,8 +28,8 @@ #include "afl-fuzz.h" #include "cmplog.h" -//#define _DEBUG -//#define CMPLOG_INTROSPECTION +// #define _DEBUG +// #define CMPLOG_INTROSPECTION // CMP attribute enum enum { @@ -571,7 +571,7 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) { } -//#ifdef CMPLOG_SOLVE_TRANSFORM +// #ifdef CMPLOG_SOLVE_TRANSFORM static int strntoll(const char *str, size_t sz, char **end, int base, long long *out) { @@ -771,7 +771,7 @@ static void to_base64(u8 *src, u8 *dst, u32 dst_len) { #endif -//#endif +// #endif static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 pattern, u64 repl, u64 o_pattern, @@ -803,8 +803,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // o_pattern, pattern, repl, changed_val, idx, taint_len, // hshape, attr); - //#ifdef CMPLOG_SOLVE_TRANSFORM - // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3 + // #ifdef CMPLOG_SOLVE_TRANSFORM + // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3 if (afl->cmplog_enable_transform && (lvl & LVL3)) { u8 *endptr; @@ -1120,7 +1120,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - //#endif + // #endif // we only allow this for ascii2integer (above) so leave if this is the case if (unlikely(pattern == o_pattern)) { return 0; } @@ -1275,7 +1275,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // 16 = modified float, 32 = modified integer (modified = wont match // in original buffer) - //#ifdef CMPLOG_SOLVE_ARITHMETIC + // #ifdef CMPLOG_SOLVE_ARITHMETIC if (!afl->cmplog_enable_arith || lvl < LVL3 || attr == IS_TRANSFORM) { return 0; @@ -1440,8 +1440,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - //#endif /* - // CMPLOG_SOLVE_ARITHMETIC + // #endif /* + // CMPLOG_SOLVE_ARITHMETIC return 0; @@ -1948,9 +1948,9 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, #ifndef CMPLOG_COMBINE (void)(cbuf); #endif - //#ifndef CMPLOG_SOLVE_TRANSFORM - // (void)(changed_val); - //#endif + // #ifndef CMPLOG_SOLVE_TRANSFORM + // (void)(changed_val); + // #endif if (afl->fsrv.total_execs - last_update > screen_update) { @@ -2418,7 +2418,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, } - //#endif + // #endif return 0; @@ -2818,9 +2818,9 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) { } else if ((lvl & LVL1) - //#ifdef CMPLOG_SOLVE_TRANSFORM + // #ifdef CMPLOG_SOLVE_TRANSFORM || ((lvl & LVL3) && afl->cmplog_enable_transform) - //#endif + // #endif ) { if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) { diff --git a/utils/afl_untracer/afl-untracer.c b/utils/afl_untracer/afl-untracer.c index a18e314e..e1038212 100644 --- a/utils/afl_untracer/afl-untracer.c +++ b/utils/afl_untracer/afl-untracer.c @@ -288,7 +288,7 @@ library_list_t *find_library(char *name) { #pragma GCC optimize("O0") void breakpoint(void) { - if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n"); + if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n"); } diff --git a/utils/libtokencap/libtokencap.so.c b/utils/libtokencap/libtokencap.so.c index 299056ab..b21f3068 100644 --- a/utils/libtokencap/libtokencap.so.c +++ b/utils/libtokencap/libtokencap.so.c @@ -81,7 +81,11 @@ void *(*__libc_memmem)(const void *haystack, size_t haystack_len, #define MAX_MAPPINGS 1024 -static struct mapping { void *st, *en; } __tokencap_ro[MAX_MAPPINGS]; +static struct mapping { + + void *st, *en; + +} __tokencap_ro[MAX_MAPPINGS]; static u32 __tokencap_ro_cnt; static u8 __tokencap_ro_loaded; diff --git a/utils/socket_fuzzing/socketfuzz.c b/utils/socket_fuzzing/socketfuzz.c index 3ec8383b..7497519e 100644 --- a/utils/socket_fuzzing/socketfuzz.c +++ b/utils/socket_fuzzing/socketfuzz.c @@ -23,7 +23,8 @@ #include #include #include -//#include "logging.h" // switche from preeny_info() to fprintf(stderr, "Info: " +// #include "logging.h" // switched from preeny_info() to fprintf(stderr, "Info: +// " // // originals -- cgit 1.4.1 From d5e3223f0340181e74d352db3def2c98cf14d628 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 23 May 2023 09:01:49 +0200 Subject: fix custom mutator only check --- src/afl-fuzz.c | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 559a7326..4134b99e 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1746,33 +1746,6 @@ int main(int argc, char **argv_orig, char **envp) { check_if_tty(afl); if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; } - if (afl->afl_env.afl_custom_mutator_only) { - - if (!afl->custom_mutators_count) { - - if (afl->shm.cmplog_mode) { - - WARNF( - "No custom mutator loaded, using AFL_CUSTOM_MUTATOR_ONLY is " - "pointless and only allowed now to allow experiments with CMPLOG."); - - } else { - - FATAL( - "No custom mutator loaded but AFL_CUSTOM_MUTATOR_ONLY specified."); - - } - - } - - /* This ensures we don't proceed to havoc/splice */ - afl->custom_only = 1; - - /* Ensure we also skip all deterministic steps */ - afl->skip_deterministic = 1; - - } - get_core_count(afl); atexit(at_exit); @@ -1872,6 +1845,33 @@ int main(int argc, char **argv_orig, char **envp) { setup_custom_mutators(afl); + if (afl->afl_env.afl_custom_mutator_only) { + + if (!afl->custom_mutators_count) { + + if (afl->shm.cmplog_mode) { + + WARNF( + "No custom mutator loaded, using AFL_CUSTOM_MUTATOR_ONLY is " + "pointless and only allowed now to allow experiments with CMPLOG."); + + } else { + + FATAL( + "No custom mutator loaded but AFL_CUSTOM_MUTATOR_ONLY specified."); + + } + + } + + /* This ensures we don't proceed to havoc/splice */ + afl->custom_only = 1; + + /* Ensure we also skip all deterministic steps */ + afl->skip_deterministic = 1; + + } + if (afl->limit_time_sig > 0 && afl->custom_mutators_count) { if (afl->custom_only) { -- cgit 1.4.1 From dd736126dc9da78d6828cdf76f7eb8b389af7ed3 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 23 May 2023 09:06:29 +0200 Subject: allow llvm_instrument native --- src/afl-cc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/afl-cc.c b/src/afl-cc.c index e3cc04dd..64c0ce66 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1838,7 +1838,8 @@ int main(int argc, char **argv, char **envp) { } if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 || - strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0) { + strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0 || + strncasecmp(ptr2, "native", strlen("native")) == 0) { if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE) instrument_mode = INSTRUMENT_LLVMNATIVE; -- cgit 1.4.1 From 22837b5ad2d1cc6313c706ac9cb7fcd005cd3c2c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 23 May 2023 12:14:58 +0200 Subject: response file fix --- src/afl-cc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/afl-cc.c b/src/afl-cc.c index 64c0ce66..84fe70ec 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -574,14 +574,15 @@ static void process_params(u32 argc, char **argv) { } - u8 *tmpbuf = malloc(st.st_size + 1), *ptr; + u8 *tmpbuf = malloc(st.st_size + 2), *ptr; char **args = malloc(sizeof(char *) * (st.st_size >> 1)); int count = 1, cont = 0, cont_act = 0; - while (fgets(tmpbuf, st.st_size, f)) { + while (fgets(tmpbuf, st.st_size + 1, f)) { ptr = tmpbuf; - // no leading whitespace + // fprintf(stderr, "1: %s\n", ptr); + // no leading whitespace while (isspace(*ptr)) { ++ptr; @@ -603,6 +604,8 @@ static void process_params(u32 argc, char **argv) { } + // fprintf(stderr, "2: %s\n", ptr); + // remove whitespace at end while (*ptr && isspace(ptr[strlen(ptr) - 1])) { @@ -611,6 +614,7 @@ static void process_params(u32 argc, char **argv) { } + // fprintf(stderr, "3: %s\n", ptr); if (*ptr) { do { -- cgit 1.4.1 From eeed38c5f8335b5a2b69d85b950aa33682a2c079 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 23 May 2023 18:31:34 +0200 Subject: fix gnumakefile for non-gcc --- GNUmakefile | 11 ++++++++--- src/afl-fuzz-redqueen.c | 12 ++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/GNUmakefile b/GNUmakefile index 4ecdae52..6962d28a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -100,8 +100,13 @@ else LDFLAGS += $(SDK_LD) endif +COMPILER_TYPE=$(shell $(CC) --version|grep "Free Software Foundation") +ifneq ($(COMPILER_TYPE), "") + # $(info gcc is being used) + CFLAGS_OPT += -Wno-error=format-truncation -Wno-format-truncation +endif + ifeq "$(SYS)" "SunOS" - CFLAGS_OPT += -Wno-format-truncation LDFLAGS = -lkstat -lrt -lsocket -lnsl endif @@ -139,13 +144,13 @@ endif ifdef DEBUG $(info Compiling DEBUG version of binaries) - override CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror -Wno-error=format-truncation= $(CFLAGS_OPT) + override CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror $(CFLAGS_OPT) else CFLAGS ?= -O2 $(CFLAGS_OPT) # -funroll-loops is slower on modern compilers endif override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wno-pointer-arith \ - -fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" -Wno-format-truncation \ + -fPIC -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \ -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" # -fstack-protector diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index d9dc50df..7f42db3f 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -379,7 +379,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, } - if (++afl->stage_cur % screen_update == 0) { show_stats(afl); }; + if (unlikely(++afl->stage_cur % screen_update == 0)) { show_stats(afl); }; } @@ -790,7 +790,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u32 its_len = MIN(len - idx, taint_len); - if (afl->fsrv.total_execs - last_update > screen_update) { + if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) { show_stats(afl); last_update = afl->fsrv.total_execs; @@ -1455,7 +1455,7 @@ static u8 cmp_extend_encodingN(afl_state_t *afl, struct cmp_header *h, u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf, u32 len, u8 do_reverse, u8 lvl, u8 *status) { - if (afl->fsrv.total_execs - last_update > screen_update) { + if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) { show_stats(afl); last_update = afl->fsrv.total_execs; @@ -1952,7 +1952,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, // (void)(changed_val); // #endif - if (afl->fsrv.total_execs - last_update > screen_update) { + if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) { show_stats(afl); last_update = afl->fsrv.total_execs; @@ -2002,10 +2002,10 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, } - u8 lmax = MAX(l0, ol0); + u8 lmin = MIN(l0, ol0); u8 save[40]; u32 saved_idx = idx, pre, from = 0, to = 0, i, j; - u32 its_len = MIN(MIN(lmax, hshape), len - idx); + u32 its_len = MIN(MIN(lmin, hshape), len - idx); its_len = MIN(its_len, taint_len); u32 saved_its_len = its_len; -- cgit 1.4.1 From c323e0dc63e97299da4a2f775f6f1639d5e13bf0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 23 May 2023 19:46:35 +0200 Subject: revert fix --- src/afl-fuzz-redqueen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 7f42db3f..41644cb9 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -2002,10 +2002,10 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, } - u8 lmin = MIN(l0, ol0); + u8 lmax = MAX(l0, ol0); u8 save[40]; u32 saved_idx = idx, pre, from = 0, to = 0, i, j; - u32 its_len = MIN(MIN(lmin, hshape), len - idx); + u32 its_len = MIN(MIN(lmax, hshape), len - idx); its_len = MIN(its_len, taint_len); u32 saved_its_len = its_len; -- cgit 1.4.1 From ad8f7d6eb3be245202ace23d4d1dd9152647a775 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 31 May 2023 11:40:48 +0200 Subject: switch user mailinglist reference to discord --- TODO.md | 1 + src/afl-forkserver.c | 8 ++++---- src/afl-fuzz-init.c | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/TODO.md b/TODO.md index d6a2e6fd..dc02a914 100644 --- a/TODO.md +++ b/TODO.md @@ -3,6 +3,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 diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 30c8901c..7322f1ad 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1226,7 +1226,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, " - Less likely, there is a horrible bug in the fuzzer. If other " "options\n" - " fail, poke for troubleshooting " + " fail, poke the Awesome Fuzzing Discord for troubleshooting " "tips.\n"); } else { @@ -1271,7 +1271,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, " - Less likely, there is a horrible bug in the fuzzer. If other " "options\n" - " fail, poke for troubleshooting " + " fail, poke the Awesome Fuzzing Discord for troubleshooting " "tips.\n", stringify_mem_size(val_buf, sizeof(val_buf), fsrv->mem_limit << 20), fsrv->mem_limit - 1); @@ -1321,7 +1321,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, " Retry with setting AFL_MAP_SIZE=10000000.\n\n" "Otherwise there is a horrible bug in the fuzzer.\n" - "Poke for troubleshooting tips.\n"); + "Poke the Awesome Fuzzing Discord for troubleshooting tips.\n"); } else { @@ -1370,7 +1370,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, " - Less likely, there is a horrible bug in the fuzzer. If other " "options\n" - " fail, poke for troubleshooting " + " fail, poke the Awesome Fuzzing Discord for troubleshooting " "tips.\n", getenv(DEFER_ENV_VAR) ? " - You are using deferred forkserver, but __AFL_INIT() is " diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index baf56a5f..13802f40 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1012,7 +1012,7 @@ void perform_dry_run(afl_state_t *afl) { " - Least likely, there is a horrible bug in the fuzzer. If " "other options\n" - " fail, poke for " + " fail, poke the Awesome Fuzzing Discord for " "troubleshooting tips.\n", stringify_mem_size(val_buf, sizeof(val_buf), afl->fsrv.mem_limit << 20), @@ -1041,7 +1041,7 @@ void perform_dry_run(afl_state_t *afl) { " - Least likely, there is a horrible bug in the fuzzer. If " "other options\n" - " fail, poke for " + " fail, poke the Awesome Fuzzing Discord for " "troubleshooting tips.\n"); } -- cgit 1.4.1 From 9324f3f6289c62451e2add1f7553a7eda0d7d642 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 1 Jun 2023 12:19:45 +0200 Subject: rewrote PCGUARD --- GNUmakefile.llvm | 4 +- TODO.md | 2 - afl-cmin.bash | 4 +- docs/Changelog.md | 5 +- instrumentation/SanitizerCoveragePCGUARD.so.cc | 603 +++++++++---------------- src/afl-cc.c | 31 +- 6 files changed, 249 insertions(+), 400 deletions(-) (limited to 'src') diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm index 2bb4e7f8..6c68f1f3 100644 --- a/GNUmakefile.llvm +++ b/GNUmakefile.llvm @@ -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 diff --git a/TODO.md b/TODO.md index dc02a914..2b7e8fcf 100644 --- a/TODO.md +++ b/TODO.md @@ -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 diff --git a/afl-cmin.bash b/afl-cmin.bash index d390ff65..dc6d5342 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -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 diff --git a/docs/Changelog.md b/docs/Changelog.md index e99747f6..facf2196 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -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 diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 8fed2042..2abc58ec 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -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 IndirCalls); void InjectTraceForCmp(Function &F, ArrayRef CmpTraceTargets); - void InjectTraceForDiv(Function &F, - ArrayRef DivTraceTargets); - void InjectTraceForGep(Function &F, - ArrayRef GepTraceTargets); void InjectTraceForSwitch(Function &F, ArrayRef SwitchTraceTargets); bool InjectCoverage(Function &F, ArrayRef AllBlocks, @@ -173,20 +162,23 @@ class ModuleSanitizerCoverageAFL void SetNoSanitizeMetadata(Instruction *I) { +#if LLVM_VERSION_MAJOR == 15 + I->setMetadata(LLVMContext::MD_nosanitize, MDNode::get(*C, None)); +#elif 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 +207,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 +228,7 @@ llvmGetPassPluginInfo() { } -#endif - +#if LLVM_VERSION_MAJOR == 1 PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M, ModuleAnalysisManager &MAM) { @@ -257,34 +246,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(); + 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(M).getManager(); + auto DTCallback = [&FAM](Function &F) -> const DominatorTree * { + + return &FAM.getResult(F); + + }; + + auto PDTCallback = [&FAM](Function &F) -> const PostDominatorTree * { + + return &FAM.getResult(F); + + }; + if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback)) return PreservedAnalyses::none(); return PreservedAnalyses::all(); } +#endif + std::pair 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 +315,8 @@ std::pair 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 +328,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 +354,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 +365,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 +406,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 +443,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(SanCovLowestStackConstant); - if (!SanCovLowestStack) { + if (!SanCovLowestStack || SanCovLowestStack->getValueType() != IntptrTy) { C->emitError(StringRef("'") + SanCovLowestStackName + "' should not be declared by the user"); @@ -465,8 +459,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 +473,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 && Options.PCTable) { + if (Ctor && debug) { - 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}); + fprintf(stderr, "SANCOV: installed pcguard_init in ctor\n"); } - // 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) + if (!instr) { + WARNF("No instrumentation targets found."); - else { - char modeline[100]; + } 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 +512,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 +556,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 +567,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(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 +626,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 IndirCalls; - SmallVector BlocksToInstrument; - SmallVector CmpTraceTargets; - SmallVector SwitchTraceTargets; - SmallVector DivTraceTargets; - SmallVector GepTraceTargets; + SmallVector BlocksToInstrument; + SmallVector CmpTraceTargets; + SmallVector SwitchTraceTargets; const DominatorTree *DT = DTCallback(F); const PostDominatorTree *PDT = PDTCallback(F); @@ -665,47 +642,28 @@ void ModuleSanitizerCoverageAFL::instrumentFunction( if (shouldInstrumentBlock(F, &BB, DT, PDT, Options)) BlocksToInstrument.push_back(&BB); - for (auto &Inst : BB) { - - if (Options.IndirectCalls) { - - CallBase *CB = dyn_cast(&Inst); - if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst); - - } + /* + for (auto &Inst : BB) { - if (Options.TraceCmp) { + if (Options.TraceCmp) { - if (ICmpInst *CMP = dyn_cast(&Inst)) - if (IsInterestingCmp(CMP, DT, Options)) - CmpTraceTargets.push_back(&Inst); - if (isa(&Inst)) SwitchTraceTargets.push_back(&Inst); + if (ICmpInst *CMP = dyn_cast(&Inst)) + if (IsInterestingCmp(CMP, DT, Options)) + CmpTraceTargets.push_back(&Inst); + if (isa(&Inst)) + SwitchTraceTargets.push_back(&Inst); - } + } - if (Options.TraceDiv) - if (BinaryOperator *BO = dyn_cast(&Inst)) - if (BO->getOpcode() == Instruction::SDiv || - BO->getOpcode() == Instruction::UDiv) - DivTraceTargets.push_back(BO); - if (Options.TraceGep) - if (GetElementPtrInst *GEP = dyn_cast(&Inst)) - GepTraceTargets.push_back(GEP); - if (Options.StackDepth) - if (isa(Inst) || - (isa(Inst) && !isa(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 +675,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); -#else - if (TargetTriple.supportsCOMDAT() && !F.isInterposable()) - if (auto Comdat = - GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId)) - Array->setComdat(Comdat); -#endif - Array->setSection(getSectionName(Section)); -#if (LLVM_VERSION_MAJOR >= 11) || \ - (LLVM_VERSION_MAJOR == 10 && LLVM_VERSION_MINOR >= 1) - #if LLVM_VERSION_MAJOR >= 16 +#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 + Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedSize())); #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 +723,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 +751,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 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 +806,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } -#if (LLVM_VERSION_MAJOR >= 12) else if (t->getTypeID() == llvm::Type::FixedVectorTyID) { FixedVectorType *tt = dyn_cast(t); @@ -868,16 +818,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 +837,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(&IN))) { Function *Callee = callInst->getCalledFunction(); @@ -1033,12 +975,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 +999,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 +1088,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 IndirCalls) { - - if (IndirCalls.empty()) return; - for (auto I : IndirCalls) { - - IRBuilder<> IRB(I); - CallBase &CB = cast(*I); - Value *Callee = CB.getCalledOperand(); - if (isa(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 +1143,6 @@ void ModuleSanitizerCoverageAFL::InjectTraceForSwitch( } -void ModuleSanitizerCoverageAFL::InjectTraceForDiv( - Function &, ArrayRef DivTraceTargets) { - - for (auto BO : DivTraceTargets) { - - IRBuilder<> IRB(BO); - Value *A1 = BO->getOperand(1); - if (isa(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 GepTraceTargets) { - - for (auto GEP : GepTraceTargets) { - - IRBuilder<> IRB(GEP); - for (Use &Idx : GEP->indices()) - if (!isa(Idx) && Idx->getType()->isIntegerTy()) - IRB.CreateCall(SanCovTraceGepFunction, - {IRB.CreateIntCast(Idx, IntptrTy, true)}); - - } - -} - void ModuleSanitizerCoverageAFL::InjectTraceForCmp( Function &, ArrayRef CmpTraceTargets) { @@ -1321,27 +1192,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 - } - - IRBuilder<> IRB(&*IP); - - if (Options.TracePC) { + } else { - IRB.CreateCall(SanCovTracePC); - // ->setCannotMerge(); // gets the PC using GET_CALLER_PC. + EntryLoc = IP->getDebugLoc(); + if (!EntryLoc) + if (auto *SP = F.getSubprogram()) + EntryLoc = DILocation::get(SP->getContext(), 0, 0, SP); +#endif } +#if LLVM_VERSION_MAJOR >= 15 + InstrumentationIRBuilder IRB(&*IP); +#else + IRBuilder<> IRB(&*IP); +#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 +1287,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( diff --git a/src/afl-cc.c b/src/afl-cc.c index 84fe70ec..9e56828c 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -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" -- cgit 1.4.1