OLD | NEW |
(Empty) | |
| 1 /* |
| 2 american fuzzy lop - LLVM-mode wrapper for clang |
| 3 ------------------------------------------------ |
| 4 |
| 5 Written by Laszlo Szekeres <lszekeres@google.com> and |
| 6 Michal Zalewski <lcamtuf@google.com> |
| 7 |
| 8 LLVM integration design comes from Laszlo Szekeres. |
| 9 |
| 10 Copyright 2015, 2016 Google Inc. All rights reserved. |
| 11 |
| 12 Licensed under the Apache License, Version 2.0 (the "License"); |
| 13 you may not use this file except in compliance with the License. |
| 14 You may obtain a copy of the License at: |
| 15 |
| 16 http://www.apache.org/licenses/LICENSE-2.0 |
| 17 |
| 18 This program is a drop-in replacement for clang, similar in most respects |
| 19 to ../afl-gcc. It tries to figure out compilation mode, adds a bunch |
| 20 of flags, and then calls the real compiler. |
| 21 |
| 22 */ |
| 23 |
| 24 #define AFL_MAIN |
| 25 |
| 26 #include "../config.h" |
| 27 #include "../types.h" |
| 28 #include "../debug.h" |
| 29 #include "../alloc-inl.h" |
| 30 |
| 31 #include <stdio.h> |
| 32 #include <unistd.h> |
| 33 #include <stdlib.h> |
| 34 #include <string.h> |
| 35 |
| 36 static u8* obj_path; /* Path to runtime libraries */ |
| 37 static u8** cc_params; /* Parameters passed to the real CC */ |
| 38 static u32 cc_par_cnt = 1; /* Param count, including argv0 */ |
| 39 |
| 40 |
| 41 /* Try to find the runtime libraries. If that fails, abort. */ |
| 42 |
| 43 static void find_obj(u8* argv0) { |
| 44 |
| 45 u8 *afl_path = getenv("AFL_PATH"); |
| 46 u8 *slash, *tmp; |
| 47 |
| 48 if (afl_path) { |
| 49 |
| 50 tmp = alloc_printf("%s/afl-llvm-rt.o", afl_path); |
| 51 |
| 52 if (!access(tmp, R_OK)) { |
| 53 obj_path = afl_path; |
| 54 ck_free(tmp); |
| 55 return; |
| 56 } |
| 57 |
| 58 ck_free(tmp); |
| 59 |
| 60 } |
| 61 |
| 62 slash = strrchr(argv0, '/'); |
| 63 |
| 64 if (slash) { |
| 65 |
| 66 u8 *dir; |
| 67 |
| 68 *slash = 0; |
| 69 dir = ck_strdup(argv0); |
| 70 *slash = '/'; |
| 71 |
| 72 tmp = alloc_printf("%s/afl-llvm-rt.o", dir); |
| 73 |
| 74 if (!access(tmp, R_OK)) { |
| 75 obj_path = dir; |
| 76 ck_free(tmp); |
| 77 return; |
| 78 } |
| 79 |
| 80 ck_free(tmp); |
| 81 ck_free(dir); |
| 82 |
| 83 } |
| 84 |
| 85 if (!access(AFL_PATH "/afl-llvm-rt.o", R_OK)) { |
| 86 obj_path = AFL_PATH; |
| 87 return; |
| 88 } |
| 89 |
| 90 FATAL("Unable to find 'afl-llvm-rt.o' or 'afl-llvm-pass.so'. Please set AFL_PA
TH"); |
| 91 |
| 92 } |
| 93 |
| 94 |
| 95 /* Copy argv to cc_params, making the necessary edits. */ |
| 96 |
| 97 static void edit_params(u32 argc, char** argv) { |
| 98 |
| 99 u8 fortify_set = 0, asan_set = 0, x_set = 0, maybe_linking = 1, bit_mode = 0; |
| 100 u8 *name; |
| 101 |
| 102 cc_params = ck_alloc((argc + 64) * sizeof(u8*)); |
| 103 |
| 104 name = strrchr(argv[0], '/'); |
| 105 if (!name) name = argv[0]; else name++; |
| 106 |
| 107 if (!strcmp(name, "afl-clang-fast++")) { |
| 108 u8* alt_cxx = getenv("AFL_CXX"); |
| 109 cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++"; |
| 110 } else { |
| 111 u8* alt_cc = getenv("AFL_CC"); |
| 112 cc_params[0] = alt_cc ? alt_cc : (u8*)"clang"; |
| 113 } |
| 114 |
| 115 /* There are two ways to compile afl-clang-fast. In the traditional mode, we |
| 116 use afl-llvm-pass.so to inject instrumentation. In the experimental |
| 117 'trace-pc' mode, we use native LLVM instrumentation callbacks instead. |
| 118 The latter is a very recent addition - see: |
| 119 |
| 120 http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs */ |
| 121 |
| 122 #ifdef USE_TRACE_PC |
| 123 cc_params[cc_par_cnt++] = "-fsanitize-coverage=bb,trace-pc"; |
| 124 #else |
| 125 cc_params[cc_par_cnt++] = "-Xclang"; |
| 126 cc_params[cc_par_cnt++] = "-load"; |
| 127 cc_params[cc_par_cnt++] = "-Xclang"; |
| 128 cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); |
| 129 #endif /* ^USE_TRACE_PC */ |
| 130 |
| 131 cc_params[cc_par_cnt++] = "-Qunused-arguments"; |
| 132 |
| 133 while (--argc) { |
| 134 u8* cur = *(++argv); |
| 135 |
| 136 if (!strcmp(cur, "-m32")) bit_mode = 32; |
| 137 if (!strcmp(cur, "-m64")) bit_mode = 64; |
| 138 |
| 139 if (!strcmp(cur, "-x")) x_set = 1; |
| 140 |
| 141 if (!strcmp(cur, "-c") || !strcmp(cur, "-S") || !strcmp(cur, "-E") || |
| 142 !strcmp(cur, "-v")) maybe_linking = 0; |
| 143 |
| 144 if (!strcmp(cur, "-fsanitize=address") || |
| 145 !strcmp(cur, "-fsanitize=memory")) asan_set = 1; |
| 146 |
| 147 if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1; |
| 148 |
| 149 if (!strcmp(cur, "-shared")) maybe_linking = 0; |
| 150 |
| 151 cc_params[cc_par_cnt++] = cur; |
| 152 |
| 153 } |
| 154 |
| 155 if (getenv("AFL_HARDEN")) { |
| 156 |
| 157 cc_params[cc_par_cnt++] = "-fstack-protector-all"; |
| 158 |
| 159 if (!fortify_set) |
| 160 cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2"; |
| 161 |
| 162 } |
| 163 |
| 164 if (!asan_set) { |
| 165 |
| 166 if (getenv("AFL_USE_ASAN")) { |
| 167 |
| 168 cc_params[cc_par_cnt++] = "-fsanitize=address"; |
| 169 |
| 170 if (getenv("AFL_USE_MSAN")) |
| 171 FATAL("ASAN and MSAN are mutually exclusive"); |
| 172 |
| 173 } else if (getenv("AFL_USE_MSAN")) { |
| 174 |
| 175 cc_params[cc_par_cnt++] = "-fsanitize=memory"; |
| 176 |
| 177 if (getenv("AFL_USE_ASAN")) |
| 178 FATAL("ASAN and MSAN are mutually exclusive"); |
| 179 |
| 180 } |
| 181 |
| 182 } |
| 183 |
| 184 #ifdef USE_TRACE_PC |
| 185 |
| 186 if (getenv("AFL_INST_RATIO")) |
| 187 FATAL("AFL_INST_RATIO not available at compile time with 'trace-pc'."); |
| 188 |
| 189 #endif /* USE_TRACE_PC */ |
| 190 |
| 191 if (!getenv("AFL_DONT_OPTIMIZE")) { |
| 192 |
| 193 cc_params[cc_par_cnt++] = "-g"; |
| 194 cc_params[cc_par_cnt++] = "-O3"; |
| 195 cc_params[cc_par_cnt++] = "-funroll-loops"; |
| 196 |
| 197 } |
| 198 |
| 199 cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1"; |
| 200 cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1"; |
| 201 cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1"; |
| 202 |
| 203 /* When the user tries to use persistent or deferred forkserver modes by |
| 204 appending a single line to the program, we want to reliably inject a |
| 205 signature into the binary (to be picked up by afl-fuzz) and we want |
| 206 to call a function from the runtime .o file. This is unnecessarily |
| 207 painful for three reasons: |
| 208 |
| 209 1) We need to convince the compiler not to optimize out the signature. |
| 210 This is done with __attribute__((used)). |
| 211 |
| 212 2) We need to convince the linker, when called with -Wl,--gc-sections, |
| 213 not to do the same. This is done by forcing an assignment to a |
| 214 'volatile' pointer. |
| 215 |
| 216 3) We need to declare __afl_persistent_loop() in the global namespace, |
| 217 but doing this within a method in a class is hard - :: and extern "C" |
| 218 are forbidden and __attribute__((alias(...))) doesn't work. Hence the |
| 219 __asm__ aliasing trick. |
| 220 |
| 221 */ |
| 222 |
| 223 cc_params[cc_par_cnt++] = "-D__AFL_LOOP(_A)=" |
| 224 "({ static volatile char *_B __attribute__((used)); " |
| 225 " _B = (char*)\"" PERSIST_SIG "\"; " |
| 226 #ifdef __APPLE__ |
| 227 "__attribute__((visibility(\"default\"))) " |
| 228 "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); " |
| 229 #else |
| 230 "__attribute__((visibility(\"default\"))) " |
| 231 "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); " |
| 232 #endif /* ^__APPLE__ */ |
| 233 "_L(_A); })"; |
| 234 |
| 235 cc_params[cc_par_cnt++] = "-D__AFL_INIT()=" |
| 236 "do { static volatile char *_A __attribute__((used)); " |
| 237 " _A = (char*)\"" DEFER_SIG "\"; " |
| 238 #ifdef __APPLE__ |
| 239 "__attribute__((visibility(\"default\"))) " |
| 240 "void _I(void) __asm__(\"___afl_manual_init\"); " |
| 241 #else |
| 242 "__attribute__((visibility(\"default\"))) " |
| 243 "void _I(void) __asm__(\"__afl_manual_init\"); " |
| 244 #endif /* ^__APPLE__ */ |
| 245 "_I(); } while (0)"; |
| 246 |
| 247 if (maybe_linking) { |
| 248 |
| 249 if (x_set) { |
| 250 cc_params[cc_par_cnt++] = "-x"; |
| 251 cc_params[cc_par_cnt++] = "none"; |
| 252 } |
| 253 |
| 254 switch (bit_mode) { |
| 255 |
| 256 case 0: |
| 257 cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path); |
| 258 break; |
| 259 |
| 260 case 32: |
| 261 cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path); |
| 262 |
| 263 if (access(cc_params[cc_par_cnt - 1], R_OK)) |
| 264 FATAL("-m32 is not supported by your compiler"); |
| 265 |
| 266 break; |
| 267 |
| 268 case 64: |
| 269 cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path); |
| 270 |
| 271 if (access(cc_params[cc_par_cnt - 1], R_OK)) |
| 272 FATAL("-m64 is not supported by your compiler"); |
| 273 |
| 274 break; |
| 275 |
| 276 } |
| 277 |
| 278 } |
| 279 |
| 280 cc_params[cc_par_cnt] = NULL; |
| 281 |
| 282 } |
| 283 |
| 284 |
| 285 /* Main entry point */ |
| 286 |
| 287 int main(int argc, char** argv) { |
| 288 |
| 289 if (isatty(2) && !getenv("AFL_QUIET")) { |
| 290 |
| 291 SAYF(cCYA "afl-clang-fast " cBRI VERSION cRST " by <lszekeres@google.com>\n
"); |
| 292 |
| 293 } |
| 294 |
| 295 if (argc < 2) { |
| 296 |
| 297 SAYF("\n" |
| 298 "This is a helper application for afl-fuzz. It serves as a drop-in repl
acement\n" |
| 299 "for clang, letting you recompile third-party code with the required ru
ntime\n" |
| 300 "instrumentation. A common use pattern would be one of the following:\n
\n" |
| 301 |
| 302 " CC=%s/afl-clang-fast ./configure\n" |
| 303 " CXX=%s/afl-clang-fast++ ./configure\n\n" |
| 304 |
| 305 "In contrast to the traditional afl-clang tool, this version is impleme
nted as\n" |
| 306 "an LLVM pass and tends to offer improved performance with slow program
s.\n\n" |
| 307 |
| 308 "You can specify custom next-stage toolchain via AFL_CC and AFL_CXX. Se
tting\n" |
| 309 "AFL_HARDEN enables hardening optimizations in the compiled code.\n\n", |
| 310 BIN_PATH, BIN_PATH); |
| 311 |
| 312 exit(1); |
| 313 |
| 314 } |
| 315 |
| 316 |
| 317 find_obj(argv[0]); |
| 318 |
| 319 edit_params(argc, argv); |
| 320 |
| 321 execvp(cc_params[0], (char**)cc_params); |
| 322 |
| 323 FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]); |
| 324 |
| 325 return 0; |
| 326 |
| 327 } |
OLD | NEW |