From 7259075b71924e7ab68546aca04fa5ecfe2d93d6 Mon Sep 17 00:00:00 2001 From: aflpp Date: Mon, 1 Mar 2021 19:13:29 +0100 Subject: len for cmplog rtn --- src/afl-fuzz-redqueen.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 1ab5f996..9bfbf95b 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -1853,7 +1853,7 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, } static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, - u8 *o_pattern, u8 *changed_val, u32 idx, + u8 *o_pattern, u8 *changed_val, u8 plen, u32 idx, u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf, u32 len, u8 lvl, u8 *status) { @@ -1866,7 +1866,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, u8 save[40]; u32 saved_idx = idx, pre, from = 0, to = 0, i, j; - u32 its_len = MIN((u32)32, len - idx); + u32 its_len = MIN((u32)plen, len - idx); its_len = MIN(its_len, taint_len); u32 saved_its_len = its_len; @@ -2365,9 +2365,9 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, status = 0; - if (unlikely(rtn_extend_encoding(afl, o->v0, o->v1, orig_o->v0, - orig_o->v1, idx, taint_len, orig_buf, - buf, cbuf, len, lvl, &status))) { + if (unlikely(rtn_extend_encoding( + afl, o->v0, o->v1, orig_o->v0, orig_o->v1, SHAPE_BYTES(h->shape), + idx, taint_len, orig_buf, buf, cbuf, len, lvl, &status))) { return 1; @@ -2382,9 +2382,9 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, status = 0; - if (unlikely(rtn_extend_encoding(afl, o->v1, o->v0, orig_o->v1, - orig_o->v0, idx, taint_len, orig_buf, - buf, cbuf, len, lvl, &status))) { + if (unlikely(rtn_extend_encoding( + afl, o->v1, o->v0, orig_o->v1, orig_o->v0, SHAPE_BYTES(h->shape), + idx, taint_len, orig_buf, buf, cbuf, len, lvl, &status))) { return 1; -- cgit 1.4.1 From 108e588e888df5c2679600ea49846a565bac23f9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 2 Mar 2021 17:46:43 +0100 Subject: add de-unicoded dictionary entries --- docs/Changelog.md | 2 + include/afl-fuzz.h | 1 + src/afl-fuzz-extras.c | 149 ++++++++++++++++++++++++++++++++++++++++++-------- src/afl-fuzz.c | 7 ++- 4 files changed, 134 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index 01240b2a..376f5f06 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,8 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.11a (dev) + - afl-fuzz + - add non-unicode variants from unicode-looking dictionary entries - afl-cc - fixed for a crash that can occur with ASAN + CMPLOG together plus better support for unicode (thanks to @stbergmann for reporting!) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 3531d672..5003b563 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1062,6 +1062,7 @@ u8 has_new_bits_unclassified(afl_state_t *, u8 *); void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32); void load_extras(afl_state_t *, u8 *); void dedup_extras(afl_state_t *); +void deunicode_extras(afl_state_t *); void add_extra(afl_state_t *afl, u8 *mem, u32 len); void maybe_add_auto(afl_state_t *, u8 *, u32); void save_auto(afl_state_t *); diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 7ecad233..52100fa1 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -387,6 +387,130 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) { } +/* add an extra/dict/token - no checks performed, no sorting */ + +static void add_extra_nocheck(afl_state_t *afl, u8 *mem, u32 len) { + + afl->extras = afl_realloc((void **)&afl->extras, + (afl->extras_cnt + 1) * sizeof(struct extra_data)); + + if (unlikely(!afl->extras)) { PFATAL("alloc"); } + + afl->extras[afl->extras_cnt].data = ck_alloc(len); + afl->extras[afl->extras_cnt].len = len; + memcpy(afl->extras[afl->extras_cnt].data, mem, len); + afl->extras_cnt++; + + /* We only want to print this once */ + + if (afl->extras_cnt == afl->max_det_extras + 1) { + + WARNF("More than %u tokens - will use them probabilistically.", + afl->max_det_extras); + + } + +} + +/* Sometimes strings in input is transformed to unicode internally, so for + fuzzing we should attempt to de-unicode if it looks like simple unicode */ + +void deunicode_extras(afl_state_t *afl) { + + if (!afl->extras_cnt) return; + + u32 i, j, orig_cnt = afl->extras_cnt; + u8 buf[64]; + + for (i = 0; i < orig_cnt; ++i) { + + if (afl->extras[i].len < 6 || afl->extras[i].len > 64 || + afl->extras[i].len % 2) { + + continue; + + } + + u32 k = 0, z1 = 0, z2 = 0, z3 = 0, z4 = 0, half = afl->extras[i].len >> 1; + u32 quarter = half >> 1; + + for (j = 0; j < afl->extras[i].len; ++j) { + + switch (j % 4) { + + case 2: + if (!afl->extras[i].data[j]) { ++z3; } + // fall through + case 0: + if (!afl->extras[i].data[j]) { ++z1; } + break; + case 3: + if (!afl->extras[i].data[j]) { ++z4; } + // fall through + case 1: + if (!afl->extras[i].data[j]) { ++z2; } + break; + + } + + } + + if ((z1 < half && z2 < half) || z1 + z2 == afl->extras[i].len) { continue; } + + // also maybe 32 bit unicode? + if (afl->extras[i].len % 4 == 0 && afl->extras[i].len >= 12 && + (z3 == quarter || z4 == quarter) && z1 + z2 == quarter * 3) { + + for (j = 0; j < afl->extras[i].len; ++j) { + + if (z4 < quarter) { + + if (j % 4 == 3) { buf[k++] = afl->extras[i].data[j]; } + + } else if (z3 < quarter) { + + if (j % 4 == 2) { buf[k++] = afl->extras[i].data[j]; } + + } else if (z2 < half) { + + if (j % 4 == 1) { buf[k++] = afl->extras[i].data[j]; } + + } else { + + if (j % 4 == 0) { buf[k++] = afl->extras[i].data[j]; } + + } + + } + + add_extra_nocheck(afl, buf, k); + k = 0; + + } + + for (j = 0; j < afl->extras[i].len; ++j) { + + if (z1 < half) { + + if (j % 2 == 0) { buf[k++] = afl->extras[i].data[j]; } + + } else { + + if (j % 2 == 1) { buf[k++] = afl->extras[i].data[j]; } + + } + + } + + add_extra_nocheck(afl, buf, k); + + } + + qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data), + compare_extras_len); + +} + /* Removes duplicates from the loaded extras. This can happen if multiple files are loaded */ @@ -396,9 +520,9 @@ void dedup_extras(afl_state_t *afl) { u32 i, j, orig_cnt = afl->extras_cnt; - for (i = 0; i < afl->extras_cnt - 1; i++) { + for (i = 0; i < afl->extras_cnt - 1; ++i) { - for (j = i + 1; j < afl->extras_cnt; j++) { + for (j = i + 1; j < afl->extras_cnt; ++j) { restart_dedup: @@ -462,30 +586,11 @@ void add_extra(afl_state_t *afl, u8 *mem, u32 len) { } - afl->extras = afl_realloc((void **)&afl->extras, - (afl->extras_cnt + 1) * sizeof(struct extra_data)); - - if (unlikely(!afl->extras)) { PFATAL("alloc"); } - - afl->extras[afl->extras_cnt].data = ck_alloc(len); - afl->extras[afl->extras_cnt].len = len; - - memcpy(afl->extras[afl->extras_cnt].data, mem, len); - - afl->extras_cnt++; + add_extra_nocheck(afl, mem, len); qsort(afl->extras, afl->extras_cnt, sizeof(struct extra_data), compare_extras_len); - /* We only want to print this once */ - - if (afl->extras_cnt == afl->max_det_extras + 1) { - - WARNF("More than %u tokens - will use them probabilistically.", - afl->max_det_extras); - - } - } /* Maybe add automatic extra. */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a02eadb2..90f77919 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1449,9 +1449,6 @@ int main(int argc, char **argv_orig, char **envp) { } - dedup_extras(afl); - OKF("Loaded a total of %u extras.", afl->extras_cnt); - } if (!afl->timeout_given) { find_timeout(afl); } // only for resumes! @@ -1681,6 +1678,10 @@ int main(int argc, char **argv_orig, char **envp) { } + deunicode_extras(afl); + dedup_extras(afl); + if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); } + // after we have the correct bitmap size we can read the bitmap -B option // and set the virgin maps if (afl->in_bitmap) { -- cgit 1.4.1 From f0c7967fbf4d6d3906693896f511b6679573c02b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 3 Mar 2021 08:58:09 +0100 Subject: add new tutorial --- README.md | 1 + src/afl-fuzz.c | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/README.md b/README.md index 800c2121..992dcd86 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,7 @@ Here are some good writeups to show how to effectively use AFL++: * [https://securitylab.github.com/research/fuzzing-software-2](https://securitylab.github.com/research/fuzzing-software-2) * [https://securitylab.github.com/research/fuzzing-sockets-FTP](https://securitylab.github.com/research/fuzzing-sockets-FTP) * [https://securitylab.github.com/research/fuzzing-sockets-FreeRDP](https://securitylab.github.com/research/fuzzing-sockets-FreeRDP) + * [https://securitylab.github.com/research/fuzzing-apache-1](https://securitylab.github.com/research/fuzzing-apache-1) If you are interested in fuzzing structured data (where you define what the structure is), these links have you covered: diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 90f77919..09aff4fb 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1437,20 +1437,8 @@ int main(int argc, char **argv_orig, char **envp) { // read_foreign_testcases(afl, 1); for the moment dont do this OKF("Loaded a total of %u seeds.", afl->queued_paths); - load_auto(afl); - pivot_inputs(afl); - if (extras_dir_cnt) { - - for (i = 0; i < extras_dir_cnt; i++) { - - load_extras(afl, extras_dir[i]); - - } - - } - if (!afl->timeout_given) { find_timeout(afl); } // only for resumes! if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL && @@ -1678,6 +1666,18 @@ int main(int argc, char **argv_orig, char **envp) { } + load_auto(afl); + + if (extras_dir_cnt) { + + for (i = 0; i < extras_dir_cnt; i++) { + + load_extras(afl, extras_dir[i]); + + } + + } + deunicode_extras(afl); dedup_extras(afl); if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); } -- cgit 1.4.1 From 1e76079e93f5b4a9729367dd982d632013669bc5 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 4 Mar 2021 11:32:32 +0100 Subject: llvm mode CALLER mode --- instrumentation/README.ctx.md | 22 +++++++++++++++++++--- instrumentation/afl-llvm-pass.so.cc | 18 ++++++++++-------- src/afl-cc.c | 37 +++++++++++++++++++++++++------------ 3 files changed, 54 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/instrumentation/README.ctx.md b/instrumentation/README.ctx.md index caf2c09a..ffcce0a9 100644 --- a/instrumentation/README.ctx.md +++ b/instrumentation/README.ctx.md @@ -4,14 +4,19 @@ This is an LLVM-based implementation of the context sensitive branch coverage. -Basically every function gets its own ID and that ID is combined with the -edges of the called functions. +Basically every function gets its own ID and, every time that an edge is logged, +all the IDs in the callstack are hashed and combined with the edge transition +hash to augment the classic edge coverage with the information about the +calling context. So if both function A and function B call a function C, the coverage collected in C will be different. In math the coverage is collected as follows: -`map[current_location_ID ^ previous_location_ID >> 1 ^ previous_callee_ID] += 1` +`map[current_location_ID ^ previous_location_ID >> 1 ^ hash_callstack_IDs] += 1` + +The callstack hash is produced XOR-ing the function IDs to avoid explosion with +recusrsive functions. ## Usage @@ -20,3 +25,14 @@ Set the `AFL_LLVM_INSTRUMENT=CTX` or `AFL_LLVM_CTX=1` environment variable. It is highly recommended to increase the MAP_SIZE_POW2 definition in config.h to at least 18 and maybe up to 20 for this as otherwise too many map collisions occur. + +## Caller Branch Coverage + +If the context sensitive coverage introduces too may collisions becoming +decremental, the user can choose to augment edge coverage with just the +called function ID, instead of the entire callstack hash. + +In math the coverage is collected as follows: +`map[current_location_ID ^ previous_location_ID >> 1 ^ previous_callee_ID] += 1` + +Set the `AFL_LLVM_INSTRUMENT=CALLER` or `AFL_LLVM_CALLER=1` environment variable. diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 87267e35..d06d3201 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -84,7 +84,7 @@ class AFLCoverage : public ModulePass { uint32_t ngram_size = 0; uint32_t map_size = MAP_SIZE; uint32_t function_minimum_size = 1; - char * ctx_str = NULL, *skip_nozero = NULL; + char * ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; }; @@ -187,6 +187,7 @@ bool AFLCoverage::runOnModule(Module &M) { char *ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE"); if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE"); ctx_str = getenv("AFL_LLVM_CTX"); + caller_str = getenv("AFL_LLVM_CALLER"); #ifdef AFL_HAVE_VECTOR_INTRINSICS /* Decide previous location vector size (must be a power of two) */ @@ -240,7 +241,7 @@ bool AFLCoverage::runOnModule(Module &M) { GlobalVariable *AFLPrevLoc; GlobalVariable *AFLContext = NULL; - if (ctx_str) + if (ctx_str || caller_str) #if defined(__ANDROID__) || defined(__HAIKU__) AFLContext = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx"); @@ -318,7 +319,7 @@ bool AFLCoverage::runOnModule(Module &M) { IRBuilder<> IRB(&(*IP)); // Context sensitive coverage - if (ctx_str && &BB == &F.getEntryBlock()) { + if ((ctx_str || caller_str) && &BB == &F.getEntryBlock()) { // load the context ID of the previous function and write to to a local // variable on the stack @@ -354,8 +355,9 @@ bool AFLCoverage::runOnModule(Module &M) { // if yes we store a context ID for this function in the global var if (has_calls) { - Value *NewCtx = IRB.CreateXor( - PrevCtx, ConstantInt::get(Int32Ty, AFL_R(map_size))); + Value *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size)); + if (ctx_str) + NewCtx = IRB.CreateXor(PrevCtx, NewCtx); StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext); StoreCtx->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); @@ -412,7 +414,7 @@ bool AFLCoverage::runOnModule(Module &M) { // in CTX mode we have to restore the original context for the caller - // she might be calling other functions which need the correct CTX - if (ctx_str && has_calls) { + if ((ctx_str || caller_str) && has_calls) { Instruction *Inst = BB.getTerminator(); if (isa(Inst) || isa(Inst)) { @@ -459,7 +461,7 @@ bool AFLCoverage::runOnModule(Module &M) { #endif PrevLocTrans = PrevLoc; - if (ctx_str) + if (ctx_str || caller_str) PrevLocTrans = IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty); else @@ -546,7 +548,7 @@ bool AFLCoverage::runOnModule(Module &M) { // in CTX mode we have to restore the original context for the caller - // she might be calling other functions which need the correct CTX. // Currently this is only needed for the Ubuntu clang-6.0 bug - if (ctx_str && has_calls) { + if ((ctx_str || caller_str) && has_calls) { Instruction *Inst = BB.getTerminator(); if (isa(Inst) || isa(Inst)) { diff --git a/src/afl-cc.c b/src/afl-cc.c index c3910e6d..9cf02059 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -73,7 +73,8 @@ enum { INSTRUMENT_GCC = 6, INSTRUMENT_CLANG = 7, INSTRUMENT_OPT_CTX = 8, - INSTRUMENT_OPT_NGRAM = 16 + INSTRUMENT_OPT_NGRAM = 16, + INSTRUMENT_OPT_CALLER = 32, }; @@ -1273,7 +1274,8 @@ int main(int argc, char **argv, char **envp) { } if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX; - + if (getenv("AFL_LLVM_CALLER")) instrument_opt_mode |= INSTRUMENT_OPT_CALLER; + if (getenv("AFL_LLVM_NGRAM_SIZE")) { instrument_opt_mode |= INSTRUMENT_OPT_NGRAM; @@ -1387,6 +1389,13 @@ int main(int argc, char **argv, char **envp) { setenv("AFL_LLVM_CTX", "1", 1); } + + if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) { + + instrument_opt_mode |= INSTRUMENT_OPT_CALLER; + setenv("AFL_LLVM_CALLER", "1", 1); + + } if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) { @@ -1420,6 +1429,11 @@ int main(int argc, char **argv, char **envp) { } } + + if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) && + (instrument_opt_mode & INSTRUMENT_OPT_CALLER)) { + FATAL("you cannot set CTX and CALLER together"); + } if (instrument_opt_mode && instrument_mode == INSTRUMENT_DEFAULT && (compiler_mode == LLVM || compiler_mode == UNSET)) { @@ -1770,7 +1784,7 @@ int main(int argc, char **argv, char **envp) { } if (instrument_opt_mode && compiler_mode != LLVM) - FATAL("CTX and NGRAM can only be used in LLVM mode"); + FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode"); if (!instrument_opt_mode) { @@ -1780,15 +1794,14 @@ int main(int argc, char **argv, char **envp) { } else { - if (instrument_opt_mode == INSTRUMENT_OPT_CTX) - - ptr = alloc_printf("%s + CTX", instrument_mode_string[instrument_mode]); - else if (instrument_opt_mode == INSTRUMENT_OPT_NGRAM) - ptr = alloc_printf("%s + NGRAM-%u", - instrument_mode_string[instrument_mode], ngram_size); - else - ptr = alloc_printf("%s + CTX + NGRAM-%u", - instrument_mode_string[instrument_mode], ngram_size); + char *ptr2 = alloc_printf(" + NGRAM-%u", ngram_size); + ptr = alloc_printf("%s%s%s%s", instrument_mode_string[instrument_mode], + (instrument_opt_mode & INSTRUMENT_OPT_CTX) ? " + CTX" : "", + (instrument_opt_mode & INSTRUMENT_OPT_CALLER) ? " + CALLER" : "", + (instrument_opt_mode & INSTRUMENT_OPT_NGRAM) ? ptr2 : "" + ); + + ck_free(ptr2); } -- cgit 1.4.1 From 8f538e77ed75256466e8b97d43d0c32948cb9931 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 4 Mar 2021 11:33:51 +0100 Subject: code format --- instrumentation/afl-llvm-pass.so.cc | 5 ++--- src/afl-cc.c | 16 +++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index d06d3201..33898aec 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -356,9 +356,8 @@ bool AFLCoverage::runOnModule(Module &M) { if (has_calls) { Value *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size)); - if (ctx_str) - NewCtx = IRB.CreateXor(PrevCtx, NewCtx); - StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext); + if (ctx_str) NewCtx = IRB.CreateXor(PrevCtx, NewCtx); + StoreInst *StoreCtx = IRB.CreateStore(NewCtx, AFLContext); StoreCtx->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); diff --git a/src/afl-cc.c b/src/afl-cc.c index 9cf02059..0c689286 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1275,7 +1275,7 @@ int main(int argc, char **argv, char **envp) { if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX; if (getenv("AFL_LLVM_CALLER")) instrument_opt_mode |= INSTRUMENT_OPT_CALLER; - + if (getenv("AFL_LLVM_NGRAM_SIZE")) { instrument_opt_mode |= INSTRUMENT_OPT_NGRAM; @@ -1389,7 +1389,7 @@ int main(int argc, char **argv, char **envp) { setenv("AFL_LLVM_CTX", "1", 1); } - + if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) { instrument_opt_mode |= INSTRUMENT_OPT_CALLER; @@ -1429,10 +1429,12 @@ int main(int argc, char **argv, char **envp) { } } - + if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) && (instrument_opt_mode & INSTRUMENT_OPT_CALLER)) { + FATAL("you cannot set CTX and CALLER together"); + } if (instrument_opt_mode && instrument_mode == INSTRUMENT_DEFAULT && @@ -1795,12 +1797,12 @@ int main(int argc, char **argv, char **envp) { } else { char *ptr2 = alloc_printf(" + NGRAM-%u", ngram_size); - ptr = alloc_printf("%s%s%s%s", instrument_mode_string[instrument_mode], + ptr = alloc_printf( + "%s%s%s%s", instrument_mode_string[instrument_mode], (instrument_opt_mode & INSTRUMENT_OPT_CTX) ? " + CTX" : "", (instrument_opt_mode & INSTRUMENT_OPT_CALLER) ? " + CALLER" : "", - (instrument_opt_mode & INSTRUMENT_OPT_NGRAM) ? ptr2 : "" - ); - + (instrument_opt_mode & INSTRUMENT_OPT_NGRAM) ? ptr2 : ""); + ck_free(ptr2); } -- cgit 1.4.1 From 96c526cb78512737a980726dd32c95593edb8cd1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 4 Mar 2021 14:04:40 +0100 Subject: fix caller/ctx change, support dlopen in afl-compiler-rt --- docs/Changelog.md | 10 ++++ instrumentation/LLVMInsTrim.so.cc | 29 ++++----- instrumentation/afl-compiler-rt.o.c | 114 +++++++++++++++++++++++++++++++----- src/afl-cc.c | 31 ++++++---- 4 files changed, 144 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/docs/Changelog.md b/docs/Changelog.md index 1be41267..6fe3517a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -14,6 +14,16 @@ sending a mail to . - afl-cc - fixed a crash that can occur with ASAN + CMPLOG together plus better support for unicode (thanks to @stbergmann for reporting!) + - handle erroneous setups in which multiple afl-compiler-rt are + compiled into the target. This now also supports dlopen instrumented + libs loaded before the forkserver. + - Renamed CTX to CALLER, added correct/real CTX implemenation to CLASSIC + - qemu_mode + - added AFL_QEMU_EXCLUDE_RANGES env by @realmadsci, thanks! + - if no new/updated checkout is wanted, build with: + NO_CHECKOUT=1 ./build_qemu_support.sh + - we no longer perform a "git drop" + ### Version ++3.10c (release) - Mac OS ARM64 support diff --git a/instrumentation/LLVMInsTrim.so.cc b/instrumentation/LLVMInsTrim.so.cc index 948f8f3a..f0de6536 100644 --- a/instrumentation/LLVMInsTrim.so.cc +++ b/instrumentation/LLVMInsTrim.so.cc @@ -135,7 +135,7 @@ struct InsTrim : public ModulePass { unsigned int PrevLocSize = 0; char * ngram_size_str = getenv("AFL_LLVM_NGRAM_SIZE"); if (!ngram_size_str) ngram_size_str = getenv("AFL_NGRAM_SIZE"); - char *ctx_str = getenv("AFL_LLVM_CTX"); + char *caller_str = getenv("AFL_LLVM_CALLER"); #ifdef AFL_HAVE_VECTOR_INTRINSICS unsigned int ngram_size = 0; @@ -197,9 +197,9 @@ struct InsTrim : public ModulePass { GlobalValue::ExternalLinkage, 0, "__afl_area_ptr"); GlobalVariable *AFLPrevLoc; GlobalVariable *AFLContext = NULL; - LoadInst * PrevCtx = NULL; // for CTX sensitive coverage + LoadInst * PrevCaller = NULL; // for CALLER sensitive coverage - if (ctx_str) + if (caller_str) #if defined(__ANDROID__) || defined(__HAIKU__) AFLContext = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx"); @@ -398,11 +398,11 @@ struct InsTrim : public ModulePass { unsigned int cur_loc; // Context sensitive coverage - if (ctx_str && &BB == &F.getEntryBlock()) { + if (caller_str && &BB == &F.getEntryBlock()) { - PrevCtx = IRB.CreateLoad(AFLContext); - PrevCtx->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); + PrevCaller = IRB.CreateLoad(AFLContext); + PrevCaller->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); // does the function have calls? and is any of the calls larger than // one basic block? @@ -441,7 +441,7 @@ struct InsTrim : public ModulePass { } - } // END of ctx_str + } // END of caller_str if (MarkSetOpt && MS.find(&BB) == MS.end()) { continue; } @@ -485,9 +485,9 @@ struct InsTrim : public ModulePass { #endif PrevLocTrans = IRB.CreateZExt(PrevLoc, IRB.getInt32Ty()); - if (ctx_str) + if (caller_str) PrevLocTrans = - IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCtx), Int32Ty); + IRB.CreateZExt(IRB.CreateXor(PrevLocTrans, PrevCaller), Int32Ty); /* Load SHM pointer */ LoadInst *MapPtr = IRB.CreateLoad(AFLMapPtr); @@ -535,16 +535,17 @@ struct InsTrim : public ModulePass { IRB.CreateStore(Incr, MapPtrIdx) ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - if (ctx_str && has_calls) { + if (caller_str && has_calls) { - // in CTX mode we have to restore the original context for the + // in CALLER mode we have to restore the original context for the // caller - she might be calling other functions which need the - // correct CTX + // correct CALLER Instruction *Inst = BB.getTerminator(); if (isa(Inst) || isa(Inst)) { IRBuilder<> Post_IRB(Inst); - StoreInst * RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext); + StoreInst * RestoreCtx = + Post_IRB.CreateStore(PrevCaller, AFLContext); RestoreCtx->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index c9577a55..e3aa787f 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -123,6 +123,17 @@ static u8 is_persistent; static u8 _is_sancov; +/* Debug? */ + +static u32 __afl_debug; + +/* Already initialized markers */ + +static u32 __afl_already_initialized_shm; +static u32 __afl_already_initialized_forkserver; +static u32 __afl_already_initialized_first; +static u32 __afl_already_initialized_second; + /* Dummy pipe for area_is_valid() */ static int __afl_dummy_fd[2] = {2, 2}; @@ -176,7 +187,7 @@ static void __afl_map_shm_fuzz() { char *id_str = getenv(SHM_FUZZ_ENV_VAR); - if (getenv("AFL_DEBUG")) { + if (__afl_debug) { fprintf(stderr, "DEBUG: fuzzcase shmem %s\n", id_str ? id_str : "none"); @@ -222,7 +233,7 @@ static void __afl_map_shm_fuzz() { __afl_fuzz_len = (u32 *)map; __afl_fuzz_ptr = map + sizeof(u32); - if (getenv("AFL_DEBUG")) { + if (__afl_debug) { fprintf(stderr, "DEBUG: successfully got fuzzing shared memory\n"); @@ -242,7 +253,6 @@ static void __afl_map_shm_fuzz() { static void __afl_map_shm(void) { - static u32 __afl_already_initialized_shm = 0; if (__afl_already_initialized_shm) return; __afl_already_initialized_shm = 1; @@ -303,7 +313,7 @@ static void __afl_map_shm(void) { early-stage __afl_area_initial region that is needed to allow some really hacky .init code to work correctly in projects such as OpenSSL. */ - if (getenv("AFL_DEBUG")) + if (__afl_debug) fprintf(stderr, "DEBUG: id_str %s, __afl_area_ptr %p, __afl_area_initial %p, " "__afl_map_addr 0x%llx, MAP_SIZE %u, __afl_final_loc %u, " @@ -359,17 +369,18 @@ static void __afl_map_shm(void) { } + close(shm_fd); + if (shm_base == MAP_FAILED) { - close(shm_fd); shm_fd = -1; - fprintf(stderr, "mmap() failed\n"); + perror("mmap for map"); + if (__afl_map_addr) send_forkserver_error(FS_ERROR_MAP_ADDR); else send_forkserver_error(FS_ERROR_MMAP); - perror("mmap for map"); exit(2); @@ -476,7 +487,7 @@ static void __afl_map_shm(void) { id_str = getenv(CMPLOG_SHM_ENV_VAR); - if (getenv("AFL_DEBUG")) { + if (__afl_debug) { fprintf(stderr, "DEBUG: cmplog id_str %s\n", id_str == NULL ? "" : id_str); @@ -541,6 +552,58 @@ static void __afl_map_shm(void) { } +/* unmap SHM. */ + +static void __afl_unmap_shm(void) { + + if (!__afl_already_initialized_shm) return; + + char *id_str = getenv(SHM_ENV_VAR); + + if (id_str) { + +#ifdef USEMMAP + + munmap((void *)__afl_area_ptr, __afl_map_size); + +#else + + shmdt((void *)__afl_area_ptr); + +#endif + + } else if ((!__afl_area_ptr || __afl_area_ptr == __afl_area_initial) && + + __afl_map_addr) { + + munmap((void *)__afl_map_addr, __afl_map_size); + + } + + __afl_area_ptr = __afl_area_ptr_dummy; + + id_str = getenv(CMPLOG_SHM_ENV_VAR); + + if (id_str) { + +#ifdef USEMMAP + + munmap((void *)__afl_cmp_map, __afl_map_size); + +#else + + shmdt((void *)__afl_cmp_map); + +#endif + + __afl_cmp_map = NULL; + + } + + __afl_already_initialized_shm = 0; + +} + #ifdef __linux__ static void __afl_start_snapshots(void) { @@ -569,7 +632,7 @@ static void __afl_start_snapshots(void) { if (read(FORKSRV_FD, &was_killed, 4) != 4) { _exit(1); } - if (getenv("AFL_DEBUG")) { + if (__afl_debug) { fprintf(stderr, "target forkserver recv: %08x\n", was_killed); @@ -746,7 +809,6 @@ static void __afl_start_snapshots(void) { static void __afl_start_forkserver(void) { - static u32 __afl_already_initialized_forkserver = 0; if (__afl_already_initialized_forkserver) return; __afl_already_initialized_forkserver = 1; @@ -800,7 +862,7 @@ static void __afl_start_forkserver(void) { if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); - if (getenv("AFL_DEBUG")) { + if (__afl_debug) { fprintf(stderr, "target forkserver recv: %08x\n", was_killed); @@ -1035,7 +1097,7 @@ void __afl_manual_init(void) { __afl_sharedmem_fuzzing = 0; if (__afl_area_ptr == NULL) __afl_area_ptr = __afl_area_ptr_dummy; - if (getenv("AFL_DEBUG")) + if (__afl_debug) fprintf(stderr, "DEBUG: disabled instrumentation because of " "AFL_DISABLE_LLVM_INSTRUMENTATION\n"); @@ -1079,10 +1141,11 @@ __attribute__((constructor(CTOR_PRIO))) void __afl_auto_early(void) { __attribute__((constructor(1))) void __afl_auto_second(void) { - static u32 __afl_already_initialized_second = 0; if (__afl_already_initialized_second) return; __afl_already_initialized_second = 1; + if (getenv("AFL_DEBUG")) { __afl_debug = 1; } + if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return; u8 *ptr; @@ -1114,7 +1177,6 @@ __attribute__((constructor(1))) void __afl_auto_second(void) { __attribute__((constructor(0))) void __afl_auto_first(void) { - static u32 __afl_already_initialized_first = 0; if (__afl_already_initialized_first) return; __afl_already_initialized_first = 1; @@ -1198,7 +1260,7 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { _is_sancov = 1; - if (getenv("AFL_DEBUG")) { + if (__afl_debug) { fprintf(stderr, "Running __sanitizer_cov_trace_pc_guard_init: %p-%p (%lu edges)\n", @@ -1235,6 +1297,28 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { } + if (__afl_debug) { + + fprintf(stderr, + "Done __sanitizer_cov_trace_pc_guard_init: __afl_final_loc = %u\n", + __afl_final_loc); + + } + + if (__afl_already_initialized_shm && __afl_final_loc > __afl_map_size) { + + if (__afl_debug) { + + fprintf(stderr, "Reinit shm necessary (+%u)\n", + __afl_final_loc - __afl_map_size); + + } + + __afl_unmap_shm(); + __afl_map_shm(); + + } + } ///// CmpLog instrumentation diff --git a/src/afl-cc.c b/src/afl-cc.c index 0c689286..ab794877 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -89,7 +89,7 @@ char instrument_mode_string[18][18] = { "GCC", "CLANG", "CTX", - "", + "CALLER", "", "", "", @@ -1514,12 +1514,13 @@ int main(int argc, char **argv, char **envp) { " CLASSIC %s no yes module yes yes " "yes\n" " - NORMAL\n" + " - CALLER\n" " - CTX\n" " - NGRAM-{2-16}\n" " INSTRIM no yes module yes yes " " yes\n" " - NORMAL\n" - " - CTX\n" + " - CALLER\n" " - NGRAM-{2-16}\n" " [GCC_PLUGIN] gcc plugin: %s%s\n" " CLASSIC DEFAULT no yes no no no " @@ -1566,7 +1567,10 @@ int main(int argc, char **argv, char **envp) { NATIVE_MSG " CLASSIC: decision target instrumentation (README.llvm.md)\n" - " CTX: CLASSIC + callee context (instrumentation/README.ctx.md)\n" + " CALLER: CLASSIC + single callee context " + "(instrumentation/README.ctx.md)\n" + " CTX: CLASSIC + full callee context " + "(instrumentation/README.ctx.md)\n" " NGRAM-x: CLASSIC + previous path " "((instrumentation/README.ngram.md)\n" " INSTRIM: Dominator tree (for LLVM <= 6.0) " @@ -1660,15 +1664,17 @@ int main(int argc, char **argv, char **envp) { " AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen " "mutator)\n" " AFL_LLVM_INSTRUMENT: set instrumentation mode:\n" - " CLASSIC, INSTRIM, PCGUARD, LTO, GCC, CLANG, CTX, NGRAM-2 ... " - "NGRAM-16\n" + " CLASSIC, INSTRIM, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, " + "NGRAM-2 ..-16\n" " You can also use the old environment variables instead:\n" " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n" " AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n" " AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed " "(option to INSTRIM)\n" - " AFL_LLVM_CTX: use context sensitive coverage (for CLASSIC and " - "INSTRIM)\n" + " AFL_LLVM_CALLER: use single context sensitive coverage (for " + "CLASSIC)\n" + " AFL_LLVM_CTX: use full context sensitive coverage (for " + "CLASSIC)\n" " AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for " "CLASSIC & INSTRIM)\n"); @@ -1814,11 +1820,14 @@ int main(int argc, char **argv, char **envp) { "(requires LLVM 11 or higher)"); #endif - if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC && - instrument_mode != INSTRUMENT_CFG) + if (instrument_opt_mode && instrument_mode == INSTRUMENT_CFG && + instrument_opt_mode & INSTRUMENT_OPT_CTX) + FATAL("CFG instrumentation mode supports NGRAM and CALLER, but not CTX."); + else if (instrument_opt_mode && instrument_mode != INSTRUMENT_CLASSIC) + // we will drop CFG/INSTRIM in the future so do not advertise FATAL( - "CTX and NGRAM instrumentation options can only be used with LLVM and " - "CFG or CLASSIC instrumentation modes!"); + "CALLER, CTX and NGRAM instrumentation options can only be used with " + "the LLVM CLASSIC instrumentation mode."); if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO")) FATAL( -- cgit 1.4.1 From b6dc529bc38469a69ca5f43e12e9cb921fdc3a08 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 4 Mar 2021 14:55:57 +0100 Subject: no ASAN odr violations by default --- src/afl-analyze.c | 1 + src/afl-forkserver.c | 1 + src/afl-showmap.c | 1 + src/afl-tmin.c | 1 + 4 files changed, 4 insertions(+) (limited to 'src') diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 20aef2da..d46ecb8d 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -785,6 +785,7 @@ static void set_up_environment(void) { "abort_on_error=1:" "detect_leaks=0:" "allocator_may_return_null=1:" + "detect_odr_violation=0:" "symbolize=0:" "handle_segv=0:" "handle_sigbus=0:" diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index fd5edc98..a129c152 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -492,6 +492,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "malloc_context_size=0:" "symbolize=0:" "allocator_may_return_null=1:" + "detect_odr_violation=0:" "handle_segv=0:" "handle_sigbus=0:" "handle_abort=0:" diff --git a/src/afl-showmap.c b/src/afl-showmap.c index b40527d3..0fc76193 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -563,6 +563,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) { "detect_leaks=0:" "allocator_may_return_null=1:" "symbolize=0:" + "detect_odr_violation=0:" "handle_segv=0:" "handle_sigbus=0:" "handle_abort=0:" diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 15336959..6d04c652 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -717,6 +717,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) { "detect_leaks=0:" "allocator_may_return_null=1:" "symbolize=0:" + "detect_odr_violation=0:" "handle_segv=0:" "handle_sigbus=0:" "handle_abort=0:" -- cgit 1.4.1 From a2f40aa285faa75e78ac1ffffe8d79e2ac1a40da Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 4 Mar 2021 22:10:32 +0100 Subject: disable corpus introspection, potentially creates huge data --- src/afl-fuzz-queue.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index ad3e3b8e..835aba40 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -198,34 +198,35 @@ void create_alias_table(afl_state_t *afl) { while (nS) afl->alias_probability[S[--nS]] = 1; -#ifdef INTROSPECTION - u8 fn[PATH_MAX]; - snprintf(fn, PATH_MAX, "%s/introspection_corpus.txt", afl->out_dir); - FILE *f = fopen(fn, "a"); - if (f) { + /* + #ifdef INTROSPECTION + u8 fn[PATH_MAX]; + snprintf(fn, PATH_MAX, "%s/introspection_corpus.txt", afl->out_dir); + FILE *f = fopen(fn, "a"); + if (f) { + + for (i = 0; i < n; i++) { + + struct queue_entry *q = afl->queue_buf[i]; + fprintf( + f, + "entry=%u name=%s favored=%s variable=%s disabled=%s len=%u " + "exec_us=%u " + "bitmap_size=%u bitsmap_size=%u tops=%u weight=%f perf_score=%f\n", + i, q->fname, q->favored ? "true" : "false", + q->var_behavior ? "true" : "false", q->disabled ? "true" : "false", + q->len, (u32)q->exec_us, q->bitmap_size, q->bitsmap_size, q->tc_ref, + q->weight, q->perf_score); - for (i = 0; i < n; i++) { + } - struct queue_entry *q = afl->queue_buf[i]; - fprintf( - f, - "entry=%u name=%s favored=%s variable=%s disabled=%s len=%u " - "exec_us=%u " - "bitmap_size=%u bitsmap_size=%u tops=%u weight=%f perf_score=%f\n", - i, q->fname, q->favored ? "true" : "false", - q->var_behavior ? "true" : "false", q->disabled ? "true" : "false", - q->len, (u32)q->exec_us, q->bitmap_size, q->bitsmap_size, q->tc_ref, - q->weight, q->perf_score); + fprintf(f, "\n"); + fclose(f); } - fprintf(f, "\n"); - fclose(f); - - } - -#endif - + #endif + */ /* fprintf(stderr, " entry alias probability perf_score weight filename\n"); for (u32 i = 0; i < n; ++i) fprintf(stderr, " %5u %5u %11u -- cgit 1.4.1 From f848562732337c2d3c71ace4667b3130574f0fe4 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 Mar 2021 10:15:38 +0100 Subject: point explicitly to AFL_MAP_SIZE on problems --- src/afl-forkserver.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index a129c152..6f08f9f4 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -909,10 +909,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } else if (!fsrv->mem_limit) { SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated before we could" - " complete a handshake with the injected code.\n" - "If the target was compiled with afl-clang-lto and AFL_LLVM_MAP_ADDR" - " then recompiling without this parameter.\n" + "Hmm, looks like the target binary terminated before we could complete" + " a\n" + "handshake with the injected code.\n" + "Most likely the target has a huge coverage map, retry with setting" + " the\n" + "environment variable AFL_MAP_SIZE=4194304\n" "Otherwise there is a horrible bug in the fuzzer.\n" "Poke for troubleshooting tips.\n"); @@ -928,6 +930,10 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, "explanations:\n\n" "%s" + + " - Most likely the target has a huge coverage map, retry with setting the\n" + " environment variable AFL_MAP_SIZE=4194304\n\n" + " - The current memory limit (%s) is too restrictive, causing an " "OOM\n" " fault in the dynamic linker. This can be fixed with the -m " -- cgit 1.4.1