diff --git a/Makefile b/Makefile index c3fa8617..e1f6e7ea 100644 --- a/Makefile +++ b/Makefile @@ -22,8 +22,7 @@ HELPER_PATH = $(PREFIX)/lib/afl DOC_PATH = $(PREFIX)/share/doc/afl MISC_PATH = $(PREFIX)/share/afl -# PROGS intentionally omit afl-as and libdislocator.so, which get installed -# to a different location. +# PROGS intentionally omit afl-as, which gets installed elsewhere. PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze SH_PROGS = afl-plot afl-cmin afl-whatsup @@ -45,7 +44,7 @@ endif COMM_HDR = alloc-inl.h config.h debug.h types.h -all: test_x86 $(PROGS) afl-as libdislocator.so test_build all_done +all: test_x86 $(PROGS) afl-as test_build all_done ifndef AFL_NO_X86 @@ -85,9 +84,6 @@ afl-analyze: afl-analyze.c $(COMM_HDR) | test_x86 afl-gotcpu: afl-gotcpu.c $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) -libdislocator.so: libdislocator.so.c $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) -shared -fPIC $@.c -o $@ $(LDFLAGS) - ifndef AFL_NO_X86 test_build: afl-gcc afl-as afl-showmap @@ -115,9 +111,11 @@ all_done: test_build .NOTPARALLEL: clean clean: - rm -f $(PROGS) libdislocator.so afl-as as afl-g++ afl-clang afl-clang++ *.o *~ a.out core core.[1-9][0-9]* *.stackdump test .test test-instr .test-instr0 .test-instr1 qemu_mode/qemu-2.3.0.tar.bz2 afl-qemu-trace + rm -f $(PROGS) afl-as as afl-g++ afl-clang afl-clang++ *.o *~ a.out core core.[1-9][0-9]* *.stackdump test .test test-instr .test-instr0 .test-instr1 qemu_mode/qemu-2.3.0.tar.bz2 afl-qemu-trace rm -rf out_dir qemu_mode/qemu-2.3.0 $(MAKE) -C llvm_mode clean + $(MAKE) -C libdislocator clean + $(MAKE) -C libtokencap clean install: all mkdir -p -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) @@ -130,7 +128,6 @@ install: all if [ -f afl-llvm-rt-64.o ]; then set -e; install -m 755 afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $${DESTDIR}$(BIN_PATH)/$$i; done install -m 755 afl-as $${DESTDIR}$(HELPER_PATH) - install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH) ln -sf afl-as $${DESTDIR}$(HELPER_PATH)/as install -m 644 docs/README docs/ChangeLog docs/*.txt $${DESTDIR}$(DOC_PATH) cp -r testcases/ $${DESTDIR}$(MISC_PATH) diff --git a/afl-gcc.c b/afl-gcc.c index b6cbc05c..1a588da9 100644 --- a/afl-gcc.c +++ b/afl-gcc.c @@ -116,7 +116,7 @@ static void edit_params(u32 argc, char** argv) { u8 m32_set = 0; #endif - cc_params = ck_alloc((argc + 64) * sizeof(u8*)); + cc_params = ck_alloc((argc + 128) * sizeof(u8*)); name = strrchr(argv[0], '/'); if (!name) name = argv[0]; else name++; @@ -271,6 +271,16 @@ static void edit_params(u32 argc, char** argv) { } + if (getenv("AFL_NO_BUILTIN")) { + + cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; + + } + cc_params[cc_par_cnt] = NULL; } diff --git a/config.h b/config.h index cd7b3491..b73fc28e 100644 --- a/config.h +++ b/config.h @@ -21,7 +21,7 @@ /* Version string: */ -#define VERSION "2.26b" +#define VERSION "2.27b" /****************************************************** * * diff --git a/docs/ChangeLog b/docs/ChangeLog index d7a01fe0..d23b9f5b 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -16,6 +16,17 @@ Not sure if you should upgrade? The lowest currently recommended version is 2.21b. If you're stuck on an earlier release, it's strongly advisable to get on with the times. +-------------- +Version 2.27b: +-------------- + + - Added libtokencap, a simple feature to intercept strcmp / memcmp and + generate dictionary entries that can help extend coverage. + + - Moved libdislocator to its own dir, added README. + + - The demo in experimental/instrumented_cmp is no more. + -------------- Version 2.26b: -------------- diff --git a/docs/README b/docs/README index 18dcbc34..ba460887 100644 --- a/docs/README +++ b/docs/README @@ -115,9 +115,8 @@ $ CC=/path/to/afl/afl-gcc ./configure --disable-shared Setting AFL_HARDEN=1 when calling 'make' will cause the CC wrapper to automatically enable code hardening options that make it easier to detect -simple memory bugs. Preloading 'libdislocator.so' (an abusive allocator) can -help uncover heap corruption issues, too; see libdislocator.so.c for info and -usage tips. +simple memory bugs. Libdislocator, a helper library included with AFL (see +libdislocator/README.dislocator) can help uncover heap corruption issues, too. PS. ASAN users are advised to review notes_for_asan.txt file for important caveats. @@ -292,6 +291,10 @@ existing syntax tokens in the input corpus by watching the instrumentation very closely during deterministic byte flips. This works for some types of parsers and grammars, but isn't nearly as good as the -x mode. +If a dictionary is really hard to come by, another option is to let AFL run +for a while, and then use the token capture library that comes as a companion +utility with AFL. For that, see libtokencap/README.tokencap. + 10) Crash triage ---------------- diff --git a/docs/notes_for_asan.txt b/docs/notes_for_asan.txt index 06466a3b..0f5bdca9 100644 --- a/docs/notes_for_asan.txt +++ b/docs/notes_for_asan.txt @@ -38,7 +38,9 @@ is not AFL-specific. There is also the option of generating a corpus using a non-ASAN binary, and then feeding it to an ASAN-instrumented one to check for bugs. This is faster, -and can give you somewhat comparable results. +and can give you somewhat comparable results. You can also try using +libdislocator (see libdislocator/README.dislocator in the parent directory) as a +lightweight and hassle-free (but less thorough) alternative. 2) Long version --------------- diff --git a/experimental/README.experiments b/experimental/README.experiments index 3e7e9eb4..af9739bd 100644 --- a/experimental/README.experiments +++ b/experimental/README.experiments @@ -22,10 +22,6 @@ Here's a quick overview of the stuff you can find in this directory: - distributed_fuzzing - a sample script for synchronizing fuzzer instances across multiple machines (see parallel_fuzzing.txt). - - instrumented_cmp - an experiment showing how a custom memcmp() or - strcmp() can be used to work around one of the - limitations of afl-fuzz. - - libpng_no_checksum - a sample patch for removing CRC checks in libpng. - persistent_demo - an example of how to use the LLVM persistent process diff --git a/experimental/instrumented_cmp/instrumented_cmp.c b/experimental/instrumented_cmp/instrumented_cmp.c deleted file mode 100644 index 8806c72d..00000000 --- a/experimental/instrumented_cmp/instrumented_cmp.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - - american fuzzy lop - instrumented strcmp() or memcmp() proof-of-concept - ----------------------------------------------------------------------- - - Written and maintained by Michal Zalewski - - Copyright 2015 Google Inc. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - - http://www.apache.org/licenses/LICENSE-2.0 - - Normally, afl-fuzz will have difficulty ever reaching the code behind - something like: - - if (!strcmp(password, "s3cr3t!")) ... - - This is because the strcmp() operation is completely opaque to the tool. - A simple and non-invasive workaround that doesn't require complex code - analysis is to replace strcmp(), memcmp(), and equivalents with - inlined, non-optimized code. - - I am still evaluating the value of doing this, but for time being, here's - a quick demo of how it may work. To test: - - $ ./afl-gcc instrumented_cmp.c - $ mkdir test_in - $ printf xxxxxxxxxxxxxxxx >test_in/input - $ ./afl-fuzz -i test_in -o test_out ./a.out - - */ - -#include -#include -#include - -/* Naive instrumented memcmp(). */ - -inline int my_memcmp(char* ptr1, char* ptr2, int len) - __attribute__((always_inline)); - -inline int my_memcmp(char* ptr1, char* ptr2, int len) { - - while (len--) if (*(ptr1++) ^ *(ptr2++)) return 1; - return 0; - -} - -#define memcmp my_memcmp - -/* Normal program. */ - -char tmp[16]; - -int main(int argc, char** argv) { - - int len = read(0, tmp, sizeof(tmp)); - - if (len != sizeof(tmp)) { - - printf("Truncated file!\n"); - exit(1); - - } - - if (!memcmp(tmp + 5, "sesame", 6)) { - - /* Simulated "faulty" code path. */ - - int* x = (int*)0x12345678; - *x = 1; - - } else printf("Bad password.\n"); - - return 0; - -} diff --git a/libdislocator/Makefile b/libdislocator/Makefile new file mode 100644 index 00000000..73433944 --- /dev/null +++ b/libdislocator/Makefile @@ -0,0 +1,37 @@ +# +# american fuzzy lop - libdislocator +# ---------------------------------- +# +# Written by Michal Zalewski +# +# Copyright 2016 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# + +PREFIX ?= /usr/local +HELPER_PATH = $(PREFIX)/lib/afl + +VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2) + +CFLAGS ?= -O3 -funroll-loops +CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign + +all: libdislocator.so + +libdislocator.so: libdislocator.so.c ../config.h + $(CC) $(CFLAGS) -shared -fPIC $< -o $@ $(LDFLAGS) + +.NOTPARALLEL: clean + +clean: + rm -f *.o *.so *~ a.out core core.[1-9][0-9]* + rm -f libdislocator.so + +install: all + install -m 755 libdislocator.so $${DESTDIR}$(HELPER_PATH) + diff --git a/libdislocator/README.dislocator b/libdislocator/README.dislocator new file mode 100644 index 00000000..837e7466 --- /dev/null +++ b/libdislocator/README.dislocator @@ -0,0 +1,60 @@ +=================================== +libdislocator, an abusive allocator +=================================== + + (See ../docs/README for the general instruction manual.) + +This is a companion library that can be used as a drop-in replacement for the +libc allocator in the fuzzed binaries. It improves the odds of bumping into +heap-related security bugs in several ways: + + - It allocates all buffers so that they are immediately adjacent to a + subsequent PROT_NONE page, causing most off-by-one reads and writes to + immediately segfault, + + - It adds a canary immediately below the allocated buffer, to catch writes + to negative offsets (won't catch reads, though), + + - It sets the memory returned by malloc() to garbage values, improving the + odds of crashing when the target accesses uninitialized data, + + - It sets freed memory to PROT_NONE and does not actually reuse it, causing + most use-after-free bugs to segfault right away, + + - It forces all realloc() calls to return a new address - and sets + PROT_NONE on the original block. This catches use-after-realloc bugs, + + - It checks for calloc() overflows and can cause soft or hard failures + of alloc requests past a configurable memory limit (AFL_LD_LIMIT_MB, + AFL_LD_HARD_FAIL). + +Basically, it is inspired by some of the non-default options available for the +OpenBSD allocator - see malloc.conf(5) on that platform for reference. It is +also somewhat similar to several other debugging libraries, such as gmalloc +and DUMA - but is simple, plug-and-play, and designed specifically for fuzzing +jobs. + +Note that it does nothing for stack-based memory handling errors. The +-fstack-protector-all setting for GCC / clang, enabled when using AFL_HARDEN, +can catch some subset of that. + +The allocator is slow and memory-intensive (even the tiniest allocation uses up +4 kB of physical memory and 8 kB of virtual mem), making it completely unsuitable +for "production" uses; but it can be faster and more hassle-free than ASAN / MSAN +when fuzzing small, self-contained binaries. + +To use this library, run AFL like so: + +AFL_PRELOAD=/path/to/libdislocator.so ./afl-fuzz [...other params...] + +You *have* to specify path, even if it's just ./libdislocator.so or +$PWD/libdislocator.so. + +Similarly to afl-tmin, the library is not "proprietary" and can be used with +other fuzzers or testing tools without the need for any code tweaks. It does not +require AFL-instrumented binaries to work. + +Note that the AFL_PRELOAD approach (which AFL internally maps to LD_PRELOAD or +DYLD_INSERT_LIBRARIES, depending on the OS) works only if the target binary is +dynamically linked. Otherwise, attempting to use the library will have no +effect. diff --git a/libdislocator.so.c b/libdislocator/libdislocator.so.c similarity index 70% rename from libdislocator.so.c rename to libdislocator/libdislocator.so.c index d91a185d..e2f737e9 100644 --- a/libdislocator.so.c +++ b/libdislocator/libdislocator.so.c @@ -14,57 +14,8 @@ http://www.apache.org/licenses/LICENSE-2.0 This is a companion library that can be used as a drop-in replacement - for the libc allocator in the fuzzed binaries. It improves the odds of - bumping into heap-related security bugs in several ways: - - - It allocates all buffers so that they are immediately adjacent to a - subsequent PROT_NONE page, causing most off-by-one reads and writes - to immediately segfault, - - - It adds a canary immediately below the allocated buffer, to catch - writes to negative offsets (won't catch reads, though), - - - It sets the memory returned by malloc() to garbage values, improving - the odds of crashing when the target accesses uninitialized data, - - - It sets freed memory to PROT_NONE and does not actually reuse it, - causing most use-after-free bugs to segfault right away, - - - It forces all realloc() calls to return a new address - and sets - PROT_NONE on the original block. This catches use-after-realloc bugs, - - - It checks for calloc() overflows and can cause soft or hard failures - of alloc requests past a configurable memory limit (AFL_LD_LIMIT_MB, - AFL_LD_HARD_FAIL). - - Basically, it is inspired by some of the non-default options available - for the OpenBSD allocator - see malloc.conf(5) on that platform for - reference. It is also somewhat similar to several other debugging - libraries, such as gmalloc and DUMA, but is simple, plug-and-play, and - designed specifically for fuzzing jobs. - - Note that it does nothing for stack-based memory handling errors. The - -fstack-protector-all setting for GCC / clang, enabled when using - AFL_HARDEN, can catch some subset of that. - - The allocator is slow and memory-intensive (even the tiniest allocation - uses up 4 kB of physical memory and 8 kB of virtual mem), making it - completely unsuitable for "production" uses; but it can be faster and more - hassle-free than ASAN / MSAN when fuzzing small, self-contained binaries. - - To use this library, run AFL like so: - - AFL_PRELOAD=/path/to/libdislocator.so ./afl-fuzz [...other params...] - - You *have* to specify path, even if it's just ./libdislocator.so or - $PWD/libdislocator.so. - - Similarly to afl-tmin, the library is not "proprietary" and can be - used with other fuzzers or testing tools without the need for any code - tweaks. - - Note that the LD_PRELOAD approach will work only if the target binary is - dynamically linked. + for the libc allocator in the fuzzed binaries. See README.dislocator for + more info. */ @@ -74,8 +25,8 @@ #include #include -#include "config.h" -#include "types.h" +#include "../config.h" +#include "../types.h" #ifndef PAGE_SIZE # define PAGE_SIZE 4096 @@ -118,7 +69,7 @@ #define PTR_C(_p) (((u32*)(_p))[-1]) #define PTR_L(_p) (((u32*)(_p))[-2]) -/* Configurable stuff (use AFL_DISLOC_* to set): */ +/* Configurable stuff (use AFL_LD_* to set): */ static u32 max_mem = MAX_ALLOC; /* Max heap usage to permit */ static u8 alloc_verbose, /* Additional debug messages */ @@ -128,6 +79,7 @@ static __thread size_t total_mem; /* Currently allocated mem */ static __thread u32 call_depth; /* To avoid recursion via fprintf() */ + /* This is the main alloc function. It allocates one page more than necessary, sets that tailing page to PROT_NONE, and then increments the return address so that it is right-aligned to that boundary. Since it always uses mmap(), diff --git a/libtokencap/Makefile b/libtokencap/Makefile new file mode 100644 index 00000000..21422deb --- /dev/null +++ b/libtokencap/Makefile @@ -0,0 +1,37 @@ +# +# american fuzzy lop - libtokencap +# -------------------------------- +# +# Written by Michal Zalewski +# +# Copyright 2016 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# + +PREFIX ?= /usr/local +HELPER_PATH = $(PREFIX)/lib/afl + +VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2) + +CFLAGS ?= -O3 -funroll-loops +CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign + +all: libtokencap.so + +libtokencap.so: libtokencap.so.c ../config.h + $(CC) $(CFLAGS) -shared -fPIC $< -o $@ $(LDFLAGS) + +.NOTPARALLEL: clean + +clean: + rm -f *.o *.so *~ a.out core core.[1-9][0-9]* + rm -f libtokencap.so + +install: all + install -m 755 libtokencap.so $${DESTDIR}$(HELPER_PATH) + diff --git a/libtokencap/README.tokencap b/libtokencap/README.tokencap new file mode 100644 index 00000000..01472fb8 --- /dev/null +++ b/libtokencap/README.tokencap @@ -0,0 +1,57 @@ +========================================= +strcmp() / memcmp() token capture library +========================================= + + (See ../docs/README for the general instruction manual.) + +This Linux-only companion library allows you to instrument strcmp(), memcmp(), +and related functions to automatically extract syntax tokens that happen to be +scanned for using these functions. The resulting list may be then passed as a +dictionary to afl-fuzz (the -x option) to improve coverage on subsequent +fuzzing runs. + +This may help improving coverage in some targets, and do precisely nothing in +others. In some cases, it may even make things worse if the library picks up +syntax tokens that are not used to process the input data, but that showed up +as a result of parsing a config file or other unrelated stuff; a dictionary +with junk tokens will simply waste a ton of CPU time. In other words, use this +with care. + +The library prints tokens, without any deduping, by appending them to a file +specified via AFL_TOKEN_FILE. If the variable is not set, the tool uses stderr +(which is probably not what you want). + +Similarly to afl-tmin, the library is not "proprietary" and can be used with +other fuzzers or testing tools without the need for any code tweaks. It does not +require AFL-instrumented binaries to work. + +To use the library, you *need* to make sure that your fuzzing target is compiled +with -fno-builtin and is linked dynamically. If you wish to automate the first +part without mucking with CFLAGS in Makefiles, you can set AFL_NO_BUILTIN=1 +when using afl-gcc. This setting specifically adds the following flags: + + -fno-builtin-strcmp -fno-builtin-strncmp -fno-builtin-strcasecmp + -fno-builtin-strcasencmp -fno-builtin-memcmp + +The next step is simply loading this library via LD_PRELOAD. The optimal usage +pattern is to allow afl-fuzz to fuzz normally for a while and build up a corpus, +and then fire off the target binary, with libtokencap.so loaded, on every file +found by AFL in that earlier run. Here's the basic idea: + + export AFL_TOKEN_FILE=$PWD/temp_output.txt + + for i in /queue/id*; do + LD_PRELOAD=/path/to/libtokencap.so \ + /path/to/target/program [...params, including $i...] + done + + sort -u temp_output.txt >afl_dictionary.txt + +If you don't get any results, the target library is probably not using strcmp() +and memcmp() to parse input; or you haven't compiled it with -fno-builtin; or +the whole thing isn't dynamically linked, and LD_PRELOAD is having no effect. + +PS. The library is Linux-only because there is probably no particularly portable +and non-invasive way to distinguish between read-only and read-write memory +mappings. The __tokencap_load_mappings() function is the only thing that would +need to be changed for other OSes. diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c new file mode 100644 index 00000000..696c913d --- /dev/null +++ b/libtokencap/libtokencap.so.c @@ -0,0 +1,253 @@ +/* + + american fuzzy lop - extract tokens passed to strcmp / memcmp + ------------------------------------------------------------- + + Written and maintained by Michal Zalewski + + Copyright 2016 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This Linux-only companion library allows you to instrument strcmp(), + memcmp(), and related functions to automatically extract tokens. + See README.tokencap for more info. + + */ + +#include +#include +#include + +#include "../types.h" +#include "../config.h" + +#ifndef __linux__ +# error "Sorry, this library is Linux-specific for now!" +#endif /* !__linux__ */ + + +/* Mapping data and such */ + +#define MAX_MAPPINGS 1024 + +static struct mapping { + void *st, *en; +} __tokencap_ro[MAX_MAPPINGS]; + +static u32 __tokencap_ro_cnt; +static u8 __tokencap_ro_loaded; +static FILE* __tokencap_out_file; + + +/* Identify read-only regions in memory. Only parameters that fall into these + ranges are worth dumping when passed to strcmp() and so on. Read-write + regions are far more likely to contain user input instead. */ + +static void __tokencap_load_mappings(void) { + + u8 buf[MAX_LINE]; + FILE* f = fopen("/proc/self/maps", "r"); + + __tokencap_ro_loaded = 1; + + if (!f) return; + + while (fgets(buf, MAX_LINE, f)) { + + u8 rf, wf; + void* st, *en; + + if (sscanf(buf, "%p-%p %c%c", &st, &en, &rf, &wf) != 4) continue; + if (wf == 'w' || rf != 'r') continue; + + __tokencap_ro[__tokencap_ro_cnt].st = (void*)st; + __tokencap_ro[__tokencap_ro_cnt].en = (void*)en; + + if (++__tokencap_ro_cnt == MAX_MAPPINGS) break; + + } + + fclose(f); + +} + + +/* Check an address against the list of read-only mappings. */ + +static u8 __tokencap_is_ro(const void* ptr) { + + u32 i; + + if (!__tokencap_ro_loaded) __tokencap_load_mappings(); + + for (i = 0; i < __tokencap_ro_cnt; i++) + if (ptr >= __tokencap_ro[i].st && ptr <= __tokencap_ro[i].en) return 1; + + return 0; + +} + + +/* Dump an interesting token to output file, quoting and escaping it + properly. */ + +static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) { + + u8 buf[MAX_AUTO_EXTRA * 4 + 1]; + u32 i; + u32 pos = 0; + + if (len < MIN_AUTO_EXTRA || len > MAX_AUTO_EXTRA) return; + + for (i = 0; i < len; i++) { + + if (is_text && !ptr[i]) break; + + switch (ptr[i]) { + + case 0 ... 31: + case 127 ... 255: + case '\"': + case '\\': + + sprintf(buf + pos, "\\x%02x", ptr[i]); + pos += 4; + break; + + default: + + buf[pos++] = ptr[i]; + + } + + } + + buf[pos] = 0; + + fprintf(__tokencap_out_file, "\"%s\"\n", buf); + +} + + +/* Replacements for strcmp(), memcmp(), and so on. Note that these will be used + only if the target is compiled with -fno-builtins and linked dynamically. */ + +#undef strcmp + +int strcmp(const char* str1, const char* str2) { + + if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1); + if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1); + + while (1) { + + unsigned char c1 = *str1, c2 = *str2; + + if (c1 != c2) return (c1 > c2) ? 1 : -1; + if (!c1) return 0; + str1++; str2++; + + } + +} + + +#undef strncmp + +int strncmp(const char* str1, const char* str2, size_t len) { + + if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1); + if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1); + + while (len--) { + + unsigned char c1 = *str1, c2 = *str2; + + if (!c1) return 0; + if (c1 != c2) return (c1 > c2) ? 1 : -1; + str1++; str2++; + + } + + return 0; + +} + + +#undef strcasecmp + +int strcasecmp(const char* str1, const char* str2) { + + if (__tokencap_is_ro(str1)) __tokencap_dump(str1, strlen(str1), 1); + if (__tokencap_is_ro(str2)) __tokencap_dump(str2, strlen(str2), 1); + + while (1) { + + unsigned char c1 = tolower(*str1), c2 = tolower(*str2); + + if (c1 != c2) return (c1 > c2) ? 1 : -1; + if (!c1) return 0; + str1++; str2++; + + } + +} + + +#undef strncasecmp + +int strncasecmp(const char* str1, const char* str2, size_t len) { + + if (__tokencap_is_ro(str1)) __tokencap_dump(str1, len, 1); + if (__tokencap_is_ro(str2)) __tokencap_dump(str2, len, 1); + + while (len--) { + + unsigned char c1 = tolower(*str1), c2 = tolower(*str2); + + if (!c1) return 0; + if (c1 != c2) return (c1 > c2) ? 1 : -1; + str1++; str2++; + + } + + return 0; + +} + + +#undef memcmp + +int memcmp(const void* mem1, const void* mem2, size_t len) { + + if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0); + if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0); + + while (len--) { + + unsigned char c1 = *(const char*)mem1, c2 = *(const char*)mem2; + if (c1 != c2) return (c1 > c2) ? 1 : -1; + mem1++; mem2++; + + } + + return 0; + +} + + +/* Init code to open the output file (or default to stderr). */ + +__attribute__((constructor)) void __tokencap_init(void) { + + u8* fn = getenv("AFL_TOKEN_FILE"); + if (fn) __tokencap_out_file = fopen(fn, "a"); + if (!__tokencap_out_file) __tokencap_out_file = stderr; + +} + diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index d9e4ef19..725a16fa 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -99,7 +99,7 @@ static void edit_params(u32 argc, char** argv) { u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1, bit_mode = 0; u8 *name; - cc_params = ck_alloc((argc + 64) * sizeof(u8*)); + cc_params = ck_alloc((argc + 128) * sizeof(u8*)); name = strrchr(argv[0], '/'); if (!name) name = argv[0]; else name++; @@ -200,6 +200,16 @@ static void edit_params(u32 argc, char** argv) { } + if (getenv("AFL_NO_BUILTIN")) { + + cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; + + } + cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";