Index: third_party/afl/src/afl-gcc.c |
diff --git a/third_party/afl/src/afl-gcc.c b/third_party/afl/src/afl-gcc.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b6cbc05c801fdda24e0cc66508c602d100b68806 |
--- /dev/null |
+++ b/third_party/afl/src/afl-gcc.c |
@@ -0,0 +1,318 @@ |
+/* |
+ american fuzzy lop - wrapper for GCC and clang |
+ ---------------------------------------------- |
+ |
+ Written and maintained by Michal Zalewski <lcamtuf@google.com> |
+ |
+ Copyright 2013, 2014, 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 |
+ |
+ This program is a drop-in replacement for GCC or clang. The most common way |
+ of using it is to pass the path to afl-gcc or afl-clang via CC when invoking |
+ ./configure. |
+ |
+ (Of course, use CXX and point it to afl-g++ / afl-clang++ for C++ code.) |
+ |
+ The wrapper needs to know the path to afl-as (renamed to 'as'). The default |
+ is /usr/local/lib/afl/. A convenient way to specify alternative directories |
+ would be to set AFL_PATH. |
+ |
+ If AFL_HARDEN is set, the wrapper will compile the target app with various |
+ hardening options that may help detect memory management issues more |
+ reliably. You can also specify AFL_USE_ASAN to enable ASAN. |
+ |
+ If you want to call a non-default compiler as a next step of the chain, |
+ specify its location via AFL_CC or AFL_CXX. |
+ |
+ */ |
+ |
+#define AFL_MAIN |
+ |
+#include "config.h" |
+#include "types.h" |
+#include "debug.h" |
+#include "alloc-inl.h" |
+ |
+#include <stdio.h> |
+#include <unistd.h> |
+#include <stdlib.h> |
+#include <string.h> |
+ |
+static u8* as_path; /* Path to the AFL 'as' wrapper */ |
+static u8** cc_params; /* Parameters passed to the real CC */ |
+static u32 cc_par_cnt = 1; /* Param count, including argv0 */ |
+static u8 be_quiet, /* Quiet mode */ |
+ clang_mode; /* Invoked as afl-clang*? */ |
+ |
+ |
+/* Try to find our "fake" GNU assembler in AFL_PATH or at the location derived |
+ from argv[0]. If that fails, abort. */ |
+ |
+static void find_as(u8* argv0) { |
+ |
+ u8 *afl_path = getenv("AFL_PATH"); |
+ u8 *slash, *tmp; |
+ |
+ if (afl_path) { |
+ |
+ tmp = alloc_printf("%s/as", afl_path); |
+ |
+ if (!access(tmp, X_OK)) { |
+ as_path = afl_path; |
+ ck_free(tmp); |
+ return; |
+ } |
+ |
+ ck_free(tmp); |
+ |
+ } |
+ |
+ slash = strrchr(argv0, '/'); |
+ |
+ if (slash) { |
+ |
+ u8 *dir; |
+ |
+ *slash = 0; |
+ dir = ck_strdup(argv0); |
+ *slash = '/'; |
+ |
+ tmp = alloc_printf("%s/afl-as", dir); |
+ |
+ if (!access(tmp, X_OK)) { |
+ as_path = dir; |
+ ck_free(tmp); |
+ return; |
+ } |
+ |
+ ck_free(tmp); |
+ ck_free(dir); |
+ |
+ } |
+ |
+ if (!access(AFL_PATH "/as", X_OK)) { |
+ as_path = AFL_PATH; |
+ return; |
+ } |
+ |
+ FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH"); |
+ |
+} |
+ |
+ |
+/* Copy argv to cc_params, making the necessary edits. */ |
+ |
+static void edit_params(u32 argc, char** argv) { |
+ |
+ u8 fortify_set = 0, asan_set = 0; |
+ u8 *name; |
+ |
+#if defined(__FreeBSD__) && defined(__x86_64__) |
+ u8 m32_set = 0; |
+#endif |
+ |
+ cc_params = ck_alloc((argc + 64) * sizeof(u8*)); |
+ |
+ name = strrchr(argv[0], '/'); |
+ if (!name) name = argv[0]; else name++; |
+ |
+ if (!strncmp(name, "afl-clang", 9)) { |
+ |
+ clang_mode = 1; |
+ |
+ setenv(CLANG_ENV_VAR, "1", 1); |
+ |
+ if (!strcmp(name, "afl-clang++")) { |
+ u8* alt_cxx = getenv("AFL_CXX"); |
+ cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; |
+ } else { |
+ u8* alt_cc = getenv("AFL_CC"); |
+ cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; |
+ } |
+ |
+ } else { |
+ |
+ /* With GCJ and Eclipse installed, you can actually compile Java! The |
+ instrumentation will work (amazingly). Alas, unhandled exceptions do |
+ not call abort(), so afl-fuzz would need to be modified to equate |
+ non-zero exit codes with crash conditions when working with Java |
+ binaries. Meh. */ |
+ |
+#ifdef __APPLE__ |
+ |
+ if (!strcmp(name, "afl-g++")) cc_params[0] = getenv("AFL_CXX"); |
+ else if (!strcmp(name, "afl-gcj")) cc_params[0] = getenv("AFL_GCJ"); |
+ else cc_params[0] = getenv("AFL_CC"); |
+ |
+ if (!cc_params[0]) { |
+ |
+ SAYF("\n" cLRD "[-] " cRST |
+ "On Apple systems, 'gcc' is usually just a wrapper for clang. Please use the\n" |
+ " 'afl-clang' utility instead of 'afl-gcc'. If you really have GCC installed,\n" |
+ " set AFL_CC or AFL_CXX to specify the correct path to that compiler.\n"); |
+ |
+ FATAL("AFL_CC or AFL_CXX required on MacOS X"); |
+ |
+ } |
+ |
+#else |
+ |
+ if (!strcmp(name, "afl-g++")) { |
+ u8* alt_cxx = getenv("AFL_CXX"); |
+ cc_params[0] = alt_cxx ? alt_cxx : (u8*)"g++"; |
+ } else if (!strcmp(name, "afl-gcj")) { |
+ u8* alt_cc = getenv("AFL_GCJ"); |
+ cc_params[0] = alt_cc ? alt_cc : (u8*)"gcj"; |
+ } else { |
+ u8* alt_cc = getenv("AFL_CC"); |
+ cc_params[0] = alt_cc ? alt_cc : (u8*)"gcc"; |
+ } |
+ |
+#endif /* __APPLE__ */ |
+ |
+ } |
+ |
+ while (--argc) { |
+ u8* cur = *(++argv); |
+ |
+ if (!strncmp(cur, "-B", 2)) { |
+ |
+ if (!be_quiet) WARNF("-B is already set, overriding"); |
+ |
+ if (!cur[2] && argc > 1) { argc--; argv++; } |
+ continue; |
+ |
+ } |
+ |
+ if (!strcmp(cur, "-integrated-as")) continue; |
+ |
+ if (!strcmp(cur, "-pipe")) continue; |
+ |
+#if defined(__FreeBSD__) && defined(__x86_64__) |
+ if (!strcmp(cur, "-m32")) m32_set = 1; |
+#endif |
+ |
+ if (!strcmp(cur, "-fsanitize=address") || |
+ !strcmp(cur, "-fsanitize=memory")) asan_set = 1; |
+ |
+ if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; |
+ |
+ cc_params[cc_par_cnt++] = cur; |
+ |
+ } |
+ |
+ cc_params[cc_par_cnt++] = "-B"; |
+ cc_params[cc_par_cnt++] = as_path; |
+ |
+ if (clang_mode) |
+ cc_params[cc_par_cnt++] = "-no-integrated-as"; |
+ |
+ if (getenv("AFL_HARDEN")) { |
+ |
+ cc_params[cc_par_cnt++] = "-fstack-protector-all"; |
+ |
+ if (!fortify_set) |
+ cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; |
+ |
+ } |
+ |
+ if (asan_set) { |
+ |
+ /* Pass this on to afl-as to adjust map density. */ |
+ |
+ setenv("AFL_USE_ASAN", "1", 1); |
+ |
+ } else if (getenv("AFL_USE_ASAN")) { |
+ |
+ cc_params[cc_par_cnt++] = "-fsanitize=address"; |
+ |
+ if (getenv("AFL_USE_MSAN")) |
+ FATAL("ASAN and MSAN are mutually exclusive"); |
+ |
+ } else if (getenv("AFL_USE_MSAN")) { |
+ |
+ cc_params[cc_par_cnt++] = "-fsanitize=memory"; |
+ |
+ if (getenv("AFL_USE_ASAN")) |
+ FATAL("ASAN and MSAN are mutually exclusive"); |
+ |
+ } |
+ |
+ if (!getenv("AFL_DONT_OPTIMIZE")) { |
+ |
+#if defined(__FreeBSD__) && defined(__x86_64__) |
+ |
+ /* On 64-bit FreeBSD systems, clang -g -m32 is broken, but -m32 itself |
+ works OK. This has nothing to do with us, but let's avoid triggering |
+ that bug. */ |
+ |
+ if (!clang_mode || !m32_set) |
+ cc_params[cc_par_cnt++] = "-g"; |
+ |
+#else |
+ |
+ cc_params[cc_par_cnt++] = "-g"; |
+ |
+#endif |
+ |
+ cc_params[cc_par_cnt++] = "-O3"; |
+ cc_params[cc_par_cnt++] = "-funroll-loops"; |
+ |
+ /* Two indicators that you're building for fuzzing; one of them is |
+ AFL-specific, the other is shared with libfuzzer. */ |
+ |
+ cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; |
+ cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; |
+ |
+ } |
+ |
+ cc_params[cc_par_cnt] = NULL; |
+ |
+} |
+ |
+ |
+/* Main entry point */ |
+ |
+int main(int argc, char** argv) { |
+ |
+ if (isatty(2) && !getenv("AFL_QUIET")) { |
+ |
+ SAYF(cCYA "afl-cc " cBRI VERSION cRST " by <lcamtuf@google.com>\n"); |
+ |
+ } else be_quiet = 1; |
+ |
+ if (argc < 2) { |
+ |
+ SAYF("\n" |
+ "This is a helper application for afl-fuzz. It serves as a drop-in replacement\n" |
+ "for gcc or clang, letting you recompile third-party code with the required\n" |
+ "runtime instrumentation. A common use pattern would be one of the following:\n\n" |
+ |
+ " CC=%s/afl-gcc ./configure\n" |
+ " CXX=%s/afl-g++ ./configure\n\n" |
+ |
+ "You can specify custom next-stage toolchain via AFL_CC, AFL_CXX, and AFL_AS.\n" |
+ "Setting AFL_HARDEN enables hardening optimizations in the compiled code.\n\n", |
+ BIN_PATH, BIN_PATH); |
+ |
+ exit(1); |
+ |
+ } |
+ |
+ |
+ find_as(argv[0]); |
+ |
+ edit_params(argc, argv); |
+ |
+ execvp(cc_params[0], (char**)cc_params); |
+ |
+ FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); |
+ |
+ return 0; |
+ |
+} |