From 82c05630ba201bfc631e4e2335c6d8c2e76d91c0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 1 Mar 2021 10:12:42 +0100 Subject: 3.11a init --- docs/Changelog.md | 3 +++ include/config.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index f3e15b6a..4e3eef16 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,6 +8,9 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . +### Version ++3.11a (dev) + - ... + ### Version ++3.10c (release) - Mac OS ARM64 support diff --git a/include/config.h b/include/config.h index c583f23b..a3aa9a4a 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ /* Version string: */ // c = release, a = volatile github dev, e = experimental branch -#define VERSION "++3.10c" +#define VERSION "++3.11a" /****************************************************** * * -- cgit 1.4.1 From ad7a7fcf075c617e09cb516da000b244be161093 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 1 Mar 2021 15:30:55 +0100 Subject: ASan-compatible area_is_mapped() --- instrumentation/afl-compiler-rt.o.c | 10 +++++++++- qemu_mode/qemuafl | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index ecb94cab..dab06177 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -34,6 +34,7 @@ #include #include +#include #ifndef __HAIKU__ #include #endif @@ -1551,15 +1552,22 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { } +__attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size) { + return NULL; +} + // POSIX shenanigan to see if an area is mapped. // If it is mapped as X-only, we have a problem, so maybe we should add a check // to avoid to call it on .text addresses static int area_is_mapped(void *ptr, size_t len) { + if (__asan_region_is_poisoned(ptr, len) == NULL) + return 1; + char *p = (char *)ptr; char *page = (char *)((uintptr_t)p & ~(sysconf(_SC_PAGE_SIZE) - 1)); - int r = msync(page, (p - page) + len, MS_ASYNC); + int r = syscall(SYS_msync, page, (p - page) + len, MS_ASYNC); if (r < 0) return errno != ENOMEM; return 1; diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index e36a30eb..213f3b27 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit e36a30ebca57ca433a5d6e20b1a32975aabb761b +Subproject commit 213f3b27dd099ef352181c48cd75c0f20a73e3f0 -- cgit 1.4.1 From 75d6a8b7011699c22e6d7c7ad9869b9a850e053b Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 1 Mar 2021 15:33:28 +0100 Subject: fix last commit --- instrumentation/afl-compiler-rt.o.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index dab06177..1151cd52 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1559,10 +1559,10 @@ __attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size) { // POSIX shenanigan to see if an area is mapped. // If it is mapped as X-only, we have a problem, so maybe we should add a check // to avoid to call it on .text addresses -static int area_is_mapped(void *ptr, size_t len) { +static int area_is_valid(void *ptr, size_t len) { - if (__asan_region_is_poisoned(ptr, len) == NULL) - return 1; + if (__asan_region_is_poisoned(ptr, len)) + return 0; char *p = (char *)ptr; char *page = (char *)((uintptr_t)p & ~(sysconf(_SC_PAGE_SIZE) - 1)); @@ -1577,7 +1577,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { /* u32 i; - if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return; + if (!area_is_valid(ptr1, 32) || !area_is_valid(ptr2, 32)) return; fprintf(stderr, "rtn arg0="); for (i = 0; i < 24; i++) fprintf(stderr, "%02x", ptr1[i]); @@ -1589,7 +1589,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { if (unlikely(!__afl_cmp_map)) return; - if (!area_is_mapped(ptr1, 32) || !area_is_mapped(ptr2, 32)) return; + if (!area_is_valid(ptr1, 32) || !area_is_valid(ptr2, 32)) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (k >> 4) ^ (k << 8); @@ -1666,7 +1666,7 @@ static u8 *get_llvm_stdstring(u8 *string) { void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { if (unlikely(!__afl_cmp_map)) return; - if (!area_is_mapped(stdstring, 32) || !area_is_mapped(cstring, 32)) return; + if (!area_is_valid(stdstring, 32) || !area_is_valid(cstring, 32)) return; __cmplog_rtn_hook(get_gcc_stdstring(stdstring), cstring); @@ -1675,7 +1675,7 @@ void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { if (unlikely(!__afl_cmp_map)) return; - if (!area_is_mapped(stdstring1, 32) || !area_is_mapped(stdstring2, 32)) + if (!area_is_valid(stdstring1, 32) || !area_is_valid(stdstring2, 32)) return; __cmplog_rtn_hook(get_gcc_stdstring(stdstring1), @@ -1686,7 +1686,7 @@ void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { if (unlikely(!__afl_cmp_map)) return; - if (!area_is_mapped(stdstring, 32) || !area_is_mapped(cstring, 32)) return; + if (!area_is_valid(stdstring, 32) || !area_is_valid(cstring, 32)) return; __cmplog_rtn_hook(get_llvm_stdstring(stdstring), cstring); @@ -1695,7 +1695,7 @@ void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { if (unlikely(!__afl_cmp_map)) return; - if (!area_is_mapped(stdstring1, 32) || !area_is_mapped(stdstring2, 32)) + if (!area_is_valid(stdstring1, 32) || !area_is_valid(stdstring2, 32)) return; __cmplog_rtn_hook(get_llvm_stdstring(stdstring1), -- cgit 1.4.1 From a29b360d55026b43989ab653958bfd86fc854927 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 1 Mar 2021 17:16:34 +0100 Subject: area_is_valid with write --- instrumentation/afl-compiler-rt.o.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 1151cd52..15bc823a 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -123,6 +123,10 @@ static u8 is_persistent; static u8 _is_sancov; +/* Dummy pipe for area_is_valid() */ + +static int dummy_pipe; + /* ensure we kill the child on termination */ void at_exit(int signal) { @@ -476,6 +480,11 @@ static void __afl_map_shm(void) { } if (id_str) { + + if (pipe(dummy_pipe) < 0) { + perror("pipe() failed\n"); + exit(1); + } #ifdef USEMMAP const char * shm_file_path = id_str; @@ -1567,9 +1576,8 @@ static int area_is_valid(void *ptr, size_t len) { char *p = (char *)ptr; char *page = (char *)((uintptr_t)p & ~(sysconf(_SC_PAGE_SIZE) - 1)); - int r = syscall(SYS_msync, page, (p - page) + len, MS_ASYNC); - if (r < 0) return errno != ENOMEM; - return 1; + int r = syscall(dummy_pipe[1], SYS_write, page, (p - page) + len); + return errno != EFAULT; } -- cgit 1.4.1 From 05e2f577f6f510f848661073fcd19c1ef6b9a517 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 1 Mar 2021 17:21:27 +0100 Subject: fix area_is_valid with write --- instrumentation/afl-compiler-rt.o.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 15bc823a..1694def6 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -125,7 +125,7 @@ static u8 _is_sancov; /* Dummy pipe for area_is_valid() */ -static int dummy_pipe; +static int dummy_pipe[2]; /* ensure we kill the child on termination */ -- cgit 1.4.1 From 14fd4771475ede994f5731faf0ce19bebfd4034f Mon Sep 17 00:00:00 2001 From: aflpp Date: Mon, 1 Mar 2021 19:03:25 +0100 Subject: better fix for asan? --- instrumentation/afl-compiler-rt.o.c | 95 ++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 1694def6..15832793 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -34,7 +34,7 @@ #include #include -#include +#include #ifndef __HAIKU__ #include #endif @@ -125,7 +125,7 @@ static u8 _is_sancov; /* Dummy pipe for area_is_valid() */ -static int dummy_pipe[2]; +static int __afl_dummy_fd[2] = {2, 2}; /* ensure we kill the child on termination */ @@ -480,10 +480,11 @@ static void __afl_map_shm(void) { } if (id_str) { - - if (pipe(dummy_pipe) < 0) { - perror("pipe() failed\n"); - exit(1); + + if ((__afl_dummy_fd[0] = open("/dev/null", O_WRONLY)) < 0) { + + if (pipe(__afl_dummy_fd) < 0) { __afl_dummy_fd[0] = 1; } + } #ifdef USEMMAP @@ -1562,7 +1563,9 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { } __attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size) { + return NULL; + } // POSIX shenanigan to see if an area is mapped. @@ -1570,14 +1573,47 @@ __attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size) { // to avoid to call it on .text addresses static int area_is_valid(void *ptr, size_t len) { - if (__asan_region_is_poisoned(ptr, len)) - return 0; + void *ret_ptr = __asan_region_is_poisoned(ptr, len); + + if (ret_ptr) { // region is poisoned + + ssize_t ret_diff = ret_ptr - ptr; + + if (ret_diff <= 0) { + + return 0; + + } else { + + return ret_diff; // only partially poisoned + + } + + } - char *p = (char *)ptr; - char *page = (char *)((uintptr_t)p & ~(sysconf(_SC_PAGE_SIZE) - 1)); + int r = syscall(__afl_dummy_fd[0], SYS_write, ptr, len); - int r = syscall(dummy_pipe[1], SYS_write, page, (p - page) + len); - return errno != EFAULT; + if (r <= 0) { // maybe this is going over an asan boundary + + char *p = (char *)ptr; + long page_size = sysconf(_SC_PAGE_SIZE); + char *page = (char *)((uintptr_t)p & ~(page_size - 1)) + page_size; + if (page < p + len) { return 0; } + len -= (p + len - page); + r = syscall(__afl_dummy_fd[0], SYS_write, p, len); + + } + + // partial writes - we return what was written. + if (r > 0) { + + return r; + + } else { + + return 0; + + } } @@ -1585,19 +1621,22 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { /* u32 i; - if (!area_is_valid(ptr1, 32) || !area_is_valid(ptr2, 32)) return; + if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return; fprintf(stderr, "rtn arg0="); - for (i = 0; i < 24; i++) + for (i = 0; i < 32; i++) fprintf(stderr, "%02x", ptr1[i]); fprintf(stderr, " arg1="); - for (i = 0; i < 24; i++) + for (i = 0; i < 32; i++) fprintf(stderr, "%02x", ptr2[i]); fprintf(stderr, "\n"); */ if (unlikely(!__afl_cmp_map)) return; - - if (!area_is_valid(ptr1, 32) || !area_is_valid(ptr2, 32)) return; + int l1, l2; + if ((l1 = area_is_valid(ptr1, 32)) <= 0 || + (l2 = area_is_valid(ptr2, 32)) <= 0) + return; + int len = MIN(l1, l2); uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (k >> 4) ^ (k << 8); @@ -1608,17 +1647,17 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) { __afl_cmp_map->headers[k].type = CMP_TYPE_RTN; - hits = 0; __afl_cmp_map->headers[k].hits = 1; - __afl_cmp_map->headers[k].shape = 31; + __afl_cmp_map->headers[k].shape = len - 1; + hits = 0; } else { hits = __afl_cmp_map->headers[k].hits++; - if (__afl_cmp_map->headers[k].shape < 31) { + if (__afl_cmp_map->headers[k].shape < len) { - __afl_cmp_map->headers[k].shape = 31; + __afl_cmp_map->headers[k].shape = len; } @@ -1626,9 +1665,9 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { hits &= CMP_MAP_RTN_H - 1; __builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0, - ptr1, 32); + ptr1, len); __builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1, - ptr2, 32); + ptr2, len); } @@ -1674,7 +1713,8 @@ static u8 *get_llvm_stdstring(u8 *string) { void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { if (unlikely(!__afl_cmp_map)) return; - if (!area_is_valid(stdstring, 32) || !area_is_valid(cstring, 32)) return; + if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0) + return; __cmplog_rtn_hook(get_gcc_stdstring(stdstring), cstring); @@ -1683,7 +1723,7 @@ void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { if (unlikely(!__afl_cmp_map)) return; - if (!area_is_valid(stdstring1, 32) || !area_is_valid(stdstring2, 32)) + if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0) return; __cmplog_rtn_hook(get_gcc_stdstring(stdstring1), @@ -1694,7 +1734,8 @@ void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { if (unlikely(!__afl_cmp_map)) return; - if (!area_is_valid(stdstring, 32) || !area_is_valid(cstring, 32)) return; + if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0) + return; __cmplog_rtn_hook(get_llvm_stdstring(stdstring), cstring); @@ -1703,7 +1744,7 @@ void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { if (unlikely(!__afl_cmp_map)) return; - if (!area_is_valid(stdstring1, 32) || !area_is_valid(stdstring2, 32)) + if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0) return; __cmplog_rtn_hook(get_llvm_stdstring(stdstring1), -- cgit 1.4.1 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(-) 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 d0a61279b8306ea74de6f4a4a9cebbc7f559a4e1 Mon Sep 17 00:00:00 2001 From: aflpp Date: Mon, 1 Mar 2021 19:15:58 +0100 Subject: write to correct pipe end --- instrumentation/afl-compiler-rt.o.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 15832793..1b21eea1 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -481,9 +481,9 @@ static void __afl_map_shm(void) { if (id_str) { - if ((__afl_dummy_fd[0] = open("/dev/null", O_WRONLY)) < 0) { + if ((__afl_dummy_fd[1] = open("/dev/null", O_WRONLY)) < 0) { - if (pipe(__afl_dummy_fd) < 0) { __afl_dummy_fd[0] = 1; } + if (pipe(__afl_dummy_fd) < 0) { __afl_dummy_fd[1] = 1; } } @@ -1591,7 +1591,7 @@ static int area_is_valid(void *ptr, size_t len) { } - int r = syscall(__afl_dummy_fd[0], SYS_write, ptr, len); + int r = syscall(__afl_dummy_fd[1], SYS_write, ptr, len); if (r <= 0) { // maybe this is going over an asan boundary @@ -1600,7 +1600,7 @@ static int area_is_valid(void *ptr, size_t len) { char *page = (char *)((uintptr_t)p & ~(page_size - 1)) + page_size; if (page < p + len) { return 0; } len -= (p + len - page); - r = syscall(__afl_dummy_fd[0], SYS_write, p, len); + r = syscall(__afl_dummy_fd[1], SYS_write, p, len); } -- cgit 1.4.1 From c3a8052a16f7d2d1947ea538719905a9d7a24d22 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 1 Mar 2021 19:30:39 +0100 Subject: update changelog --- docs/Changelog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 4e3eef16..f5742d24 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,8 +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-cc + - fixed for a crash that can occur with ASAN + CMPLOG together ### Version ++3.10c (release) - Mac OS ARM64 support -- cgit 1.4.1 From c269c3977ccb96710a2488b19c72bae51832a827 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 2 Mar 2021 11:38:12 +0100 Subject: fix llvm for unicode strings (hopefully) --- instrumentation/SanitizerCoverageLTO.so.cc | 4 ++-- instrumentation/afl-llvm-dict2file.so.cc | 5 +++-- instrumentation/afl-llvm-lto-instrumentation.so.cc | 4 ++-- instrumentation/compare-transform-pass.so.cc | 6 +++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 3026abc8..942d5357 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -733,7 +733,7 @@ bool ModuleSanitizerCoverage::instrumentModule( Var->getInitializer())) { HasStr2 = true; - Str2 = Array->getAsString().str(); + Str2 = Array->getRawDataValues().str(); } @@ -809,7 +809,7 @@ bool ModuleSanitizerCoverage::instrumentModule( Var->getInitializer())) { HasStr1 = true; - Str1 = Array->getAsString().str(); + Str1 = Array->getRawDataValues().str(); } diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index 19ef15f7..1c365da8 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -357,6 +357,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { StringRef TmpStr; bool HasStr1; getConstantStringInfo(Str1P, TmpStr); + if (TmpStr.empty()) { HasStr1 = false; @@ -403,7 +404,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { dyn_cast(Var->getInitializer())) { HasStr2 = true; - Str2 = Array->getAsString().str(); + Str2 = Array->getRawDataValues().str(); } @@ -479,7 +480,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { dyn_cast(Var->getInitializer())) { HasStr1 = true; - Str1 = Array->getAsString().str(); + Str1 = Array->getRawDataValues().str(); } diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 137bae2c..1f21b917 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -519,7 +519,7 @@ bool AFLLTOPass::runOnModule(Module &M) { Var->getInitializer())) { HasStr2 = true; - Str2 = Array->getAsString().str(); + Str2 = Array->getRawDataValues().str(); } @@ -595,7 +595,7 @@ bool AFLLTOPass::runOnModule(Module &M) { Var->getInitializer())) { HasStr1 = true; - Str1 = Array->getAsString().str(); + Str1 = Array->getRawDataValues().str(); } diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index bd524a69..84301493 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -229,9 +229,9 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, dyn_cast(Var->getInitializer())) { HasStr2 = true; - Str2 = Array->getAsString(); + Str2 = Array->getRawDataValues(); valueMap[Str2P] = new std::string(Str2.str()); - fprintf(stderr, "glo2 %s\n", Str2.str().c_str()); + // fprintf(stderr, "glo2 %s\n", Str2.str().c_str()); } @@ -254,7 +254,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, Var->getInitializer())) { HasStr1 = true; - Str1 = Array->getAsString(); + Str1 = Array->getRawDataValues(); valueMap[Str1P] = new std::string(Str1.str()); // fprintf(stderr, "glo1 %s\n", Str1.str().c_str()); -- cgit 1.4.1 From 333509bb0a56be9bd2e236f0e2f37d4af2dd7d59 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 2 Mar 2021 16:24:43 +0100 Subject: better unicode support --- docs/Changelog.md | 3 ++- instrumentation/SanitizerCoverageLTO.so.cc | 14 +++++++++----- instrumentation/afl-llvm-dict2file.so.cc | 14 +++++++++----- instrumentation/afl-llvm-lto-instrumentation.so.cc | 14 +++++++++----- instrumentation/compare-transform-pass.so.cc | 11 +++++++++-- 5 files changed, 38 insertions(+), 18 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index f5742d24..01240b2a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,7 +10,8 @@ sending a mail to . ### Version ++3.11a (dev) - afl-cc - - fixed for a crash that can occur with ASAN + CMPLOG together + - fixed for a crash that can occur with ASAN + CMPLOG together plus + better support for unicode (thanks to @stbergmann for reporting!) ### Version ++3.10c (release) - Mac OS ARM64 support diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 942d5357..849b6eef 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -872,17 +872,21 @@ bool ModuleSanitizerCoverage::instrumentModule( // was not already added if (!isMemcmp) { - if (addedNull == false) { + if (addedNull == false && thestring[optLen - 1] != '\0') { thestring.append("\0", 1); // add null byte optLen++; } - // ensure we do not have garbage - size_t offset = thestring.find('\0', 0); - if (offset + 1 < optLen) optLen = offset + 1; - thestring = thestring.substr(0, optLen); + if (!isStdString) { + + // ensure we do not have garbage + size_t offset = thestring.find('\0', 0); + if (offset + 1 < optLen) optLen = offset + 1; + thestring = thestring.substr(0, optLen); + + } } diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index 1c365da8..885aa035 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -543,17 +543,21 @@ bool AFLdict2filePass::runOnModule(Module &M) { // was not already added if (!isMemcmp) { - if (addedNull == false) { + if (addedNull == false && thestring[optLen - 1] != '\0') { thestring.append("\0", 1); // add null byte optLen++; } - // ensure we do not have garbage - size_t offset = thestring.find('\0', 0); - if (offset + 1 < optLen) optLen = offset + 1; - thestring = thestring.substr(0, optLen); + if (!isStdString) { + + // ensure we do not have garbage + size_t offset = thestring.find('\0', 0); + if (offset + 1 < optLen) optLen = offset + 1; + thestring = thestring.substr(0, optLen); + + } } diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 1f21b917..ef270a1f 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -658,17 +658,21 @@ bool AFLLTOPass::runOnModule(Module &M) { // was not already added if (!isMemcmp) { - if (addedNull == false) { + if (addedNull == false && thestring[optLen - 1] != '\0') { thestring.append("\0", 1); // add null byte optLen++; } - // ensure we do not have garbage - size_t offset = thestring.find('\0', 0); - if (offset + 1 < optLen) optLen = offset + 1; - thestring = thestring.substr(0, optLen); + if (!isStdString) { + + // ensure we do not have garbage + size_t offset = thestring.find('\0', 0); + if (offset + 1 < optLen) optLen = offset + 1; + thestring = thestring.substr(0, optLen); + + } } diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index 84301493..a85522a2 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -421,14 +421,21 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } // add null termination character implicit in c strings - TmpConstStr.append("\0", 1); + if (TmpConstStr[TmpConstStr.length() - 1] != 0) { + + TmpConstStr.append("\0", 1); + + } // in the unusual case the const str has embedded null // characters, the string comparison functions should terminate // at the first null - if (!isMemcmp) + if (!isMemcmp) { + TmpConstStr.assign(TmpConstStr, 0, TmpConstStr.find('\0') + 1); + } + constStrLen = TmpConstStr.length(); // prefer use of StringRef (in comparison to std::string a StringRef has // built-in runtime bounds checking, which makes debugging easier) -- 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(-) 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 f0bc2e0e8b9d7b7e6e5371153f1b3bd7500cdae7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 2 Mar 2021 18:45:41 +0100 Subject: docu --- TODO.md | 8 +++++++- docs/Changelog.md | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 4615c456..e5a678cf 100644 --- a/TODO.md +++ b/TODO.md @@ -2,12 +2,15 @@ ## Roadmap 3.00+ - - AFL_MAP_SIZE for qemu_mode and unicorn_mode - CPU affinity for many cores? There seems to be an issue > 96 cores - afl-plot to support multiple plot_data - afl_custom_fuzz_splice_optin() - afl_custom_splice() - intel-pt tracer + - better autodetection of shifting runtime timeout values + - cmplog: use colorization input for havoc? + - cmplog: too much tainted bytes, directly add to dict and skip? + ## Further down the road @@ -23,9 +26,12 @@ qemu_mode: - add/implement AFL_QEMU_INST_LIBLIST and AFL_QEMU_NOINST_PROGRAM - add/implement AFL_QEMU_INST_REGIONS as a list of _START/_END addresses + ## Ideas - LTO/sancov: write current edge to prev_loc and use that information when using cmplog or __sanitizer_cov_trace_cmp*. maybe we can deduct by follow up edge numbers that both following cmp paths have been found and then disable working on this edge id -> cmplog_intelligence branch + - use cmplog colorization taint result for havoc locations? + diff --git a/docs/Changelog.md b/docs/Changelog.md index 376f5f06..1be41267 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -12,7 +12,7 @@ sending a mail to . - 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 + - fixed a crash that can occur with ASAN + CMPLOG together plus better support for unicode (thanks to @stbergmann for reporting!) ### Version ++3.10c (release) -- cgit 1.4.1 From 8bdb40b7631ea0a6f7dec8e51a6c69c6b3c7513d Mon Sep 17 00:00:00 2001 From: realmadsci <71108352+realmadsci@users.noreply.github.com> Date: Tue, 2 Mar 2021 15:28:26 -0500 Subject: cpu-exec: Add AFL_QEMU_EXCLUDE_RANGES This environment variable allows rejection of specific regions from instrumentation. It takes priority over AFL_INST_LIBS and AFL_QEMU_INST_RANGES, so it can be used to poke a "hole" in previously included sections. --- include/envs.h | 1 + qemu_mode/README.md | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/envs.h b/include/envs.h index 143979c6..26f4de90 100644 --- a/include/envs.h +++ b/include/envs.h @@ -141,6 +141,7 @@ static char *afl_environment_variables[] = { "AFL_QEMU_PERSISTENT_RETADDR_OFFSET", "AFL_QEMU_PERSISTENT_EXITS", "AFL_QEMU_INST_RANGES", + "AFL_QEMU_EXCLUDE_RANGES", "AFL_QEMU_SNAPSHOT", "AFL_QUIET", "AFL_RANDOM_ALLOC_CANARY", diff --git a/qemu_mode/README.md b/qemu_mode/README.md index bc4c1d2c..a14cbe64 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -99,6 +99,13 @@ Just set AFL_QEMU_INST_RANGES=A,B,C... The format of the items in the list is either a range of addresses like 0x123-0x321 or a module name like module.so (that is matched in the mapped object filename). +Alternatively you can tell QEMU to ignore part of an address space for instrumentation. + +Just set AFL_QEMU_EXCLUDE_RANGES=A,B,C... + +The format of the items on the list is the same as for AFL_QEMU_INST_RANGES, and excluding ranges +takes priority over any included ranges or AFL_INST_LIBS. + ## 7) CompareCoverage CompareCoverage is a sub-instrumentation with effects similar to laf-intel. -- 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(-) 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 3977d50b5538e8097eb5d9329c6df5eaa147374b Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 4 Mar 2021 10:52:22 +0100 Subject: update qemuafl and remove git stas --- qemu_mode/QEMUAFL_VERSION | 2 +- qemu_mode/build_qemu_support.sh | 2 +- qemu_mode/qemuafl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qemu_mode/QEMUAFL_VERSION b/qemu_mode/QEMUAFL_VERSION index 1152380c..a7f25da3 100644 --- a/qemu_mode/QEMUAFL_VERSION +++ b/qemu_mode/QEMUAFL_VERSION @@ -1 +1 @@ -e36a30ebca +d1ca56b84e diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index 815e77d6..97a05800 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -132,7 +132,7 @@ echo "[+] Got qemuafl." cd "qemuafl" || exit 1 echo "[*] Checking out $QEMUAFL_VERSION" -sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null +# sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null git checkout "$QEMUAFL_VERSION" || echo Warning: could not check out to commit $QEMUAFL_VERSION echo "[*] Making sure imported headers matches" diff --git a/qemu_mode/qemuafl b/qemu_mode/qemuafl index 213f3b27..d1ca56b8 160000 --- a/qemu_mode/qemuafl +++ b/qemu_mode/qemuafl @@ -1 +1 @@ -Subproject commit 213f3b27dd099ef352181c48cd75c0f20a73e3f0 +Subproject commit d1ca56b84e78f821406eef28d836918edfc8d610 -- cgit 1.4.1 From 08ef8d6b787f1a04b5ec3644d7ecae41d2668193 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 4 Mar 2021 10:57:00 +0100 Subject: NO_CHECKOUT=1 ./build_qemu_support.sh --- qemu_mode/build_qemu_support.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index 97a05800..4d3d9bf6 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -131,9 +131,13 @@ test -d qemuafl || { echo "[-] Not checked out, please install git or check your echo "[+] Got qemuafl." cd "qemuafl" || exit 1 -echo "[*] Checking out $QEMUAFL_VERSION" -# sh -c 'git stash && git stash drop' 1>/dev/null 2>/dev/null -git checkout "$QEMUAFL_VERSION" || echo Warning: could not check out to commit $QEMUAFL_VERSION +if [ -n "$NO_CHECKOUT" ]; then + echo "[*] Skipping checkout to $QEMUAFL_VERSION" +else + echo "[*] Checking out $QEMUAFL_VERSION" + sh -c 'git stash' 1>/dev/null 2>/dev/null + git checkout "$QEMUAFL_VERSION" || echo Warning: could not check out to commit $QEMUAFL_VERSION +fi echo "[*] Making sure imported headers matches" cp "../../include/config.h" "./qemuafl/imported/" || exit 1 -- cgit 1.4.1 From 0e736276e6421162da0070e98d17d25b9a679de0 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 4 Mar 2021 11:00:54 +0100 Subject: restore correct CTX behaviour in llvm mode --- instrumentation/afl-llvm-pass.so.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 16fd9c94..87267e35 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -354,7 +354,8 @@ bool AFLCoverage::runOnModule(Module &M) { // if yes we store a context ID for this function in the global var if (has_calls) { - ConstantInt *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size)); + Value *NewCtx = IRB.CreateXor( + PrevCtx, ConstantInt::get(Int32Ty, AFL_R(map_size))); StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext); StoreCtx->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); -- 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(-) 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(-) 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 02f33192560a972f02fad72e051b9f884635d7ff Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 4 Mar 2021 12:23:19 +0100 Subject: only initialize afl-compiler-rt once --- instrumentation/afl-compiler-rt.o.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 1b21eea1..c9577a55 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -242,6 +242,10 @@ 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; + // if we are not running in afl ensure the map exists if (!__afl_area_ptr) { __afl_area_ptr = __afl_area_ptr_dummy; } @@ -742,6 +746,10 @@ 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; + struct sigaction orig_action; sigaction(SIGTERM, NULL, &orig_action); old_sigterm_handler = orig_action.sa_handler; @@ -1071,6 +1079,10 @@ __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_DISABLE_LLVM_INSTRUMENTATION")) return; u8 *ptr; @@ -1102,6 +1114,10 @@ __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; + if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return; u8 *ptr; -- 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(-) 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 79d75d8e42e5adf64e149ab6e1fe197cb1d4f303 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 4 Mar 2021 14:19:00 +0100 Subject: even support dlopen instrumented libs after the forkserver --- docs/Changelog.md | 5 +++-- instrumentation/afl-compiler-rt.o.c | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 6fe3517a..b1c991ff 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,8 +15,9 @@ sending a mail to . - 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. + compiled into the target. This now also supports dlopen + instrumented libs loaded before the forkserver and even after the + forkserver is started (then with collisions though) - Renamed CTX to CALLER, added correct/real CTX implemenation to CLASSIC - qemu_mode - added AFL_QEMU_EXCLUDE_RANGES env by @realmadsci, thanks! diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index e3aa787f..87bf6486 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1263,8 +1263,10 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { if (__afl_debug) { fprintf(stderr, - "Running __sanitizer_cov_trace_pc_guard_init: %p-%p (%lu edges)\n", - start, stop, (unsigned long)(stop - start)); + "Running __sanitizer_cov_trace_pc_guard_init: %p-%p (%lu edges) " + "after_fs=%u\n", + start, stop, (unsigned long)(stop - start), + __afl_already_initialized_forkserver); } @@ -1280,6 +1282,36 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { } + /* instrumented code is loaded *after* our forkserver is up. this is a + problem. We cannot prevent collisions then :( */ + if (__afl_already_initialized_forkserver && + __afl_final_loc + 1 + stop - start > __afl_map_size) { + + if (__afl_debug) + fprintf(stderr, "Warning: new instrumneted code after the forkserver!\n"); + __afl_final_loc = 2; + + if (1 + stop - start > __afl_map_size) { + + *(start++) = ++__afl_final_loc; + + while (start < stop) { + + if (R(100) < inst_ratio) + *start = ++__afl_final_loc % __afl_map_size; + else + *start = 0; + + start++; + + } + + return; + + } + + } + /* Make sure that the first element in the range is always set - we use that to avoid duplicate calls (which can happen as an artifact of the underlying implementation in LLVM). */ -- 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(+) 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 f34a860d5fd22ba3e3eb3aa37299f7691a3d32a6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 4 Mar 2021 20:14:47 +0100 Subject: NO_ARCH_OPT was removed due many issues --- GNUmakefile | 1 - README.md | 1 - 2 files changed, 2 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 0420cdfc..871ee10d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -364,7 +364,6 @@ help: @echo NO_PYTHON - disable python support @echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing @echo AFL_NO_X86 - if compiling on non-intel/amd platforms - @echo NO_ARCH_OPT - builds afl++ without machine architecture optimizations @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 diff --git a/README.md b/README.md index 992dcd86..6b11fee4 100644 --- a/README.md +++ b/README.md @@ -224,7 +224,6 @@ These build options exist: * NO_PYTHON - disable python support * NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing * AFL_NO_X86 - if compiling on non-intel/amd platforms -* NO_ARCH_OPT - builds afl++ without machine architecture optimizations * LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian) e.g.: make ASAN_BUILD=1 -- 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(-) 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 3342aa751d8e9102449e1739b38a25c40ab18e81 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 Mar 2021 10:05:43 +0100 Subject: fix laf string transform crash --- docs/Changelog.md | 1 + instrumentation/SanitizerCoverageLTO.so.cc | 3 +++ instrumentation/afl-llvm-dict2file.so.cc | 4 ++++ instrumentation/afl-llvm-lto-instrumentation.so.cc | 3 +++ instrumentation/compare-transform-pass.so.cc | 11 +++++++++-- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index b1c991ff..c5b275de 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -14,6 +14,7 @@ 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!) + - fixed a crash in LAF transform for empty strings - 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 and even after the diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 849b6eef..13a5e5fd 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -849,15 +849,18 @@ bool ModuleSanitizerCoverage::instrumentModule( thestring = Str2; optLen = thestring.length(); + if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; } if (isMemcmp || isStrncmp || isStrncasecmp) { Value * op2 = callInst->getArgOperand(2); ConstantInt *ilen = dyn_cast(op2); + if (ilen) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); addedNull = true; diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index 885aa035..c954054b 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -521,14 +521,18 @@ bool AFLdict2filePass::runOnModule(Module &M) { optLen = thestring.length(); + if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; } + if (isMemcmp || isStrncmp || isStrncasecmp) { Value * op2 = callInst->getArgOperand(2); ConstantInt *ilen = dyn_cast(op2); + if (ilen) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); addedNull = true; diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index ef270a1f..50306224 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -635,15 +635,18 @@ bool AFLLTOPass::runOnModule(Module &M) { thestring = Str2; optLen = thestring.length(); + if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; } if (isMemcmp || isStrncmp || isStrncasecmp) { Value * op2 = callInst->getArgOperand(2); ConstantInt *ilen = dyn_cast(op2); + if (ilen) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); addedNull = true; diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index a85522a2..3ecba4e6 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -316,7 +316,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, uint64_t len = ilen->getZExtValue(); // if len is zero this is a pointless call but allow real // implementation to worry about that - if (!len) continue; + if (len < 2) continue; if (isMemcmp) { @@ -420,8 +420,15 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } + if (TmpConstStr.length() < 2 || + (TmpConstStr.length() == 2 && !TmpConstStr[1])) { + + continue; + + } + // add null termination character implicit in c strings - if (TmpConstStr[TmpConstStr.length() - 1] != 0) { + if (!isMemcmp && TmpConstStr[TmpConstStr.length() - 1]) { TmpConstStr.append("\0", 1); -- 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(-) 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 From 3e5ac0af5237bbd01abc30538add248ee0bf1735 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 Mar 2021 10:21:28 +0100 Subject: no static for rt initialized markers --- instrumentation/afl-compiler-rt.o.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 87bf6486..664c942d 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -129,10 +129,10 @@ 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; +u32 __afl_already_initialized_shm; +u32 __afl_already_initialized_forkserver; +u32 __afl_already_initialized_first; +u32 __afl_already_initialized_second; /* Dummy pipe for area_is_valid() */ -- cgit 1.4.1 From 41ad23041b98917e9c38873f5b296ab98e59e460 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 Mar 2021 14:58:37 +0100 Subject: remove warnings --- instrumentation/afl-compiler-rt.o.c | 8 +++----- instrumentation/cmplog-instructions-pass.cc | 14 +++----------- instrumentation/split-compares-pass.so.cc | 19 +++++++++++++++---- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 664c942d..1d8fd757 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1170,7 +1170,7 @@ __attribute__((constructor(1))) void __afl_auto_second(void) { } -} +} // ptr memleak report is a false positive /* preset __afl_area_ptr #1 - at constructor level 0 global variables have not been set */ @@ -1181,9 +1181,7 @@ __attribute__((constructor(0))) void __afl_auto_first(void) { __afl_already_initialized_first = 1; if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return; - u8 *ptr; - - ptr = (u8 *)malloc(MAP_INITIAL_SIZE); + u8 *ptr = (u8 *)malloc(MAP_INITIAL_SIZE); if (ptr && (ssize_t)ptr != -1) { @@ -1192,7 +1190,7 @@ __attribute__((constructor(0))) void __afl_auto_first(void) { } -} +} // ptr memleak report is a false positive /* The following stuff deals with supporting -fsanitize-coverage=trace-pc-guard. It remains non-operational in the traditional, plugin-backed LLVM mode. diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc index dbca9afa..ad334d3b 100644 --- a/instrumentation/cmplog-instructions-pass.cc +++ b/instrumentation/cmplog-instructions-pass.cc @@ -418,7 +418,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) { IntegerType * intTyOp0 = NULL; IntegerType * intTyOp1 = NULL; unsigned max_size = 0, cast_size = 0; - unsigned char attr = 0, do_cast = 0; + unsigned char attr = 0; std::vector args; CmpInst *cmpInst = dyn_cast(selectcmpInst); @@ -484,7 +484,6 @@ bool CmpLogInstructions::hookInstrs(Module &M) { max_size = 128; attr += 8; - do_cast = 1; } else { @@ -503,12 +502,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) { if (!max_size || max_size < 16) { continue; } - if (max_size % 8) { - - max_size = (((max_size / 8) + 1) * 8); - do_cast = 1; - - } + if (max_size % 8) { max_size = (((max_size / 8) + 1) * 8); } if (max_size > 128) { @@ -521,7 +515,6 @@ bool CmpLogInstructions::hookInstrs(Module &M) { } max_size = 128; - do_cast = 1; } @@ -537,7 +530,6 @@ bool CmpLogInstructions::hookInstrs(Module &M) { break; default: cast_size = 128; - do_cast = 1; } @@ -574,7 +566,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) { } // fprintf(stderr, "_ExtInt(%u) castTo %u with attr %u didcast %u\n", - // max_size, cast_size, attr, do_cast); + // max_size, cast_size, attr); switch (cast_size) { diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 80cd90ba..d03944df 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -149,8 +149,11 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { auto op1 = FcmpInst->getOperand(1); /* find out what the new predicate is going to be */ - auto pred = dyn_cast(FcmpInst)->getPredicate(); + auto cmp_inst = dyn_cast(FcmpInst); + if (!cmp_inst) { continue; } + auto pred = cmp_inst->getPredicate(); CmpInst::Predicate new_pred; + switch (pred) { case CmpInst::FCMP_UGE: @@ -276,8 +279,11 @@ bool SplitComparesTransform::simplifyCompares(Module &M) { auto op1 = IcmpInst->getOperand(1); /* find out what the new predicate is going to be */ - auto pred = dyn_cast(IcmpInst)->getPredicate(); + auto cmp_inst = dyn_cast(IcmpInst); + if (!cmp_inst) { continue; } + auto pred = cmp_inst->getPredicate(); CmpInst::Predicate new_pred; + switch (pred) { case CmpInst::ICMP_UGE: @@ -412,8 +418,11 @@ bool SplitComparesTransform::simplifyIntSignedness(Module &M) { IntegerType *IntType = IntegerType::get(C, bitw); /* get the new predicate */ - auto pred = dyn_cast(IcmpInst)->getPredicate(); + auto cmp_inst = dyn_cast(IcmpInst); + if (!cmp_inst) { continue; } + auto pred = cmp_inst->getPredicate(); CmpInst::Predicate new_pred; + if (pred == CmpInst::ICMP_SGT) { new_pred = CmpInst::ICMP_UGT; @@ -1113,7 +1122,9 @@ size_t SplitComparesTransform::splitIntCompares(Module &M, unsigned bitw) { auto op0 = IcmpInst->getOperand(0); auto op1 = IcmpInst->getOperand(1); - auto pred = dyn_cast(IcmpInst)->getPredicate(); + auto cmp_inst = dyn_cast(IcmpInst); + if (!cmp_inst) { continue; } + auto pred = cmp_inst->getPredicate(); BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); -- cgit 1.4.1 From c9854ec8cbd87dc09d7a6ab1b75f3fce2f7bc9ca Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 5 Mar 2021 18:07:16 +0100 Subject: typo --- docs/Changelog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index c5b275de..4e76fedd 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,10 +16,10 @@ sending a mail to . better support for unicode (thanks to @stbergmann for reporting!) - fixed a crash in LAF transform for empty strings - handle erroneous setups in which multiple afl-compiler-rt are - compiled into the target. This now also supports dlopen + compiled into the target. This now also supports dlopen() instrumented libs loaded before the forkserver and even after the forkserver is started (then with collisions though) - - Renamed CTX to CALLER, added correct/real CTX implemenation to CLASSIC + - Renamed CTX to CALLER, added correct/real CTX implementation to CLASSIC - qemu_mode - added AFL_QEMU_EXCLUDE_RANGES env by @realmadsci, thanks! - if no new/updated checkout is wanted, build with: -- cgit 1.4.1 From 16d6f35aa6f968d6dbdd2005e8fa140955815837 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 5 Mar 2021 18:11:05 +0100 Subject: typos --- instrumentation/README.ctx.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/instrumentation/README.ctx.md b/instrumentation/README.ctx.md index ffcce0a9..577b3e5f 100644 --- a/instrumentation/README.ctx.md +++ b/instrumentation/README.ctx.md @@ -4,7 +4,7 @@ This is an LLVM-based implementation of the context sensitive branch coverage. -Basically every function gets its own ID and, every time that an edge is logged, +Basically every function gets its own ID and, every time when 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. @@ -16,7 +16,7 @@ In math the coverage is collected as follows: `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. +recursive functions. ## Usage @@ -28,7 +28,7 @@ many map collisions occur. ## Caller Branch Coverage -If the context sensitive coverage introduces too may collisions becoming +If the context sensitive coverage introduces too may collisions and becoming decremental, the user can choose to augment edge coverage with just the called function ID, instead of the entire callstack hash. -- cgit 1.4.1 From c9819e3b94796e22546596d1c16c9e89ce272e35 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 Mar 2021 18:24:24 +0100 Subject: reduce github action minutes --- .github/workflows/ci.yml | 4 ++-- .github/workflows/codeql-analysis.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31cfceaf..8412fcbb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,8 +3,8 @@ name: CI on: push: branches: [ stable, dev ] - pull_request: - branches: [ stable, dev ] +# pull_request: +# branches: [ stable, dev ] jobs: build: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index eda8dfd0..e6c166f2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -3,8 +3,8 @@ name: "CodeQL" on: push: branches: [ stable, dev ] - pull_request: - branches: [ stable, dev ] +# pull_request: +# branches: [ stable, dev ] jobs: analyze: -- cgit 1.4.1 From 44be521ab8ef5d62847ae48ebdb060d84aae5e47 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 Mar 2021 19:19:43 +0100 Subject: fix --- instrumentation/afl-compiler-rt.o.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 1d8fd757..c741bc05 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -370,10 +370,10 @@ static void __afl_map_shm(void) { } close(shm_fd); + shm_fd = -1; if (shm_base == MAP_FAILED) { - shm_fd = -1; fprintf(stderr, "mmap() failed\n"); perror("mmap for map"); -- cgit 1.4.1 From 9844e1a856d38780a8bff6e15411956e3f183d57 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 Mar 2021 19:32:27 +0100 Subject: fix --- afl-cmin | 4 ++++ afl-cmin.bash | 1 + 2 files changed, 5 insertions(+) diff --git a/afl-cmin b/afl-cmin index 4ee79a79..7f8544eb 100755 --- a/afl-cmin +++ b/afl-cmin @@ -287,6 +287,10 @@ BEGIN { exit 1 } + if (0 == system( "test -d "in_dir"/default" )) { + in_dir = in_dir "/default" + } + if (0 == system( "test -d "in_dir"/queue" )) { in_dir = in_dir "/queue" } diff --git a/afl-cmin.bash b/afl-cmin.bash index dae21939..5b2c3894 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -223,6 +223,7 @@ if [ ! -d "$IN_DIR" ]; then exit 1 fi +test -d "$IN_DIR/default" && IN_DIR="$IN_DIR/default" test -d "$IN_DIR/queue" && IN_DIR="$IN_DIR/queue" find "$OUT_DIR" -name 'id[:_]*' -maxdepth 1 -exec rm -- {} \; 2>/dev/null -- cgit 1.4.1 From 2dd5a020615842e51dcf8cfaa7b01ad6bef4cda8 Mon Sep 17 00:00:00 2001 From: julihoh Date: Fri, 5 Mar 2021 19:40:59 +0100 Subject: Ergonomic Improvements for Rust Custom Mutators (#772) * allow returning of str instead of CStr in rust custom mutator * use OsStr instead of CStr for file paths * fix cfg and compiler errors * custom mutator default descriptions * fix usage of afl_internal feature flag * fix example mutator cfg * fix lain mutator * Revert "fix lain mutator" This reverts commit adf700180888d86e8331939cea62d0b39fc699a7. * actually fix lain mutator * resolve question around utf-8 null bytes * change from OsStr to Path to be even more ergonomic * add rust custom mutator ci * fix github action * again * separate compilation check --- .github/workflows/rust_custom_mutator.yml | 30 ++++ custom_mutators/rust/custom_mutator/src/lib.rs | 164 +++++++++++++++++---- .../rust/example/src/example_mutator.rs | 1 + .../rust/example_lain/src/lain_mutator.rs | 2 + 4 files changed, 168 insertions(+), 29 deletions(-) create mode 100644 .github/workflows/rust_custom_mutator.yml diff --git a/.github/workflows/rust_custom_mutator.yml b/.github/workflows/rust_custom_mutator.yml new file mode 100644 index 00000000..de2b184a --- /dev/null +++ b/.github/workflows/rust_custom_mutator.yml @@ -0,0 +1,30 @@ +name: Rust Custom Mutators + +on: + push: + branches: [ stable, dev ] + pull_request: + branches: [ stable, dev ] + +jobs: + test: + name: Test Rust Custom Mutator Support + runs-on: '${{ matrix.os }}' + defaults: + run: + working-directory: custom_mutators/rust + strategy: + matrix: + os: [ubuntu-20.04] + steps: + - uses: actions/checkout@v2 + - name: Install Rust Toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - name: Check Code Compiles + run: cargo check + - name: Run General Tests + run: cargo test + - name: Run Tests for afl_internals feature flag + run: cd custom_mutator && cargo test --features=afl_internals \ No newline at end of file diff --git a/custom_mutators/rust/custom_mutator/src/lib.rs b/custom_mutators/rust/custom_mutator/src/lib.rs index b82af250..9444e4d1 100644 --- a/custom_mutators/rust/custom_mutator/src/lib.rs +++ b/custom_mutators/rust/custom_mutator/src/lib.rs @@ -1,3 +1,4 @@ +#![cfg(unix)] //! Somewhat safe and somewhat ergonomic bindings for creating [AFL++](https://github.com/AFLplusplus/AFLplusplus) [custom mutators](https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/custom_mutators.md) in Rust. //! //! # Usage @@ -23,7 +24,7 @@ //! The state is passed to [`CustomMutator::init`], when the feature is activated. //! //! _This is completely unsafe and uses automatically generated types extracted from the AFL++ source._ -use std::{ffi::CStr, fmt::Debug}; +use std::{fmt::Debug, path::Path}; #[cfg(feature = "afl_internals")] #[doc(hidden)] @@ -33,7 +34,7 @@ pub use custom_mutator_sys::afl_state; #[doc(hidden)] pub trait RawCustomMutator { #[cfg(feature = "afl_internals")] - fn init(afl: &'static afl_state, seed: c_uint) -> Self + fn init(afl: &'static afl_state, seed: u32) -> Self where Self: Sized; #[cfg(not(feature = "afl_internals"))] @@ -52,17 +53,17 @@ pub trait RawCustomMutator { 1 } - fn queue_new_entry(&mut self, filename_new_queue: &CStr, _filename_orig_queue: Option<&CStr>) {} + fn queue_new_entry(&mut self, filename_new_queue: &Path, _filename_orig_queue: Option<&Path>) {} - fn queue_get(&mut self, filename: &CStr) -> bool { + fn queue_get(&mut self, filename: &Path) -> bool { true } - fn describe(&mut self, max_description: usize) -> Option<&CStr> { - None + fn describe(&mut self, max_description: usize) -> Option<&str> { + Some(default_mutator_describe::(max_description)) } - fn introspection(&mut self) -> Option<&CStr> { + fn introspection(&mut self) -> Option<&str> { None } @@ -81,16 +82,17 @@ pub mod wrappers { #[cfg(feature = "afl_internals")] use custom_mutator_sys::afl_state; - use core::slice; use std::{ any::Any, convert::TryInto, - ffi::{c_void, CStr}, + ffi::{c_void, CStr, OsStr}, mem::ManuallyDrop, - os::raw::c_char, + os::{raw::c_char, unix::ffi::OsStrExt}, panic::catch_unwind, + path::Path, process::abort, ptr::null, + slice, }; use crate::RawCustomMutator; @@ -99,6 +101,10 @@ pub mod wrappers { /// Also has some convenience functions for FFI conversions (from and to ptr) and tries to make misuse hard (see [`FFIContext::from`]). struct FFIContext { mutator: M, + /// buffer for storing the description returned by [`RawCustomMutator::describe`] as a CString + description_buffer: Vec, + /// buffer for storing the introspection returned by [`RawCustomMutator::introspect`] as a CString + introspection_buffer: Vec, } impl FFIContext { @@ -115,12 +121,16 @@ pub mod wrappers { fn new(afl: &'static afl_state, seed: u32) -> Box { Box::new(Self { mutator: M::init(afl, seed), + description_buffer: Vec::new(), + introspection_buffer: Vec::new(), }) } #[cfg(not(feature = "afl_internals"))] fn new(seed: u32) -> Box { Box::new(Self { mutator: M::init(seed), + description_buffer: Vec::new(), + introspection_buffer: Vec::new(), }) } } @@ -242,9 +252,13 @@ pub mod wrappers { if filename_new_queue.is_null() { panic!("received null filename_new_queue in afl_custom_queue_new_entry"); } - let filename_new_queue = unsafe { CStr::from_ptr(filename_new_queue) }; + let filename_new_queue = Path::new(OsStr::from_bytes( + unsafe { CStr::from_ptr(filename_new_queue) }.to_bytes(), + )); let filename_orig_queue = if !filename_orig_queue.is_null() { - Some(unsafe { CStr::from_ptr(filename_orig_queue) }) + Some(Path::new(OsStr::from_bytes( + unsafe { CStr::from_ptr(filename_orig_queue) }.to_bytes(), + ))) } else { None }; @@ -271,9 +285,14 @@ pub mod wrappers { /// Internal function used in the macro pub fn afl_custom_introspection_(data: *mut c_void) -> *const c_char { match catch_unwind(|| { - let mut context = FFIContext::::from(data); + let context = &mut *FFIContext::::from(data); if let Some(res) = context.mutator.introspection() { - res.as_ptr() + let buf = &mut context.introspection_buffer; + buf.clear(); + buf.extend_from_slice(res.as_bytes()); + buf.push(0); + // unwrapping here, as the error case should be extremely rare + CStr::from_bytes_with_nul(&buf).unwrap().as_ptr() } else { null() } @@ -289,9 +308,14 @@ pub mod wrappers { max_description_len: usize, ) -> *const c_char { match catch_unwind(|| { - let mut context = FFIContext::::from(data); + let context = &mut *FFIContext::::from(data); if let Some(res) = context.mutator.describe(max_description_len) { - res.as_ptr() + let buf = &mut context.description_buffer; + buf.clear(); + buf.extend_from_slice(res.as_bytes()); + buf.push(0); + // unwrapping here, as the error case should be extremely rare + CStr::from_bytes_with_nul(&buf).unwrap().as_ptr() } else { null() } @@ -310,9 +334,9 @@ pub mod wrappers { let mut context = FFIContext::::from(data); assert!(!filename.is_null()); - context - .mutator - .queue_get(unsafe { CStr::from_ptr(filename) }) as u8 + context.mutator.queue_get(Path::new(OsStr::from_bytes( + unsafe { CStr::from_ptr(filename) }.to_bytes(), + ))) as u8 }) { Ok(ret) => ret, Err(err) => panic_handler("afl_custom_queue_get", err), @@ -516,21 +540,21 @@ pub trait CustomMutator { fn queue_new_entry( &mut self, - filename_new_queue: &CStr, - filename_orig_queue: Option<&CStr>, + filename_new_queue: &Path, + filename_orig_queue: Option<&Path>, ) -> Result<(), Self::Error> { Ok(()) } - fn queue_get(&mut self, filename: &CStr) -> Result { + fn queue_get(&mut self, filename: &Path) -> Result { Ok(true) } - fn describe(&mut self, max_description: usize) -> Result, Self::Error> { - Ok(None) + fn describe(&mut self, max_description: usize) -> Result, Self::Error> { + Ok(Some(default_mutator_describe::(max_description))) } - fn introspection(&mut self) -> Result, Self::Error> { + fn introspection(&mut self) -> Result, Self::Error> { Ok(None) } } @@ -593,7 +617,7 @@ where } } - fn queue_new_entry(&mut self, filename_new_queue: &CStr, filename_orig_queue: Option<&CStr>) { + fn queue_new_entry(&mut self, filename_new_queue: &Path, filename_orig_queue: Option<&Path>) { match self.queue_new_entry(filename_new_queue, filename_orig_queue) { Ok(r) => r, Err(e) => { @@ -602,7 +626,7 @@ where } } - fn queue_get(&mut self, filename: &CStr) -> bool { + fn queue_get(&mut self, filename: &Path) -> bool { match self.queue_get(filename) { Ok(r) => r, Err(e) => { @@ -612,7 +636,7 @@ where } } - fn describe(&mut self, max_description: usize) -> Option<&CStr> { + fn describe(&mut self, max_description: usize) -> Option<&str> { match self.describe(max_description) { Ok(r) => r, Err(e) => { @@ -622,7 +646,7 @@ where } } - fn introspection(&mut self) -> Option<&CStr> { + fn introspection(&mut self) -> Option<&str> { match self.introspection() { Ok(r) => r, Err(e) => { @@ -632,3 +656,85 @@ where } } } + +/// the default value to return from [`CustomMutator::describe`]. +fn default_mutator_describe(max_len: usize) -> &'static str { + truncate_str_unicode_safe(std::any::type_name::(), max_len) +} + +#[cfg(all(test, not(feature = "afl_internals")))] +mod default_mutator_describe { + struct MyMutator; + use super::CustomMutator; + impl CustomMutator for MyMutator { + type Error = (); + + fn init(_: u32) -> Result { + Ok(Self) + } + + fn fuzz<'b, 's: 'b>( + &'s mut self, + _: &'b mut [u8], + _: Option<&[u8]>, + _: usize, + ) -> Result, Self::Error> { + unimplemented!() + } + } + + #[test] + fn test_default_describe() { + assert_eq!( + MyMutator::init(0).unwrap().describe(64).unwrap().unwrap(), + "custom_mutator::default_mutator_describe::MyMutator" + ); + } +} + +/// little helper function to truncate a `str` to a maximum of bytes while retaining unicode safety +fn truncate_str_unicode_safe(s: &str, max_len: usize) -> &str { + if s.len() <= max_len { + s + } else { + if let Some((last_index, _)) = s + .char_indices() + .take_while(|(index, _)| *index <= max_len) + .last() + { + &s[..last_index] + } else { + "" + } + } +} + +#[cfg(test)] +mod truncate_test { + use super::truncate_str_unicode_safe; + + #[test] + fn test_truncate() { + for (max_len, input, expected_output) in &[ + (0usize, "a", ""), + (1, "a", "a"), + (1, "ä", ""), + (2, "ä", "ä"), + (3, "äa", "äa"), + (4, "äa", "äa"), + (1, "👎", ""), + (2, "👎", ""), + (3, "👎", ""), + (4, "👎", "👎"), + (1, "abc", "a"), + (2, "abc", "ab"), + ] { + let actual_output = truncate_str_unicode_safe(input, *max_len); + assert_eq!( + &actual_output, expected_output, + "{:#?} truncated to {} bytes should be {:#?}, but is {:#?}", + input, max_len, expected_output, actual_output + ); + } + } +} diff --git a/custom_mutators/rust/example/src/example_mutator.rs b/custom_mutators/rust/example/src/example_mutator.rs index 9b9d4997..c4711dd1 100644 --- a/custom_mutators/rust/example/src/example_mutator.rs +++ b/custom_mutators/rust/example/src/example_mutator.rs @@ -1,3 +1,4 @@ +#![cfg(unix)] #![allow(unused_variables)] use custom_mutator::{export_mutator, CustomMutator}; diff --git a/custom_mutators/rust/example_lain/src/lain_mutator.rs b/custom_mutators/rust/example_lain/src/lain_mutator.rs index 22e5fe73..7099aeae 100644 --- a/custom_mutators/rust/example_lain/src/lain_mutator.rs +++ b/custom_mutators/rust/example_lain/src/lain_mutator.rs @@ -1,3 +1,5 @@ +#![cfg(unix)] + use custom_mutator::{export_mutator, CustomMutator}; use lain::{ mutator::Mutator, -- cgit 1.4.1 From e8d580f54d0ba4cc096f084ed7c52e772b66039c Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 5 Mar 2021 19:45:48 +0100 Subject: rust mutator changes added to changelog --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 4e76fedd..3ca4a20b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -11,6 +11,7 @@ sending a mail to . ### Version ++3.11a (dev) - afl-fuzz - add non-unicode variants from unicode-looking dictionary entries + - Rust custom mutator API improvements - afl-cc - fixed a crash that can occur with ASAN + CMPLOG together plus better support for unicode (thanks to @stbergmann for reporting!) -- cgit 1.4.1 From 7b907e45ada18020da03b69a24bc68b64a11d1e7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 5 Mar 2021 19:55:20 +0100 Subject: we do not support 80 + 128 bit FP in laf --- instrumentation/split-compares-pass.so.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index d03944df..b02a89fb 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -612,6 +612,10 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { if (op_size != op1->getType()->getPrimitiveSizeInBits()) { continue; } const unsigned int sizeInBits = op0->getType()->getPrimitiveSizeInBits(); + + // BUG FIXME TODO: u64 does not work for > 64 bit ... e.g. 80 and 128 bit + if (sizeInBits > 64) { continue; } + const unsigned int precision = sizeInBits == 32 ? 24 : sizeInBits == 64 ? 53 : sizeInBits == 128 ? 113 @@ -619,8 +623,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { : sizeInBits == 80 ? 65 : sizeInBits - 8; - const unsigned shiftR_exponent = precision - 1; - // BUG FIXME TODO: u64 does not work for > 64 bit ... e.g. 80 and 128 bit + const unsigned shiftR_exponent = precision - 1; const unsigned long long mask_fraction = (1ULL << (shiftR_exponent - 1)) | ((1ULL << (shiftR_exponent - 1)) - 1); const unsigned long long mask_exponent = -- cgit 1.4.1 From 9b3d8c327d33191b181219ffce411b40bdbe8902 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 6 Mar 2021 10:20:01 +0100 Subject: fix for asan compile rt --- instrumentation/afl-compiler-rt.o.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index c741bc05..a702ec39 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1703,41 +1703,25 @@ __attribute__((weak)) void *__asan_region_is_poisoned(void *beg, size_t size) { // to avoid to call it on .text addresses static int area_is_valid(void *ptr, size_t len) { - void *ret_ptr = __asan_region_is_poisoned(ptr, len); + if (unlikely(__asan_region_is_poisoned(ptr, len))) { return 0; } - if (ret_ptr) { // region is poisoned + long r = syscall(__afl_dummy_fd[1], SYS_write, ptr, len); - ssize_t ret_diff = ret_ptr - ptr; - - if (ret_diff <= 0) { - - return 0; - - } else { - - return ret_diff; // only partially poisoned - - } - - } - - int r = syscall(__afl_dummy_fd[1], SYS_write, ptr, len); - - if (r <= 0) { // maybe this is going over an asan boundary + if (unlikely(r <= 0 || r > len)) { // fail - maybe hitting asan boundary? char *p = (char *)ptr; long page_size = sysconf(_SC_PAGE_SIZE); char *page = (char *)((uintptr_t)p & ~(page_size - 1)) + page_size; - if (page < p + len) { return 0; } + if (page < p + len) { return 0; } // no isnt, return fail len -= (p + len - page); r = syscall(__afl_dummy_fd[1], SYS_write, p, len); } // partial writes - we return what was written. - if (r > 0) { + if (likely(r >= 0 && r <= len)) { - return r; + return (int)r; } else { -- cgit 1.4.1