OLD | NEW |
(Empty) | |
| 1 /* |
| 2 american fuzzy lop - wrapper for GCC and clang |
| 3 ---------------------------------------------- |
| 4 |
| 5 Written and maintained by Michal Zalewski <lcamtuf@google.com> |
| 6 |
| 7 Copyright 2013, 2014, 2015 Google Inc. All rights reserved. |
| 8 |
| 9 Licensed under the Apache License, Version 2.0 (the "License"); |
| 10 you may not use this file except in compliance with the License. |
| 11 You may obtain a copy of the License at: |
| 12 |
| 13 http://www.apache.org/licenses/LICENSE-2.0 |
| 14 |
| 15 This program is a drop-in replacement for GCC or clang. The most common way |
| 16 of using it is to pass the path to afl-gcc or afl-clang via CC when invoking |
| 17 ./configure. |
| 18 |
| 19 (Of course, use CXX and point it to afl-g++ / afl-clang++ for C++ code.) |
| 20 |
| 21 The wrapper needs to know the path to afl-as (renamed to 'as'). The default |
| 22 is /usr/local/lib/afl/. A convenient way to specify alternative directories |
| 23 would be to set AFL_PATH. |
| 24 |
| 25 If AFL_HARDEN is set, the wrapper will compile the target app with various |
| 26 hardening options that may help detect memory management issues more |
| 27 reliably. You can also specify AFL_USE_ASAN to enable ASAN. |
| 28 |
| 29 If you want to call a non-default compiler as a next step of the chain, |
| 30 specify its location via AFL_CC or AFL_CXX. |
| 31 |
| 32 */ |
| 33 |
| 34 #define AFL_MAIN |
| 35 |
| 36 #include "config.h" |
| 37 #include "types.h" |
| 38 #include "debug.h" |
| 39 #include "alloc-inl.h" |
| 40 |
| 41 #include <stdio.h> |
| 42 #include <unistd.h> |
| 43 #include <stdlib.h> |
| 44 #include <string.h> |
| 45 |
| 46 static u8* as_path; /* Path to the AFL 'as' wrapper */ |
| 47 static u8** cc_params; /* Parameters passed to the real CC */ |
| 48 static u32 cc_par_cnt = 1; /* Param count, including argv0 */ |
| 49 static u8 be_quiet, /* Quiet mode */ |
| 50 clang_mode; /* Invoked as afl-clang*? */ |
| 51 |
| 52 |
| 53 /* Try to find our "fake" GNU assembler in AFL_PATH or at the location derived |
| 54 from argv[0]. If that fails, abort. */ |
| 55 |
| 56 static void find_as(u8* argv0) { |
| 57 |
| 58 u8 *afl_path = getenv("AFL_PATH"); |
| 59 u8 *slash, *tmp; |
| 60 |
| 61 if (afl_path) { |
| 62 |
| 63 tmp = alloc_printf("%s/as", afl_path); |
| 64 |
| 65 if (!access(tmp, X_OK)) { |
| 66 as_path = afl_path; |
| 67 ck_free(tmp); |
| 68 return; |
| 69 } |
| 70 |
| 71 ck_free(tmp); |
| 72 |
| 73 } |
| 74 |
| 75 slash = strrchr(argv0, '/'); |
| 76 |
| 77 if (slash) { |
| 78 |
| 79 u8 *dir; |
| 80 |
| 81 *slash = 0; |
| 82 dir = ck_strdup(argv0); |
| 83 *slash = '/'; |
| 84 |
| 85 tmp = alloc_printf("%s/afl-as", dir); |
| 86 |
| 87 if (!access(tmp, X_OK)) { |
| 88 as_path = dir; |
| 89 ck_free(tmp); |
| 90 return; |
| 91 } |
| 92 |
| 93 ck_free(tmp); |
| 94 ck_free(dir); |
| 95 |
| 96 } |
| 97 |
| 98 if (!access(AFL_PATH "/as", X_OK)) { |
| 99 as_path = AFL_PATH; |
| 100 return; |
| 101 } |
| 102 |
| 103 FATAL("Unable to find AFL wrapper binary for 'as'. Please set AFL_PATH"); |
| 104 |
| 105 } |
| 106 |
| 107 |
| 108 /* Copy argv to cc_params, making the necessary edits. */ |
| 109 |
| 110 static void edit_params(u32 argc, char** argv) { |
| 111 |
| 112 u8 fortify_set = 0, asan_set = 0; |
| 113 u8 *name; |
| 114 |
| 115 #if defined(__FreeBSD__) && defined(__x86_64__) |
| 116 u8 m32_set = 0; |
| 117 #endif |
| 118 |
| 119 cc_params = ck_alloc((argc + 64) * sizeof(u8*)); |
| 120 |
| 121 name = strrchr(argv[0], '/'); |
| 122 if (!name) name = argv[0]; else name++; |
| 123 |
| 124 if (!strncmp(name, "afl-clang", 9)) { |
| 125 |
| 126 clang_mode = 1; |
| 127 |
| 128 setenv(CLANG_ENV_VAR, "1", 1); |
| 129 |
| 130 if (!strcmp(name, "afl-clang++")) { |
| 131 u8* alt_cxx = getenv("AFL_CXX"); |
| 132 cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; |
| 133 } else { |
| 134 u8* alt_cc = getenv("AFL_CC"); |
| 135 cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; |
| 136 } |
| 137 |
| 138 } else { |
| 139 |
| 140 /* With GCJ and Eclipse installed, you can actually compile Java! The |
| 141 instrumentation will work (amazingly). Alas, unhandled exceptions do |
| 142 not call abort(), so afl-fuzz would need to be modified to equate |
| 143 non-zero exit codes with crash conditions when working with Java |
| 144 binaries. Meh. */ |
| 145 |
| 146 #ifdef __APPLE__ |
| 147 |
| 148 if (!strcmp(name, "afl-g++")) cc_params[0] = getenv("AFL_CXX"); |
| 149 else if (!strcmp(name, "afl-gcj")) cc_params[0] = getenv("AFL_GCJ"); |
| 150 else cc_params[0] = getenv("AFL_CC"); |
| 151 |
| 152 if (!cc_params[0]) { |
| 153 |
| 154 SAYF("\n" cLRD "[-] " cRST |
| 155 "On Apple systems, 'gcc' is usually just a wrapper for clang. Please
use the\n" |
| 156 " 'afl-clang' utility instead of 'afl-gcc'. If you really have GCC
installed,\n" |
| 157 " set AFL_CC or AFL_CXX to specify the correct path to that compil
er.\n"); |
| 158 |
| 159 FATAL("AFL_CC or AFL_CXX required on MacOS X"); |
| 160 |
| 161 } |
| 162 |
| 163 #else |
| 164 |
| 165 if (!strcmp(name, "afl-g++")) { |
| 166 u8* alt_cxx = getenv("AFL_CXX"); |
| 167 cc_params[0] = alt_cxx ? alt_cxx : (u8*)"g++"; |
| 168 } else if (!strcmp(name, "afl-gcj")) { |
| 169 u8* alt_cc = getenv("AFL_GCJ"); |
| 170 cc_params[0] = alt_cc ? alt_cc : (u8*)"gcj"; |
| 171 } else { |
| 172 u8* alt_cc = getenv("AFL_CC"); |
| 173 cc_params[0] = alt_cc ? alt_cc : (u8*)"gcc"; |
| 174 } |
| 175 |
| 176 #endif /* __APPLE__ */ |
| 177 |
| 178 } |
| 179 |
| 180 while (--argc) { |
| 181 u8* cur = *(++argv); |
| 182 |
| 183 if (!strncmp(cur, "-B", 2)) { |
| 184 |
| 185 if (!be_quiet) WARNF("-B is already set, overriding"); |
| 186 |
| 187 if (!cur[2] && argc > 1) { argc--; argv++; } |
| 188 continue; |
| 189 |
| 190 } |
| 191 |
| 192 if (!strcmp(cur, "-integrated-as")) continue; |
| 193 |
| 194 if (!strcmp(cur, "-pipe")) continue; |
| 195 |
| 196 #if defined(__FreeBSD__) && defined(__x86_64__) |
| 197 if (!strcmp(cur, "-m32")) m32_set = 1; |
| 198 #endif |
| 199 |
| 200 if (!strcmp(cur, "-fsanitize=address") || |
| 201 !strcmp(cur, "-fsanitize=memory")) asan_set = 1; |
| 202 |
| 203 if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; |
| 204 |
| 205 cc_params[cc_par_cnt++] = cur; |
| 206 |
| 207 } |
| 208 |
| 209 cc_params[cc_par_cnt++] = "-B"; |
| 210 cc_params[cc_par_cnt++] = as_path; |
| 211 |
| 212 if (clang_mode) |
| 213 cc_params[cc_par_cnt++] = "-no-integrated-as"; |
| 214 |
| 215 if (getenv("AFL_HARDEN")) { |
| 216 |
| 217 cc_params[cc_par_cnt++] = "-fstack-protector-all"; |
| 218 |
| 219 if (!fortify_set) |
| 220 cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; |
| 221 |
| 222 } |
| 223 |
| 224 if (asan_set) { |
| 225 |
| 226 /* Pass this on to afl-as to adjust map density. */ |
| 227 |
| 228 setenv("AFL_USE_ASAN", "1", 1); |
| 229 |
| 230 } else if (getenv("AFL_USE_ASAN")) { |
| 231 |
| 232 cc_params[cc_par_cnt++] = "-fsanitize=address"; |
| 233 |
| 234 if (getenv("AFL_USE_MSAN")) |
| 235 FATAL("ASAN and MSAN are mutually exclusive"); |
| 236 |
| 237 } else if (getenv("AFL_USE_MSAN")) { |
| 238 |
| 239 cc_params[cc_par_cnt++] = "-fsanitize=memory"; |
| 240 |
| 241 if (getenv("AFL_USE_ASAN")) |
| 242 FATAL("ASAN and MSAN are mutually exclusive"); |
| 243 |
| 244 } |
| 245 |
| 246 if (!getenv("AFL_DONT_OPTIMIZE")) { |
| 247 |
| 248 #if defined(__FreeBSD__) && defined(__x86_64__) |
| 249 |
| 250 /* On 64-bit FreeBSD systems, clang -g -m32 is broken, but -m32 itself |
| 251 works OK. This has nothing to do with us, but let's avoid triggering |
| 252 that bug. */ |
| 253 |
| 254 if (!clang_mode || !m32_set) |
| 255 cc_params[cc_par_cnt++] = "-g"; |
| 256 |
| 257 #else |
| 258 |
| 259 cc_params[cc_par_cnt++] = "-g"; |
| 260 |
| 261 #endif |
| 262 |
| 263 cc_params[cc_par_cnt++] = "-O3"; |
| 264 cc_params[cc_par_cnt++] = "-funroll-loops"; |
| 265 |
| 266 /* Two indicators that you're building for fuzzing; one of them is |
| 267 AFL-specific, the other is shared with libfuzzer. */ |
| 268 |
| 269 cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; |
| 270 cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; |
| 271 |
| 272 } |
| 273 |
| 274 cc_params[cc_par_cnt] = NULL; |
| 275 |
| 276 } |
| 277 |
| 278 |
| 279 /* Main entry point */ |
| 280 |
| 281 int main(int argc, char** argv) { |
| 282 |
| 283 if (isatty(2) && !getenv("AFL_QUIET")) { |
| 284 |
| 285 SAYF(cCYA "afl-cc " cBRI VERSION cRST " by <lcamtuf@google.com>\n"); |
| 286 |
| 287 } else be_quiet = 1; |
| 288 |
| 289 if (argc < 2) { |
| 290 |
| 291 SAYF("\n" |
| 292 "This is a helper application for afl-fuzz. It serves as a drop-in repl
acement\n" |
| 293 "for gcc or clang, letting you recompile third-party code with the requ
ired\n" |
| 294 "runtime instrumentation. A common use pattern would be one of the foll
owing:\n\n" |
| 295 |
| 296 " CC=%s/afl-gcc ./configure\n" |
| 297 " CXX=%s/afl-g++ ./configure\n\n" |
| 298 |
| 299 "You can specify custom next-stage toolchain via AFL_CC, AFL_CXX, and A
FL_AS.\n" |
| 300 "Setting AFL_HARDEN enables hardening optimizations in the compiled cod
e.\n\n", |
| 301 BIN_PATH, BIN_PATH); |
| 302 |
| 303 exit(1); |
| 304 |
| 305 } |
| 306 |
| 307 |
| 308 find_as(argv[0]); |
| 309 |
| 310 edit_params(argc, argv); |
| 311 |
| 312 execvp(cc_params[0], (char**)cc_params); |
| 313 |
| 314 FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); |
| 315 |
| 316 return 0; |
| 317 |
| 318 } |
OLD | NEW |