1 /*
2 american fuzzy lop++ - compiler instrumentation wrapper
3 -------------------------------------------------------
4
5 Written by Michal Zalewski, Laszlo Szekeres and Marc Heuse
6
7 Copyright 2015, 2016 Google Inc. All rights reserved.
8 Copyright 2019-2024 AFLplusplus Project. All rights reserved.
9
10 Licensed under the Apache License, Version 2.0 (the "License");
11 you may not use this file except in compliance with the License.
12 You may obtain a copy of the License at:
13
14 https://www.apache.org/licenses/LICENSE-2.0
15
16 */
17
18 #define AFL_MAIN
19
20 #include "common.h"
21 #include "config.h"
22 #include "types.h"
23 #include "debug.h"
24 #include "alloc-inl.h"
25 #include "llvm-alternative-coverage.h"
26
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <limits.h>
33 #include <assert.h>
34 #include <ctype.h>
35 #include <sys/stat.h>
36
37 #if (LLVM_MAJOR - 0 == 0)
38 #undef LLVM_MAJOR
39 #endif
40 #if !defined(LLVM_MAJOR)
41 #define LLVM_MAJOR 0
42 #endif
43 #if (LLVM_MINOR - 0 == 0)
44 #undef LLVM_MINOR
45 #endif
46 #if !defined(LLVM_MINOR)
47 #define LLVM_MINOR 0
48 #endif
49
50 #ifndef MAX_PARAMS_NUM
51 #define MAX_PARAMS_NUM 2048
52 #endif
53
54 /** Global declarations -----BEGIN----- **/
55
56 typedef enum {
57
58 PARAM_MISS, // not matched
59 PARAM_SCAN, // scan only
60 PARAM_KEEP, // kept as-is
61 PARAM_DROP, // ignored
62
63 } param_st;
64
65 typedef enum {
66
67 INSTRUMENT_DEFAULT = 0,
68 INSTRUMENT_CLASSIC = 1,
69 INSTRUMENT_AFL = 1,
70 INSTRUMENT_PCGUARD = 2,
71 INSTRUMENT_CFG = 3,
72 INSTRUMENT_LTO = 4,
73 INSTRUMENT_LLVMNATIVE = 5,
74 INSTRUMENT_GCC = 6,
75 INSTRUMENT_CLANG = 7,
76 INSTRUMENT_OPT_CTX = 8,
77 INSTRUMENT_OPT_NGRAM = 16,
78 INSTRUMENT_OPT_CALLER = 32,
79 INSTRUMENT_OPT_CTX_K = 64,
80 INSTRUMENT_OPT_CODECOV = 128,
81
82 } instrument_mode_id;
83
84 typedef enum {
85
86 UNSET = 0,
87 LTO = 1,
88 LLVM = 2,
89 GCC_PLUGIN = 3,
90 GCC = 4,
91 CLANG = 5
92
93 } compiler_mode_id;
94
95 static u8 cwd[4096];
96
97 char instrument_mode_string[18][18] = {
98
99 "DEFAULT",
100 "CLASSIC",
101 "PCGUARD",
102 "CFG",
103 "LTO",
104 "PCGUARD-NATIVE",
105 "GCC",
106 "CLANG",
107 "CTX",
108 "CALLER",
109 "",
110 "",
111 "",
112 "",
113 "",
114 "",
115 "NGRAM",
116 ""
117
118 };
119
120 char compiler_mode_string[7][12] = {
121
122 "AUTOSELECT", "LLVM-LTO", "LLVM", "GCC_PLUGIN",
123 "GCC", "CLANG", ""
124
125 };
126
instrument_mode_2str(instrument_mode_id i)127 u8 *instrument_mode_2str(instrument_mode_id i) {
128
129 return instrument_mode_string[i];
130
131 }
132
compiler_mode_2str(compiler_mode_id i)133 u8 *compiler_mode_2str(compiler_mode_id i) {
134
135 return compiler_mode_string[i];
136
137 }
138
getthecwd()139 u8 *getthecwd() {
140
141 if (getcwd(cwd, sizeof(cwd)) == NULL) {
142
143 static u8 fail[] = "";
144 return fail;
145
146 }
147
148 return cwd;
149
150 }
151
152 typedef struct aflcc_state {
153
154 u8 **cc_params; /* Parameters passed to the real CC */
155 u32 cc_par_cnt; /* Param count, including argv0 */
156
157 u8 *argv0; /* Original argv0 (by strdup) */
158 u8 *callname; /* Executable file argv0 indicated */
159
160 u8 debug;
161
162 u8 compiler_mode, plusplus_mode, lto_mode;
163
164 u8 *lto_flag;
165
166 u8 instrument_mode, instrument_opt_mode, ngram_size, ctx_k;
167
168 u8 cmplog_mode;
169
170 u8 have_instr_env, have_gcc, have_clang, have_llvm, have_gcc_plugin, have_lto,
171 have_optimized_pcguard, have_instr_list;
172
173 u8 fortify_set, x_set, bit_mode, preprocessor_only, have_unroll, have_o,
174 have_pic, have_c, shared_linking, partial_linking, non_dash, have_fp,
175 have_flto, have_hidden, have_fortify, have_fcf, have_staticasan,
176 have_rust_asanrt, have_asan, have_msan, have_ubsan, have_lsan, have_tsan,
177 have_cfisan;
178
179 // u8 *march_opt;
180 u8 need_aflpplib;
181 int passthrough;
182
183 u8 use_stdin; /* dummy */
184 u8 *argvnull; /* dummy */
185
186 } aflcc_state_t;
187
188 void aflcc_state_init(aflcc_state_t *, u8 *argv0);
189
190 u8 *find_object(aflcc_state_t *, u8 *obj);
191
192 void find_built_deps(aflcc_state_t *);
193
194 /* Insert param into the new argv, raise error if MAX_PARAMS_NUM exceeded. */
insert_param(aflcc_state_t * aflcc,u8 * param)195 static inline void insert_param(aflcc_state_t *aflcc, u8 *param) {
196
197 if (unlikely(aflcc->cc_par_cnt + 1 >= MAX_PARAMS_NUM))
198 FATAL("Too many command line parameters, please increase MAX_PARAMS_NUM.");
199
200 aflcc->cc_params[aflcc->cc_par_cnt++] = param;
201
202 }
203
204 /*
205 Insert a param which contains path to the object file. It uses find_object to
206 get the path based on the name `obj`, and then uses a sprintf like method to
207 format it with `fmt`. If `fmt` is NULL, the inserted arg is same as the path.
208 If `msg` provided, it should be an error msg raised if the path can't be
209 found. `obj` must not be NULL.
210 */
insert_object(aflcc_state_t * aflcc,u8 * obj,u8 * fmt,u8 * msg)211 static inline void insert_object(aflcc_state_t *aflcc, u8 *obj, u8 *fmt,
212 u8 *msg) {
213
214 u8 *_obj_path = find_object(aflcc, obj);
215 if (!_obj_path) {
216
217 if (msg)
218 FATAL("%s", msg);
219 else
220 FATAL("Unable to find '%s'", obj);
221
222 } else {
223
224 if (fmt) {
225
226 u8 *_obj_path_fmt = alloc_printf(fmt, _obj_path);
227 ck_free(_obj_path);
228 aflcc->cc_params[aflcc->cc_par_cnt++] = _obj_path_fmt;
229
230 } else {
231
232 aflcc->cc_params[aflcc->cc_par_cnt++] = _obj_path;
233
234 }
235
236 }
237
238 }
239
240 /* Insert params into the new argv, make clang load the pass. */
load_llvm_pass(aflcc_state_t * aflcc,u8 * pass)241 static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
242
243 #if LLVM_MAJOR >= 11 /* use new pass manager */
244 #if LLVM_MAJOR < 16
245 insert_param(aflcc, "-fexperimental-new-pass-manager");
246 #endif
247 insert_object(aflcc, pass, "-fpass-plugin=%s", 0);
248 #else
249 insert_param(aflcc, "-Xclang");
250 insert_param(aflcc, "-load");
251 insert_param(aflcc, "-Xclang");
252 insert_object(aflcc, pass, 0, 0);
253 #endif
254
255 }
256
debugf_args(int argc,char ** argv)257 static inline void debugf_args(int argc, char **argv) {
258
259 DEBUGF("cd '%s';", getthecwd());
260 for (int i = 0; i < argc; i++)
261 SAYF(" '%s'", argv[i]);
262 SAYF("\n");
263 fflush(stdout);
264 fflush(stderr);
265
266 }
267
268 void compiler_mode_by_callname(aflcc_state_t *);
269 void compiler_mode_by_environ(aflcc_state_t *);
270 void compiler_mode_by_cmdline(aflcc_state_t *, int argc, char **argv);
271 void instrument_mode_by_environ(aflcc_state_t *);
272 void mode_final_checkout(aflcc_state_t *, int argc, char **argv);
273 void mode_notification(aflcc_state_t *);
274
275 void add_real_argv0(aflcc_state_t *);
276
277 void add_defs_common(aflcc_state_t *);
278 void add_defs_selective_instr(aflcc_state_t *);
279 void add_defs_persistent_mode(aflcc_state_t *);
280 void add_defs_fortify(aflcc_state_t *, u8);
281 void add_defs_lsan_ctrl(aflcc_state_t *);
282
283 param_st parse_fsanitize(aflcc_state_t *, u8 *, u8);
284 void add_sanitizers(aflcc_state_t *, char **envp);
285 void add_optimized_pcguard(aflcc_state_t *);
286 void add_native_pcguard(aflcc_state_t *);
287
288 void add_assembler(aflcc_state_t *);
289 void add_gcc_plugin(aflcc_state_t *);
290
291 param_st parse_misc_params(aflcc_state_t *, u8 *, u8);
292 void add_misc_params(aflcc_state_t *);
293
294 param_st parse_linking_params(aflcc_state_t *, u8 *, u8, u8 *skip_next,
295 char **argv);
296
297 void add_lto_linker(aflcc_state_t *);
298 void add_lto_passes(aflcc_state_t *);
299 void add_runtime(aflcc_state_t *);
300
301 /** Global declarations -----END----- **/
302
303 /*
304 Init global state struct. We also extract the callname,
305 check debug options and if in C++ mode here.
306 */
aflcc_state_init(aflcc_state_t * aflcc,u8 * argv0)307 void aflcc_state_init(aflcc_state_t *aflcc, u8 *argv0) {
308
309 // Default NULL/0 is a good start
310 memset(aflcc, 0, sizeof(aflcc_state_t));
311
312 aflcc->cc_params = ck_alloc(MAX_PARAMS_NUM * sizeof(u8 *));
313 aflcc->cc_par_cnt = 1;
314
315 aflcc->lto_flag = AFL_CLANG_FLTO;
316
317 // aflcc->march_opt = CFLAGS_OPT;
318
319 /* callname & if C++ mode */
320
321 aflcc->argv0 = ck_strdup(argv0);
322
323 char *cname = NULL;
324
325 if ((cname = strrchr(aflcc->argv0, '/')) != NULL) {
326
327 cname++;
328
329 } else {
330
331 cname = aflcc->argv0;
332
333 }
334
335 aflcc->callname = cname;
336
337 if (strlen(cname) > 2 && (strncmp(cname + strlen(cname) - 2, "++", 2) == 0 ||
338 strstr(cname, "-g++") != NULL)) {
339
340 aflcc->plusplus_mode = 1;
341
342 }
343
344 /* debug */
345
346 if (getenv("AFL_DEBUG")) {
347
348 aflcc->debug = 1;
349 if (strcmp(getenv("AFL_DEBUG"), "0") == 0) unsetenv("AFL_DEBUG");
350
351 } else if (getenv("AFL_QUIET")) {
352
353 be_quiet = 1;
354
355 }
356
357 if ((getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) && (!aflcc->debug)) {
358
359 be_quiet = 1;
360
361 }
362
363 }
364
365 /*
366 Try to find a specific runtime we need, in here:
367
368 1. firstly we check the $AFL_PATH environment variable location if set
369 2. next we check argv[0] if it has path information and use it
370 a) we also check ../lib/afl
371 3. if 2. failed we check /proc (only Linux, Android, NetBSD, DragonFly, and
372 FreeBSD with procfs)
373 a) and check here in ../lib/afl too
374 4. we look into the AFL_PATH define (usually /usr/local/lib/afl)
375 5. we finally try the current directory
376
377 if all these attempts fail - we return NULL and the caller has to decide
378 what to do. Otherwise the path to obj would be allocated and returned.
379 */
find_object(aflcc_state_t * aflcc,u8 * obj)380 u8 *find_object(aflcc_state_t *aflcc, u8 *obj) {
381
382 u8 *argv0 = aflcc->argv0;
383
384 u8 *afl_path = getenv("AFL_PATH");
385 u8 *slash = NULL, *tmp;
386
387 if (afl_path) {
388
389 tmp = alloc_printf("%s/%s", afl_path, obj);
390
391 if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
392
393 if (!access(tmp, R_OK)) { return tmp; }
394
395 ck_free(tmp);
396
397 }
398
399 if (argv0) {
400
401 slash = strrchr(argv0, '/');
402
403 if (slash) {
404
405 u8 *dir = ck_strdup(argv0);
406
407 slash = strrchr(dir, '/');
408 *slash = 0;
409
410 tmp = alloc_printf("%s/%s", dir, obj);
411
412 if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
413
414 if (!access(tmp, R_OK)) {
415
416 ck_free(dir);
417 return tmp;
418
419 }
420
421 ck_free(tmp);
422 tmp = alloc_printf("%s/../lib/afl/%s", dir, obj);
423
424 if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
425
426 if (!access(tmp, R_OK)) {
427
428 ck_free(dir);
429 return tmp;
430
431 }
432
433 ck_free(tmp);
434 ck_free(dir);
435
436 }
437
438 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__linux__) || \
439 defined(__ANDROID__) || defined(__NetBSD__)
440 #define HAS_PROC_FS 1
441 #endif
442 #ifdef HAS_PROC_FS
443 else {
444
445 char *procname = NULL;
446 #if defined(__FreeBSD__) || defined(__DragonFly__)
447 procname = "/proc/curproc/file";
448 #elif defined(__linux__) || defined(__ANDROID__)
449 procname = "/proc/self/exe";
450 #elif defined(__NetBSD__)
451 procname = "/proc/curproc/exe";
452 #endif
453 if (procname) {
454
455 char exepath[PATH_MAX];
456 ssize_t exepath_len = readlink(procname, exepath, sizeof(exepath));
457 if (exepath_len > 0 && exepath_len < PATH_MAX) {
458
459 exepath[exepath_len] = 0;
460 slash = strrchr(exepath, '/');
461
462 if (slash) {
463
464 *slash = 0;
465 tmp = alloc_printf("%s/%s", exepath, obj);
466
467 if (!access(tmp, R_OK)) { return tmp; }
468
469 ck_free(tmp);
470 tmp = alloc_printf("%s/../lib/afl/%s", exepath, obj);
471
472 if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
473
474 if (!access(tmp, R_OK)) { return tmp; }
475
476 ck_free(tmp);
477
478 }
479
480 }
481
482 }
483
484 }
485
486 #endif
487 #undef HAS_PROC_FS
488
489 }
490
491 tmp = alloc_printf("%s/%s", AFL_PATH, obj);
492
493 if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
494
495 if (!access(tmp, R_OK)) { return tmp; }
496
497 ck_free(tmp);
498 tmp = alloc_printf("./%s", obj);
499
500 if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
501
502 if (!access(tmp, R_OK)) { return tmp; }
503
504 ck_free(tmp);
505
506 if (aflcc->debug) DEBUGF("Trying ... giving up\n");
507
508 return NULL;
509
510 }
511
512 /*
513 Deduce some info about compiler toolchains in current system,
514 from the building results of AFL++
515 */
find_built_deps(aflcc_state_t * aflcc)516 void find_built_deps(aflcc_state_t *aflcc) {
517
518 char *ptr = NULL;
519
520 #if defined(__x86_64__)
521 if ((ptr = find_object(aflcc, "as")) != NULL) {
522
523 #ifndef __APPLE__
524 // on OSX clang masquerades as GCC
525 aflcc->have_gcc = 1;
526 #endif
527 aflcc->have_clang = 1;
528 ck_free(ptr);
529
530 }
531
532 #endif
533
534 if ((ptr = find_object(aflcc, "SanitizerCoveragePCGUARD.so")) != NULL) {
535
536 aflcc->have_optimized_pcguard = 1;
537 ck_free(ptr);
538
539 }
540
541 #if (LLVM_MAJOR >= 3)
542
543 if ((ptr = find_object(aflcc, "SanitizerCoverageLTO.so")) != NULL) {
544
545 aflcc->have_lto = 1;
546 ck_free(ptr);
547
548 }
549
550 if ((ptr = find_object(aflcc, "cmplog-routines-pass.so")) != NULL) {
551
552 aflcc->have_llvm = 1;
553 ck_free(ptr);
554
555 }
556
557 #endif
558
559 #ifdef __ANDROID__
560 aflcc->have_llvm = 1;
561 #endif
562
563 if ((ptr = find_object(aflcc, "afl-gcc-pass.so")) != NULL) {
564
565 aflcc->have_gcc_plugin = 1;
566 ck_free(ptr);
567
568 }
569
570 #if !defined(__ANDROID__) && !defined(ANDROID)
571 ptr = find_object(aflcc, "afl-compiler-rt.o");
572
573 if (!ptr) {
574
575 FATAL(
576 "Unable to find 'afl-compiler-rt.o'. Please set the AFL_PATH "
577 "environment variable.");
578
579 }
580
581 if (aflcc->debug) { DEBUGF("rt=%s\n", ptr); }
582
583 ck_free(ptr);
584 #endif
585
586 }
587
588 /** compiler_mode & instrument_mode selecting -----BEGIN----- **/
589
590 /* Select compiler_mode by callname, such as "afl-clang-fast", etc. */
compiler_mode_by_callname(aflcc_state_t * aflcc)591 void compiler_mode_by_callname(aflcc_state_t *aflcc) {
592
593 if (strncmp(aflcc->callname, "afl-clang-fast", 14) == 0) {
594
595 /* afl-clang-fast is always created there by makefile
596 just like afl-clang, burdened with special purposes:
597 - If llvm-config is not available (i.e. LLVM_MAJOR is 0),
598 or too old, it falls back to LLVM-NATIVE mode and let
599 the actual compiler complain if doesn't work.
600 - Otherwise try default llvm instruments except LTO.
601 */
602 #if (LLVM_MAJOR >= 3)
603 aflcc->compiler_mode = LLVM;
604 #else
605 aflcc->compiler_mode = CLANG;
606 #endif
607
608 } else
609
610 #if (LLVM_MAJOR >= 3)
611
612 if (strncmp(aflcc->callname, "afl-clang-lto", 13) == 0 ||
613
614 strncmp(aflcc->callname, "afl-lto", 7) == 0) {
615
616 aflcc->compiler_mode = LTO;
617
618 } else
619
620 #endif
621
622 if (strncmp(aflcc->callname, "afl-gcc-fast", 12) == 0 ||
623
624 strncmp(aflcc->callname, "afl-g++-fast", 12) == 0) {
625
626 aflcc->compiler_mode = GCC_PLUGIN;
627
628 } else if (strncmp(aflcc->callname, "afl-gcc", 7) == 0 ||
629
630 strncmp(aflcc->callname, "afl-g++", 7) == 0) {
631
632 aflcc->compiler_mode = GCC;
633
634 } else if (strcmp(aflcc->callname, "afl-clang") == 0 ||
635
636 strcmp(aflcc->callname, "afl-clang++") == 0) {
637
638 aflcc->compiler_mode = CLANG;
639
640 }
641
642 }
643
644 /*
645 Select compiler_mode by env AFL_CC_COMPILER. And passthrough mode can be
646 regarded as a special compiler_mode, so we check for it here, too.
647 */
compiler_mode_by_environ(aflcc_state_t * aflcc)648 void compiler_mode_by_environ(aflcc_state_t *aflcc) {
649
650 if (getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) {
651
652 aflcc->passthrough = 1;
653
654 }
655
656 char *ptr = getenv("AFL_CC_COMPILER");
657
658 if (!ptr) { return; }
659
660 if (aflcc->compiler_mode) {
661
662 if (!be_quiet) {
663
664 WARNF(
665 "\"AFL_CC_COMPILER\" is set but a specific compiler was already "
666 "selected by command line parameter or symlink, ignoring the "
667 "environment variable!");
668
669 }
670
671 } else {
672
673 if (strncasecmp(ptr, "LTO", 3) == 0) {
674
675 aflcc->compiler_mode = LTO;
676
677 } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
678
679 aflcc->compiler_mode = LLVM;
680
681 } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
682
683 strncasecmp(ptr, "GCC-P", 5) == 0 ||
684 strncasecmp(ptr, "GCCP", 4) == 0) {
685
686 aflcc->compiler_mode = GCC_PLUGIN;
687
688 } else if (strcasecmp(ptr, "GCC") == 0) {
689
690 aflcc->compiler_mode = GCC;
691
692 } else if (strcasecmp(ptr, "CLANG") == 0) {
693
694 aflcc->compiler_mode = CLANG;
695
696 } else
697
698 FATAL("Unknown AFL_CC_COMPILER mode: %s\n", ptr);
699
700 }
701
702 }
703
704 /*
705 Select compiler_mode by command line options --afl-...
706 If it can be inferred, instrument_mode would also be set.
707 This can supersedes previous result based on callname
708 or AFL_CC_COMPILER. And "--afl_noopt"/"--afl-noopt" will
709 be overwritten by "-g".
710 */
compiler_mode_by_cmdline(aflcc_state_t * aflcc,int argc,char ** argv)711 void compiler_mode_by_cmdline(aflcc_state_t *aflcc, int argc, char **argv) {
712
713 char *ptr = NULL;
714
715 for (int i = 1; i < argc; i++) {
716
717 if (strncmp(argv[i], "--afl", 5) == 0) {
718
719 if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) {
720
721 aflcc->passthrough = 1;
722 argv[i] = "-g"; // we have to overwrite it, -g is always good
723 continue;
724
725 }
726
727 if (aflcc->compiler_mode && !be_quiet) {
728
729 WARNF(
730 "--afl-... compiler mode supersedes the AFL_CC_COMPILER and "
731 "symlink compiler selection!");
732
733 }
734
735 ptr = argv[i];
736 ptr += 5;
737 while (*ptr == '-')
738 ptr++;
739
740 if (strncasecmp(ptr, "LTO", 3) == 0) {
741
742 aflcc->compiler_mode = LTO;
743
744 } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
745
746 aflcc->compiler_mode = LLVM;
747
748 } else if (strncasecmp(ptr, "PCGUARD", 7) == 0 ||
749
750 strncasecmp(ptr, "PC-GUARD", 8) == 0) {
751
752 aflcc->compiler_mode = LLVM;
753 aflcc->instrument_mode = INSTRUMENT_PCGUARD;
754
755 } else if (strcasecmp(ptr, "INSTRIM") == 0 ||
756
757 strcasecmp(ptr, "CFG") == 0) {
758
759 FATAL(
760 "InsTrim instrumentation was removed. Use a modern LLVM and "
761 "PCGUARD (default in afl-cc).\n");
762
763 } else if (strcasecmp(ptr, "AFL") == 0 ||
764
765 strcasecmp(ptr, "CLASSIC") == 0) {
766
767 aflcc->compiler_mode = LLVM;
768 aflcc->instrument_mode = INSTRUMENT_CLASSIC;
769
770 } else if (strcasecmp(ptr, "LLVMNATIVE") == 0 ||
771
772 strcasecmp(ptr, "NATIVE") == 0 ||
773 strcasecmp(ptr, "LLVM-NATIVE") == 0) {
774
775 aflcc->compiler_mode = LLVM;
776 aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
777
778 } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
779
780 strncasecmp(ptr, "GCC-P", 5) == 0 ||
781 strncasecmp(ptr, "GCCP", 4) == 0) {
782
783 aflcc->compiler_mode = GCC_PLUGIN;
784
785 } else if (strcasecmp(ptr, "GCC") == 0) {
786
787 aflcc->compiler_mode = GCC;
788
789 } else if (strncasecmp(ptr, "CLANG", 5) == 0) {
790
791 aflcc->compiler_mode = CLANG;
792
793 } else
794
795 FATAL("Unknown --afl-... compiler mode: %s\n", argv[i]);
796
797 }
798
799 }
800
801 }
802
803 /*
804 Select instrument_mode by those envs in old style:
805 - USE_TRACE_PC, AFL_USE_TRACE_PC, AFL_LLVM_USE_TRACE_PC, AFL_TRACE_PC
806 - AFL_LLVM_CALLER, AFL_LLVM_CTX, AFL_LLVM_CTX_K
807 - AFL_LLVM_NGRAM_SIZE
808 */
instrument_mode_old_environ(aflcc_state_t * aflcc)809 static void instrument_mode_old_environ(aflcc_state_t *aflcc) {
810
811 if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
812 getenv("INSTRIM_LIB")) {
813
814 FATAL(
815 "InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD "
816 "(default in afl-cc).\n");
817
818 }
819
820 if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
821 getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
822
823 if (aflcc->instrument_mode == 0)
824 aflcc->instrument_mode = INSTRUMENT_PCGUARD;
825 else if (aflcc->instrument_mode != INSTRUMENT_PCGUARD)
826 FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together");
827
828 }
829
830 if (getenv("AFL_LLVM_CTX")) aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX;
831 if (getenv("AFL_LLVM_CALLER"))
832 aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
833
834 if (getenv("AFL_LLVM_NGRAM_SIZE")) {
835
836 aflcc->instrument_opt_mode |= INSTRUMENT_OPT_NGRAM;
837 aflcc->ngram_size = atoi(getenv("AFL_LLVM_NGRAM_SIZE"));
838 if (aflcc->ngram_size < 2 || aflcc->ngram_size > NGRAM_SIZE_MAX)
839 FATAL(
840 "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
841 "(%u)",
842 NGRAM_SIZE_MAX);
843
844 }
845
846 if (getenv("AFL_LLVM_CTX_K")) {
847
848 aflcc->ctx_k = atoi(getenv("AFL_LLVM_CTX_K"));
849 if (aflcc->ctx_k < 1 || aflcc->ctx_k > CTX_MAX_K)
850 FATAL("K-CTX instrumentation mode must be between 1 and CTX_MAX_K (%u)",
851 CTX_MAX_K);
852 if (aflcc->ctx_k == 1) {
853
854 setenv("AFL_LLVM_CALLER", "1", 1);
855 unsetenv("AFL_LLVM_CTX_K");
856 aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
857
858 } else {
859
860 aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX_K;
861
862 }
863
864 }
865
866 }
867
868 /*
869 Select instrument_mode by env 'AFL_LLVM_INSTRUMENT'.
870 Previous compiler_mode will be superseded, if required by some
871 values of instrument_mode.
872 */
instrument_mode_new_environ(aflcc_state_t * aflcc)873 static void instrument_mode_new_environ(aflcc_state_t *aflcc) {
874
875 if (!getenv("AFL_LLVM_INSTRUMENT")) { return; }
876
877 u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
878
879 while (ptr2) {
880
881 if (strncasecmp(ptr2, "afl", strlen("afl")) == 0 ||
882 strncasecmp(ptr2, "classic", strlen("classic")) == 0) {
883
884 if (aflcc->instrument_mode == INSTRUMENT_LTO) {
885
886 aflcc->instrument_mode = INSTRUMENT_CLASSIC;
887 aflcc->lto_mode = 1;
888
889 } else if (!aflcc->instrument_mode ||
890
891 aflcc->instrument_mode == INSTRUMENT_AFL) {
892
893 aflcc->instrument_mode = INSTRUMENT_AFL;
894
895 } else {
896
897 FATAL("main instrumentation mode already set with %s",
898 instrument_mode_2str(aflcc->instrument_mode));
899
900 }
901
902 }
903
904 if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 ||
905 strncasecmp(ptr2, "pcguard", strlen("pcguard")) == 0) {
906
907 if (!aflcc->instrument_mode ||
908 aflcc->instrument_mode == INSTRUMENT_PCGUARD)
909
910 aflcc->instrument_mode = INSTRUMENT_PCGUARD;
911
912 else
913 FATAL("main instrumentation mode already set with %s",
914 instrument_mode_2str(aflcc->instrument_mode));
915
916 }
917
918 if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
919 strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0 ||
920 strncasecmp(ptr2, "native", strlen("native")) == 0) {
921
922 if (!aflcc->instrument_mode ||
923 aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE)
924
925 aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
926
927 else
928 FATAL("main instrumentation mode already set with %s",
929 instrument_mode_2str(aflcc->instrument_mode));
930
931 }
932
933 if (strncasecmp(ptr2, "llvmcodecov", strlen("llvmcodecov")) == 0 ||
934 strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) {
935
936 if (!aflcc->instrument_mode ||
937 aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE) {
938
939 aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
940 aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CODECOV;
941
942 } else {
943
944 FATAL("main instrumentation mode already set with %s",
945 instrument_mode_2str(aflcc->instrument_mode));
946
947 }
948
949 }
950
951 if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
952 strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
953
954 FATAL(
955 "InsTrim instrumentation was removed. Use a modern LLVM and "
956 "PCGUARD (default in afl-cc).\n");
957
958 }
959
960 if (strncasecmp(ptr2, "lto", strlen("lto")) == 0) {
961
962 aflcc->lto_mode = 1;
963 if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_LTO)
964
965 aflcc->instrument_mode = INSTRUMENT_LTO;
966
967 else
968 FATAL("main instrumentation mode already set with %s",
969 instrument_mode_2str(aflcc->instrument_mode));
970
971 }
972
973 if (strcasecmp(ptr2, "gcc") == 0) {
974
975 if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_GCC)
976
977 aflcc->instrument_mode = INSTRUMENT_GCC;
978
979 else if (aflcc->instrument_mode != INSTRUMENT_GCC)
980 FATAL("main instrumentation mode already set with %s",
981 instrument_mode_2str(aflcc->instrument_mode));
982
983 aflcc->compiler_mode = GCC;
984
985 }
986
987 if (strcasecmp(ptr2, "clang") == 0) {
988
989 if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_CLANG)
990
991 aflcc->instrument_mode = INSTRUMENT_CLANG;
992
993 else if (aflcc->instrument_mode != INSTRUMENT_CLANG)
994 FATAL("main instrumentation mode already set with %s",
995 instrument_mode_2str(aflcc->instrument_mode));
996
997 aflcc->compiler_mode = CLANG;
998
999 }
1000
1001 if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0 ||
1002 strncasecmp(ptr2, "kctx-", strlen("c-ctx-")) == 0 ||
1003 strncasecmp(ptr2, "k-ctx-", strlen("k-ctx-")) == 0) {
1004
1005 u8 *ptr3 = ptr2;
1006 while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
1007 ptr3++;
1008
1009 if (!*ptr3) {
1010
1011 if ((ptr3 = getenv("AFL_LLVM_CTX_K")) == NULL)
1012 FATAL(
1013 "you must set the K-CTX K with (e.g. for value 2) "
1014 "AFL_LLVM_INSTRUMENT=ctx-2");
1015
1016 }
1017
1018 aflcc->ctx_k = atoi(ptr3);
1019 if (aflcc->ctx_k < 1 || aflcc->ctx_k > CTX_MAX_K)
1020 FATAL(
1021 "K-CTX instrumentation option must be between 1 and CTX_MAX_K "
1022 "(%u)",
1023 CTX_MAX_K);
1024
1025 if (aflcc->ctx_k == 1) {
1026
1027 aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
1028 setenv("AFL_LLVM_CALLER", "1", 1);
1029 unsetenv("AFL_LLVM_CTX_K");
1030
1031 } else {
1032
1033 aflcc->instrument_opt_mode |= (INSTRUMENT_OPT_CTX_K);
1034 u8 *ptr4 = alloc_printf("%u", aflcc->ctx_k);
1035 setenv("AFL_LLVM_CTX_K", ptr4, 1);
1036
1037 }
1038
1039 }
1040
1041 if (strcasecmp(ptr2, "ctx") == 0) {
1042
1043 aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX;
1044 setenv("AFL_LLVM_CTX", "1", 1);
1045
1046 }
1047
1048 if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) {
1049
1050 aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
1051 setenv("AFL_LLVM_CALLER", "1", 1);
1052
1053 }
1054
1055 if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) {
1056
1057 u8 *ptr3 = ptr2 + strlen("ngram");
1058 while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9')) {
1059
1060 ptr3++;
1061
1062 }
1063
1064 if (!*ptr3) {
1065
1066 if ((ptr3 = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL)
1067 FATAL(
1068 "you must set the NGRAM size with (e.g. for value 2) "
1069 "AFL_LLVM_INSTRUMENT=ngram-2");
1070
1071 }
1072
1073 aflcc->ngram_size = atoi(ptr3);
1074
1075 if (aflcc->ngram_size < 2 || aflcc->ngram_size > NGRAM_SIZE_MAX) {
1076
1077 FATAL(
1078 "NGRAM instrumentation option must be between 2 and "
1079 "NGRAM_SIZE_MAX (%u)",
1080 NGRAM_SIZE_MAX);
1081
1082 }
1083
1084 aflcc->instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM);
1085 u8 *ptr4 = alloc_printf("%u", aflcc->ngram_size);
1086 setenv("AFL_LLVM_NGRAM_SIZE", ptr4, 1);
1087
1088 }
1089
1090 ptr2 = strtok(NULL, ":,;");
1091
1092 }
1093
1094 }
1095
1096 /*
1097 Select instrument_mode by envs, the top wrapper. We check
1098 have_instr_env firstly, then call instrument_mode_old_environ
1099 and instrument_mode_new_environ sequentially.
1100 */
instrument_mode_by_environ(aflcc_state_t * aflcc)1101 void instrument_mode_by_environ(aflcc_state_t *aflcc) {
1102
1103 if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST") ||
1104 getenv("AFL_LLVM_ALLOWLIST") || getenv("AFL_LLVM_DENYLIST") ||
1105 getenv("AFL_LLVM_BLOCKLIST")) {
1106
1107 aflcc->have_instr_env = 1;
1108
1109 }
1110
1111 if (aflcc->have_instr_env && getenv("AFL_DONT_OPTIMIZE") && !be_quiet) {
1112
1113 WARNF(
1114 "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
1115 "for file matching, only function matching!");
1116
1117 }
1118
1119 instrument_mode_old_environ(aflcc);
1120 instrument_mode_new_environ(aflcc);
1121
1122 }
1123
1124 /*
1125 Workaround to ensure CALLER, CTX, K-CTX and NGRAM
1126 instrumentation were used correctly.
1127 */
instrument_opt_mode_exclude(aflcc_state_t * aflcc)1128 static void instrument_opt_mode_exclude(aflcc_state_t *aflcc) {
1129
1130 if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
1131 (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER)) {
1132
1133 FATAL("you cannot set CTX and CALLER together");
1134
1135 }
1136
1137 if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
1138 (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
1139
1140 FATAL("you cannot set CTX and K-CTX together");
1141
1142 }
1143
1144 if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
1145 (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
1146
1147 FATAL("you cannot set CALLER and K-CTX together");
1148
1149 }
1150
1151 if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM)
1152 FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode");
1153
1154 if (aflcc->instrument_opt_mode &&
1155 aflcc->instrument_opt_mode != INSTRUMENT_OPT_CODECOV &&
1156 aflcc->instrument_mode != INSTRUMENT_CLASSIC)
1157 FATAL(
1158 "CALLER, CTX and NGRAM instrumentation options can only be used with "
1159 "the LLVM CLASSIC instrumentation mode.");
1160
1161 }
1162
1163 /*
1164 Last step of compiler_mode & instrument_mode selecting.
1165 We have a few of workarounds here, to check any corner cases,
1166 prepare for a series of fallbacks, and raise warnings or errors.
1167 */
mode_final_checkout(aflcc_state_t * aflcc,int argc,char ** argv)1168 void mode_final_checkout(aflcc_state_t *aflcc, int argc, char **argv) {
1169
1170 if (aflcc->instrument_opt_mode &&
1171 aflcc->instrument_mode == INSTRUMENT_DEFAULT &&
1172 (aflcc->compiler_mode == LLVM || aflcc->compiler_mode == UNSET)) {
1173
1174 aflcc->instrument_mode = INSTRUMENT_CLASSIC;
1175 aflcc->compiler_mode = LLVM;
1176
1177 }
1178
1179 if (!aflcc->compiler_mode) {
1180
1181 // lto is not a default because outside of afl-cc RANLIB and AR have to
1182 // be set to LLVM versions so this would work
1183 if (aflcc->have_llvm)
1184 aflcc->compiler_mode = LLVM;
1185 else if (aflcc->have_gcc_plugin)
1186 aflcc->compiler_mode = GCC_PLUGIN;
1187 else if (aflcc->have_gcc)
1188 aflcc->compiler_mode = GCC;
1189 else if (aflcc->have_clang)
1190 aflcc->compiler_mode = CLANG;
1191 else if (aflcc->have_lto)
1192 aflcc->compiler_mode = LTO;
1193 else
1194 FATAL("no compiler mode available");
1195
1196 }
1197
1198 switch (aflcc->compiler_mode) {
1199
1200 case GCC:
1201 if (!aflcc->have_gcc) FATAL("afl-gcc is not available on your platform!");
1202 break;
1203 case CLANG:
1204 if (!aflcc->have_clang)
1205 FATAL("afl-clang is not available on your platform!");
1206 break;
1207 case LLVM:
1208 if (!aflcc->have_llvm)
1209 FATAL(
1210 "LLVM mode is not available, please install LLVM 13+ and recompile "
1211 "AFL++");
1212 break;
1213 case GCC_PLUGIN:
1214 if (!aflcc->have_gcc_plugin)
1215 FATAL(
1216 "GCC_PLUGIN mode is not available, install gcc plugin support and "
1217 "recompile AFL++");
1218 break;
1219 case LTO:
1220 if (!aflcc->have_lto)
1221 FATAL(
1222 "LTO mode is not available, please install LLVM 13+ and lld of the "
1223 "same version and recompile AFL++");
1224 break;
1225 default:
1226 FATAL("no compiler mode available");
1227
1228 }
1229
1230 if (aflcc->compiler_mode == GCC) { aflcc->instrument_mode = INSTRUMENT_GCC; }
1231
1232 if (aflcc->compiler_mode == CLANG) {
1233
1234 /* if our PCGUARD implementation is not available then silently switch to
1235 native LLVM PCGUARD. Or classic asm instrument is explicitly preferred. */
1236 if (!aflcc->have_optimized_pcguard &&
1237 (aflcc->instrument_mode == INSTRUMENT_DEFAULT ||
1238 aflcc->instrument_mode == INSTRUMENT_PCGUARD)) {
1239
1240 aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
1241
1242 } else {
1243
1244 aflcc->instrument_mode = INSTRUMENT_CLANG;
1245 setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as
1246
1247 }
1248
1249 }
1250
1251 if (aflcc->compiler_mode == LTO) {
1252
1253 if (aflcc->instrument_mode == 0 ||
1254 aflcc->instrument_mode == INSTRUMENT_LTO ||
1255 aflcc->instrument_mode == INSTRUMENT_CFG ||
1256 aflcc->instrument_mode == INSTRUMENT_PCGUARD) {
1257
1258 aflcc->lto_mode = 1;
1259 // force CFG
1260 // if (!aflcc->instrument_mode) {
1261
1262 aflcc->instrument_mode = INSTRUMENT_PCGUARD;
1263
1264 // }
1265
1266 } else if (aflcc->instrument_mode == INSTRUMENT_CLASSIC) {
1267
1268 aflcc->lto_mode = 1;
1269
1270 } else {
1271
1272 if (!be_quiet) {
1273
1274 WARNF("afl-clang-lto called with mode %s, using that mode instead",
1275 instrument_mode_2str(aflcc->instrument_mode));
1276
1277 }
1278
1279 }
1280
1281 }
1282
1283 if (aflcc->instrument_mode == 0 && aflcc->compiler_mode < GCC_PLUGIN) {
1284
1285 #if LLVM_MAJOR >= 7
1286 #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
1287 if (aflcc->have_instr_env) {
1288
1289 aflcc->instrument_mode = INSTRUMENT_AFL;
1290 if (!be_quiet) {
1291
1292 WARNF(
1293 "Switching to classic instrumentation because "
1294 "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD < 10.0.1.");
1295
1296 }
1297
1298 } else
1299
1300 #endif
1301 aflcc->instrument_mode = INSTRUMENT_PCGUARD;
1302
1303 #else
1304 aflcc->instrument_mode = INSTRUMENT_AFL;
1305 #endif
1306
1307 }
1308
1309 if (!aflcc->instrument_opt_mode && aflcc->lto_mode &&
1310 aflcc->instrument_mode == INSTRUMENT_CFG) {
1311
1312 aflcc->instrument_mode = INSTRUMENT_PCGUARD;
1313
1314 }
1315
1316 #ifndef AFL_CLANG_FLTO
1317 if (aflcc->lto_mode)
1318 FATAL(
1319 "instrumentation mode LTO specified but LLVM support not available "
1320 "(requires LLVM 11 or higher)");
1321 #endif
1322
1323 if (aflcc->lto_mode) {
1324
1325 if (aflcc->lto_flag[0] != '-')
1326 FATAL(
1327 "Using afl-clang-lto is not possible because Makefile magic did not "
1328 "identify the correct -flto flag");
1329 else
1330 aflcc->compiler_mode = LTO;
1331
1332 }
1333
1334 if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO"))
1335 FATAL(
1336 "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set "
1337 "together");
1338
1339 #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
1340
1341 if (aflcc->instrument_mode == INSTRUMENT_PCGUARD && aflcc->have_instr_env) {
1342
1343 FATAL(
1344 "Instrumentation type PCGUARD does not support "
1345 "AFL_LLVM_ALLOWLIST/DENYLIST! Use LLVM 10.0.1+ instead.");
1346
1347 }
1348
1349 #endif
1350
1351 instrument_opt_mode_exclude(aflcc);
1352
1353 u8 *ptr2;
1354
1355 if ((ptr2 = getenv("AFL_LLVM_DICT2FILE")) != NULL && *ptr2 != '/')
1356 FATAL("AFL_LLVM_DICT2FILE must be set to an absolute file path");
1357
1358 if (getenv("AFL_LLVM_LAF_ALL")) {
1359
1360 setenv("AFL_LLVM_LAF_SPLIT_SWITCHES", "1", 1);
1361 setenv("AFL_LLVM_LAF_SPLIT_COMPARES", "1", 1);
1362 setenv("AFL_LLVM_LAF_SPLIT_FLOATS", "1", 1);
1363 setenv("AFL_LLVM_LAF_TRANSFORM_COMPARES", "1", 1);
1364
1365 }
1366
1367 aflcc->cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG") ||
1368 getenv("AFL_GCC_CMPLOG");
1369
1370 }
1371
1372 /*
1373 Print welcome message on screen, giving brief notes about
1374 compiler_mode and instrument_mode.
1375 */
mode_notification(aflcc_state_t * aflcc)1376 void mode_notification(aflcc_state_t *aflcc) {
1377
1378 char *ptr2 = alloc_printf(" + NGRAM-%u", aflcc->ngram_size);
1379 char *ptr3 = alloc_printf(" + K-CTX-%u", aflcc->ctx_k);
1380
1381 char *ptr1 = alloc_printf(
1382 "%s%s%s%s%s", instrument_mode_2str(aflcc->instrument_mode),
1383 (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) ? " + CTX" : "",
1384 (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) ? " + CALLER" : "",
1385 (aflcc->instrument_opt_mode & INSTRUMENT_OPT_NGRAM) ? ptr2 : "",
1386 (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K) ? ptr3 : "");
1387
1388 ck_free(ptr2);
1389 ck_free(ptr3);
1390
1391 if ((isatty(2) && !be_quiet) || aflcc->debug) {
1392
1393 SAYF(cCYA
1394 "afl-cc" VERSION cRST
1395 " by Michal Zalewski, Laszlo Szekeres, Marc Heuse - mode: %s-%s\n",
1396 compiler_mode_2str(aflcc->compiler_mode), ptr1);
1397
1398 }
1399
1400 ck_free(ptr1);
1401
1402 if (!be_quiet &&
1403 (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG)) {
1404
1405 WARNF(
1406 "You are using outdated instrumentation, install LLVM and/or "
1407 "gcc-plugin and use afl-clang-fast/afl-clang-lto/afl-gcc-fast "
1408 "instead!");
1409
1410 }
1411
1412 }
1413
1414 /*
1415 Set argv[0] required by execvp. It can be
1416 - specified by env AFL_CXX
1417 - g++ or clang++
1418 - CLANGPP_BIN or LLVM_BINDIR/clang++
1419 when in C++ mode, or
1420 - specified by env AFL_CC
1421 - gcc or clang
1422 - CLANG_BIN or LLVM_BINDIR/clang
1423 otherwise.
1424 */
add_real_argv0(aflcc_state_t * aflcc)1425 void add_real_argv0(aflcc_state_t *aflcc) {
1426
1427 static u8 llvm_fullpath[PATH_MAX];
1428
1429 if (aflcc->plusplus_mode) {
1430
1431 u8 *alt_cxx = getenv("AFL_CXX");
1432
1433 if (!alt_cxx) {
1434
1435 if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == GCC_PLUGIN) {
1436
1437 alt_cxx = "g++";
1438
1439 } else if (aflcc->compiler_mode == CLANG) {
1440
1441 alt_cxx = "clang++";
1442
1443 } else {
1444
1445 if (USE_BINDIR)
1446 snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++",
1447 LLVM_BINDIR);
1448 else
1449 snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANGPP_BIN);
1450 alt_cxx = llvm_fullpath;
1451
1452 }
1453
1454 }
1455
1456 aflcc->cc_params[0] = alt_cxx;
1457
1458 } else {
1459
1460 u8 *alt_cc = getenv("AFL_CC");
1461
1462 if (!alt_cc) {
1463
1464 if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == GCC_PLUGIN) {
1465
1466 alt_cc = "gcc";
1467
1468 } else if (aflcc->compiler_mode == CLANG) {
1469
1470 alt_cc = "clang";
1471
1472 } else {
1473
1474 if (USE_BINDIR)
1475 snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang",
1476 LLVM_BINDIR);
1477 else
1478 snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANG_BIN);
1479 alt_cc = llvm_fullpath;
1480
1481 }
1482
1483 }
1484
1485 aflcc->cc_params[0] = alt_cc;
1486
1487 }
1488
1489 }
1490
1491 /** compiler_mode & instrument_mode selecting -----END----- **/
1492
1493 /** Macro defs for the preprocessor -----BEGIN----- **/
1494
add_defs_common(aflcc_state_t * aflcc)1495 void add_defs_common(aflcc_state_t *aflcc) {
1496
1497 insert_param(aflcc, "-D__AFL_COMPILER=1");
1498 insert_param(aflcc, "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1");
1499
1500 }
1501
1502 /*
1503 __afl_coverage macro defs. See
1504 instrumentation/README.instrument_list.md#
1505 2-selective-instrumentation-with-_afl_coverage-directives
1506 */
add_defs_selective_instr(aflcc_state_t * aflcc)1507 void add_defs_selective_instr(aflcc_state_t *aflcc) {
1508
1509 if (aflcc->plusplus_mode) {
1510
1511 insert_param(aflcc,
1512 "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;"
1513 "extern \"C\" void __afl_coverage_discard();"
1514 "extern \"C\" void __afl_coverage_skip();"
1515 "extern \"C\" void __afl_coverage_on();"
1516 "extern \"C\" void __afl_coverage_off();");
1517
1518 } else {
1519
1520 insert_param(aflcc,
1521 "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;"
1522 "void __afl_coverage_discard();"
1523 "void __afl_coverage_skip();"
1524 "void __afl_coverage_on();"
1525 "void __afl_coverage_off();");
1526
1527 }
1528
1529 insert_param(
1530 aflcc,
1531 "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = "
1532 "1;");
1533 insert_param(aflcc, "-D__AFL_COVERAGE_ON()=__afl_coverage_on()");
1534 insert_param(aflcc, "-D__AFL_COVERAGE_OFF()=__afl_coverage_off()");
1535 insert_param(aflcc, "-D__AFL_COVERAGE_DISCARD()=__afl_coverage_discard()");
1536 insert_param(aflcc, "-D__AFL_COVERAGE_SKIP()=__afl_coverage_skip()");
1537
1538 }
1539
1540 /*
1541 Macro defs for persistent mode. As documented in
1542 instrumentation/README.persistent_mode.md, deferred forkserver initialization
1543 and persistent mode are not available in afl-gcc and afl-clang.
1544 */
add_defs_persistent_mode(aflcc_state_t * aflcc)1545 void add_defs_persistent_mode(aflcc_state_t *aflcc) {
1546
1547 if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG) return;
1548
1549 insert_param(aflcc, "-D__AFL_HAVE_MANUAL_CONTROL=1");
1550
1551 /* When the user tries to use persistent or deferred forkserver modes by
1552 appending a single line to the program, we want to reliably inject a
1553 signature into the binary (to be picked up by afl-fuzz) and we want
1554 to call a function from the runtime .o file. This is unnecessarily
1555 painful for three reasons:
1556
1557 1) We need to convince the compiler not to optimize out the signature.
1558 This is done with __attribute__((used)).
1559
1560 2) We need to convince the linker, when called with -Wl,--gc-sections,
1561 not to do the same. This is done by forcing an assignment to a
1562 'volatile' pointer.
1563
1564 3) We need to declare __afl_persistent_loop() in the global namespace,
1565 but doing this within a method in a class is hard - :: and extern "C"
1566 are forbidden and __attribute__((alias(...))) doesn't work. Hence the
1567 __asm__ aliasing trick.
1568
1569 */
1570
1571 insert_param(aflcc,
1572 "-D__AFL_FUZZ_INIT()="
1573 "int __afl_sharedmem_fuzzing = 1;"
1574 "extern unsigned int *__afl_fuzz_len;"
1575 "extern unsigned char *__afl_fuzz_ptr;"
1576 "unsigned char __afl_fuzz_alt[1048576];"
1577 "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;");
1578
1579 insert_param(aflcc,
1580 "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : "
1581 "__afl_fuzz_alt_ptr)");
1582
1583 insert_param(
1584 aflcc,
1585 "-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : "
1586 "(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff "
1587 "? 0 : *__afl_fuzz_len)");
1588
1589 insert_param(
1590 aflcc,
1591 "-D__AFL_LOOP(_A)="
1592 "({ static volatile const char *_B __attribute__((used,unused)); "
1593 " _B = (const char*)\"" PERSIST_SIG
1594 "\"; "
1595 "extern __attribute__((visibility(\"default\"))) int __afl_connected;"
1596 #ifdef __APPLE__
1597 "__attribute__((visibility(\"default\"))) "
1598 "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
1599 #else
1600 "__attribute__((visibility(\"default\"))) "
1601 "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
1602 #endif /* ^__APPLE__ */
1603 // if afl is connected, we run _A times, else once.
1604 "_L(__afl_connected ? _A : 1); })");
1605
1606 insert_param(
1607 aflcc,
1608 "-D__AFL_INIT()="
1609 "do { static volatile const char *_A __attribute__((used,unused)); "
1610 " _A = (const char*)\"" DEFER_SIG
1611 "\"; "
1612 #ifdef __APPLE__
1613 "__attribute__((visibility(\"default\"))) "
1614 "void _I(void) __asm__(\"___afl_manual_init\"); "
1615 #else
1616 "__attribute__((visibility(\"default\"))) "
1617 "void _I(void) __asm__(\"__afl_manual_init\"); "
1618 #endif /* ^__APPLE__ */
1619 "_I(); } while (0)");
1620
1621 }
1622
1623 /*
1624 Control macro def of _FORTIFY_SOURCE. It will do nothing
1625 if we detect this routine has been called previously, or
1626 the macro already here in these existing args.
1627 */
add_defs_fortify(aflcc_state_t * aflcc,u8 action)1628 void add_defs_fortify(aflcc_state_t *aflcc, u8 action) {
1629
1630 if (aflcc->have_fortify) { return; }
1631
1632 switch (action) {
1633
1634 case 1:
1635 insert_param(aflcc, "-D_FORTIFY_SOURCE=1");
1636 break;
1637
1638 case 2:
1639 insert_param(aflcc, "-D_FORTIFY_SOURCE=2");
1640 break;
1641
1642 default: // OFF
1643 insert_param(aflcc, "-U_FORTIFY_SOURCE");
1644 break;
1645
1646 }
1647
1648 aflcc->have_fortify = 1;
1649
1650 }
1651
1652 /* Macro defs of __AFL_LEAK_CHECK, __AFL_LSAN_ON and __AFL_LSAN_OFF */
add_defs_lsan_ctrl(aflcc_state_t * aflcc)1653 void add_defs_lsan_ctrl(aflcc_state_t *aflcc) {
1654
1655 insert_param(aflcc, "-includesanitizer/lsan_interface.h");
1656 insert_param(
1657 aflcc,
1658 "-D__AFL_LEAK_CHECK()={if(__lsan_do_recoverable_leak_check() > 0) "
1659 "_exit(23); }");
1660 insert_param(aflcc, "-D__AFL_LSAN_OFF()=__lsan_disable();");
1661 insert_param(aflcc, "-D__AFL_LSAN_ON()=__lsan_enable();");
1662
1663 }
1664
1665 /** Macro defs for the preprocessor -----END----- **/
1666
1667 /** About -fsanitize -----BEGIN----- **/
1668
1669 /* For input "-fsanitize=...", it:
1670
1671 1. may have various OOB traps :) if ... doesn't contain ',' or
1672 the input has bad syntax such as "-fsantiz=,"
1673 2. strips any fuzzer* in ... and writes back (may result in "-fsanitize=")
1674 3. rets 1 if exactly "fuzzer" found, otherwise rets 0
1675 */
fsanitize_fuzzer_comma(char * string)1676 static u8 fsanitize_fuzzer_comma(char *string) {
1677
1678 u8 detect_single_fuzzer = 0;
1679
1680 char *p, *ptr = string + strlen("-fsanitize=");
1681 // ck_alloc will check alloc failure
1682 char *new = ck_alloc(strlen(string) + 1);
1683 char *tmp = ck_alloc(strlen(ptr) + 1);
1684 u32 count = 0, len, ende = 0;
1685
1686 strcpy(new, "-fsanitize=");
1687
1688 do {
1689
1690 p = strchr(ptr, ',');
1691 if (!p) {
1692
1693 p = ptr + strlen(ptr) + 1;
1694 ende = 1;
1695
1696 }
1697
1698 len = p - ptr;
1699 if (len) {
1700
1701 strncpy(tmp, ptr, len);
1702 tmp[len] = 0;
1703 // fprintf(stderr, "Found: %s\n", tmp);
1704 ptr += len + 1;
1705 if (*tmp) {
1706
1707 u32 copy = 1;
1708 if (!strcmp(tmp, "fuzzer")) {
1709
1710 detect_single_fuzzer = 1;
1711 copy = 0;
1712
1713 } else if (!strncmp(tmp, "fuzzer", 6)) {
1714
1715 copy = 0;
1716
1717 }
1718
1719 if (copy) {
1720
1721 if (count) { strcat(new, ","); }
1722 strcat(new, tmp);
1723 ++count;
1724
1725 }
1726
1727 }
1728
1729 } else {
1730
1731 ptr++;
1732
1733 }
1734
1735 } while (!ende);
1736
1737 strcpy(string, new);
1738
1739 ck_free(tmp);
1740 ck_free(new);
1741
1742 return detect_single_fuzzer;
1743
1744 }
1745
1746 /*
1747 Parse and process possible -fsanitize related args, return PARAM_MISS
1748 if nothing matched. We have 3 main tasks here for these args:
1749 - Check which one of those sanitizers present here.
1750 - Check if libfuzzer present. We need to block the request of enable
1751 libfuzzer, and link harness with our libAFLDriver.a later.
1752 - Check if SanCov allow/denylist options present. We need to try switching
1753 to LLVMNATIVE instead of using our optimized PCGUARD anyway. If we
1754 can't make it finally for various reasons, just drop these options.
1755 */
parse_fsanitize(aflcc_state_t * aflcc,u8 * cur_argv,u8 scan)1756 param_st parse_fsanitize(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
1757
1758 param_st final_ = PARAM_MISS;
1759
1760 // MACRO START
1761 #define HAVE_SANITIZER_SCAN_KEEP(v, k) \
1762 do { \
1763 \
1764 if (strstr(cur_argv, "=" STRINGIFY(k)) || \
1765 strstr(cur_argv, "," STRINGIFY(k))) { \
1766 \
1767 if (scan) { \
1768 \
1769 aflcc->have_##v = 1; \
1770 final_ = PARAM_SCAN; \
1771 \
1772 } else { \
1773 \
1774 final_ = PARAM_KEEP; \
1775 \
1776 } \
1777 \
1778 } \
1779 \
1780 } while (0)
1781
1782 // MACRO END
1783
1784 if (!strncmp(cur_argv, "-fsanitize=", strlen("-fsanitize="))) {
1785
1786 HAVE_SANITIZER_SCAN_KEEP(asan, address);
1787 HAVE_SANITIZER_SCAN_KEEP(msan, memory);
1788 HAVE_SANITIZER_SCAN_KEEP(ubsan, undefined);
1789 HAVE_SANITIZER_SCAN_KEEP(tsan, thread);
1790 HAVE_SANITIZER_SCAN_KEEP(lsan, leak);
1791 HAVE_SANITIZER_SCAN_KEEP(cfisan, cfi);
1792
1793 }
1794
1795 #undef HAVE_SANITIZER_SCAN_KEEP
1796
1797 // We can't use a "else if" there, because some of the following
1798 // matching rules overlap with those in the if-statement above.
1799 if (!strcmp(cur_argv, "-fsanitize=fuzzer")) {
1800
1801 if (scan) {
1802
1803 aflcc->need_aflpplib = 1;
1804 final_ = PARAM_SCAN;
1805
1806 } else {
1807
1808 final_ = PARAM_DROP;
1809
1810 }
1811
1812 } else if (!strncmp(cur_argv, "-fsanitize=", strlen("-fsanitize=")) &&
1813
1814 strchr(cur_argv, ',') &&
1815 !strstr(cur_argv, "=,")) { // avoid OOB errors
1816
1817 if (scan) {
1818
1819 u8 *cur_argv_ = ck_strdup(cur_argv);
1820
1821 if (fsanitize_fuzzer_comma(cur_argv_)) {
1822
1823 aflcc->need_aflpplib = 1;
1824 final_ = PARAM_SCAN;
1825
1826 }
1827
1828 ck_free(cur_argv_);
1829
1830 } else {
1831
1832 fsanitize_fuzzer_comma(cur_argv);
1833 if (!cur_argv || strlen(cur_argv) <= strlen("-fsanitize="))
1834 final_ = PARAM_DROP; // this means it only has "fuzzer" previously.
1835
1836 }
1837
1838 } else if (!strncmp(cur_argv, "-fsanitize-coverage-", 20) &&
1839
1840 strstr(cur_argv, "list=")) {
1841
1842 if (scan) {
1843
1844 aflcc->have_instr_list = 1;
1845 final_ = PARAM_SCAN;
1846
1847 } else {
1848
1849 if (aflcc->instrument_mode != INSTRUMENT_LLVMNATIVE) {
1850
1851 if (!be_quiet) { WARNF("Found '%s' - stripping!", cur_argv); }
1852 final_ = PARAM_DROP;
1853
1854 } else {
1855
1856 final_ = PARAM_KEEP;
1857
1858 }
1859
1860 }
1861
1862 }
1863
1864 if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
1865
1866 return final_;
1867
1868 }
1869
1870 /*
1871 Add params for sanitizers. Here we need to consider:
1872 - Use static runtime for asan, as much as possible.
1873 - ASAN, MSAN, AFL_HARDEN are mutually exclusive.
1874 - Add options if not found there, on request of AFL_USE_ASAN, AFL_USE_MSAN,
1875 etc.
1876 - Update have_* so that functions called after this can have correct context.
1877 However this also means any functions called before should NOT depend on
1878 these have_*, otherwise they may not work as expected.
1879 */
add_sanitizers(aflcc_state_t * aflcc,char ** envp)1880 void add_sanitizers(aflcc_state_t *aflcc, char **envp) {
1881
1882 if (getenv("AFL_USE_ASAN") || aflcc->have_asan) {
1883
1884 if (getenv("AFL_USE_MSAN") || aflcc->have_msan)
1885 FATAL("ASAN and MSAN are mutually exclusive");
1886
1887 if (getenv("AFL_HARDEN"))
1888 FATAL("ASAN and AFL_HARDEN are mutually exclusive");
1889
1890 if (aflcc->compiler_mode == GCC_PLUGIN && !aflcc->have_staticasan) {
1891
1892 insert_param(aflcc, "-static-libasan");
1893
1894 }
1895
1896 add_defs_fortify(aflcc, 0);
1897 if (!aflcc->have_asan) { insert_param(aflcc, "-fsanitize=address"); }
1898 aflcc->have_asan = 1;
1899
1900 } else if (getenv("AFL_USE_MSAN") || aflcc->have_msan) {
1901
1902 if (getenv("AFL_USE_ASAN") || aflcc->have_asan)
1903 FATAL("ASAN and MSAN are mutually exclusive");
1904
1905 if (getenv("AFL_HARDEN"))
1906 FATAL("MSAN and AFL_HARDEN are mutually exclusive");
1907
1908 add_defs_fortify(aflcc, 0);
1909 if (!aflcc->have_msan) { insert_param(aflcc, "-fsanitize=memory"); }
1910 aflcc->have_msan = 1;
1911
1912 }
1913
1914 if (getenv("AFL_USE_UBSAN") || aflcc->have_ubsan) {
1915
1916 if (!aflcc->have_ubsan) {
1917
1918 insert_param(aflcc, "-fsanitize=undefined");
1919 insert_param(aflcc, "-fsanitize-undefined-trap-on-error");
1920 insert_param(aflcc, "-fno-sanitize-recover=all");
1921
1922 }
1923
1924 if (!aflcc->have_fp) {
1925
1926 insert_param(aflcc, "-fno-omit-frame-pointer");
1927 aflcc->have_fp = 1;
1928
1929 }
1930
1931 aflcc->have_ubsan = 1;
1932
1933 }
1934
1935 if (getenv("AFL_USE_TSAN") || aflcc->have_tsan) {
1936
1937 if (!aflcc->have_fp) {
1938
1939 insert_param(aflcc, "-fno-omit-frame-pointer");
1940 aflcc->have_fp = 1;
1941
1942 }
1943
1944 if (!aflcc->have_tsan) { insert_param(aflcc, "-fsanitize=thread"); }
1945 aflcc->have_tsan = 1;
1946
1947 }
1948
1949 if (getenv("AFL_USE_LSAN") && !aflcc->have_lsan) {
1950
1951 insert_param(aflcc, "-fsanitize=leak");
1952 add_defs_lsan_ctrl(aflcc);
1953 aflcc->have_lsan = 1;
1954
1955 }
1956
1957 if (getenv("AFL_USE_CFISAN") || aflcc->have_cfisan) {
1958
1959 if (aflcc->compiler_mode == GCC_PLUGIN || aflcc->compiler_mode == GCC) {
1960
1961 if (!aflcc->have_fcf) { insert_param(aflcc, "-fcf-protection=full"); }
1962
1963 } else {
1964
1965 if (!aflcc->lto_mode && !aflcc->have_flto) {
1966
1967 uint32_t i = 0, found = 0;
1968 while (envp[i] != NULL && !found) {
1969
1970 if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
1971
1972 }
1973
1974 if (!found) { insert_param(aflcc, "-flto"); }
1975 aflcc->have_flto = 1;
1976
1977 }
1978
1979 if (!aflcc->have_cfisan) { insert_param(aflcc, "-fsanitize=cfi"); }
1980
1981 if (!aflcc->have_hidden) {
1982
1983 insert_param(aflcc, "-fvisibility=hidden");
1984 aflcc->have_hidden = 1;
1985
1986 }
1987
1988 aflcc->have_cfisan = 1;
1989
1990 }
1991
1992 }
1993
1994 }
1995
1996 /* Add params to enable LLVM SanCov, the native PCGUARD */
add_native_pcguard(aflcc_state_t * aflcc)1997 void add_native_pcguard(aflcc_state_t *aflcc) {
1998
1999 /* If there is a rust ASan runtime on the command line, it is likely we're
2000 * linking from rust and adding native flags requiring the sanitizer runtime
2001 * will trigger native clang to add yet another runtime, causing linker
2002 * errors. For now we shouldn't add instrumentation here, we're linking
2003 * anyway.
2004 */
2005 if (aflcc->have_rust_asanrt) { return; }
2006
2007 /* If llvm-config doesn't figure out LLVM_MAJOR, just
2008 go on anyway and let compiler complain if doesn't work. */
2009
2010 #if LLVM_MAJOR > 0 && LLVM_MAJOR < 6
2011 FATAL("pcguard instrumentation with pc-table requires LLVM 6.0.1+");
2012 #else
2013 #if LLVM_MAJOR == 0
2014 WARNF(
2015 "pcguard instrumentation with pc-table requires LLVM 6.0.1+"
2016 " otherwise the compiler will fail");
2017 #endif
2018 if (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CODECOV) {
2019
2020 insert_param(aflcc,
2021 "-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table");
2022
2023 } else {
2024
2025 insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard,pc-table");
2026
2027 }
2028
2029 #endif
2030
2031 }
2032
2033 /*
2034 Add params to launch our optimized PCGUARD on request.
2035 It will fallback to use the native PCGUARD in some cases. If so, plz
2036 bear in mind that instrument_mode will be set to INSTRUMENT_LLVMNATIVE.
2037 */
add_optimized_pcguard(aflcc_state_t * aflcc)2038 void add_optimized_pcguard(aflcc_state_t *aflcc) {
2039
2040 #if LLVM_MAJOR >= 13
2041 #if defined __ANDROID__ || ANDROID
2042
2043 insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
2044 aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
2045
2046 #else
2047
2048 if (aflcc->have_instr_list) {
2049
2050 if (!be_quiet)
2051 SAYF(
2052 "Using unoptimized trace-pc-guard, due usage of "
2053 "-fsanitize-coverage-allow/denylist, you can use "
2054 "AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST instead.\n");
2055
2056 insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
2057 aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
2058
2059 } else {
2060
2061 /* Since LLVM_MAJOR >= 13 we use new pass manager */
2062 #if LLVM_MAJOR < 16
2063 insert_param(aflcc, "-fexperimental-new-pass-manager");
2064 #endif
2065 insert_object(aflcc, "SanitizerCoveragePCGUARD.so", "-fpass-plugin=%s", 0);
2066
2067 }
2068
2069 #endif // defined __ANDROID__ || ANDROID
2070 #else // LLVM_MAJOR < 13
2071 #if LLVM_MAJOR >= 4
2072
2073 if (!be_quiet)
2074 SAYF(
2075 "Using unoptimized trace-pc-guard, upgrade to LLVM 13+ for "
2076 "enhanced version.\n");
2077 insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
2078 aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
2079
2080 #else
2081
2082 FATAL("pcguard instrumentation requires LLVM 4.0.1+");
2083
2084 #endif
2085 #endif
2086
2087 }
2088
2089 /** About -fsanitize -----END----- **/
2090
2091 /** Linking behaviors -----BEGIN----- **/
2092
2093 /*
2094 Parse and process possible linking stage related args,
2095 return PARAM_MISS if nothing matched.
2096 */
parse_linking_params(aflcc_state_t * aflcc,u8 * cur_argv,u8 scan,u8 * skip_next,char ** argv)2097 param_st parse_linking_params(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan,
2098 u8 *skip_next, char **argv) {
2099
2100 if (aflcc->lto_mode && !strncmp(cur_argv, "-flto=thin", 10)) {
2101
2102 FATAL(
2103 "afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or "
2104 "use afl-clang-fast!");
2105
2106 }
2107
2108 param_st final_ = PARAM_MISS;
2109
2110 if (!strcmp(cur_argv, "-shared") || !strcmp(cur_argv, "-dynamiclib")) {
2111
2112 if (scan) {
2113
2114 aflcc->shared_linking = 1;
2115 final_ = PARAM_SCAN;
2116
2117 } else {
2118
2119 final_ = PARAM_KEEP;
2120
2121 }
2122
2123 } else if (!strcmp(cur_argv, "-Wl,-r") || !strcmp(cur_argv, "-Wl,-i") ||
2124
2125 !strcmp(cur_argv, "-Wl,--relocatable") ||
2126 !strcmp(cur_argv, "-r") || !strcmp(cur_argv, "--relocatable")) {
2127
2128 if (scan) {
2129
2130 aflcc->partial_linking = 1;
2131 final_ = PARAM_SCAN;
2132
2133 } else {
2134
2135 final_ = PARAM_KEEP;
2136
2137 }
2138
2139 } else if (!strncmp(cur_argv, "-fuse-ld=", 9) ||
2140
2141 !strncmp(cur_argv, "--ld-path=", 10)) {
2142
2143 if (scan) {
2144
2145 final_ = PARAM_SCAN;
2146
2147 } else {
2148
2149 if (aflcc->lto_mode)
2150 final_ = PARAM_DROP;
2151 else
2152 final_ = PARAM_KEEP;
2153
2154 }
2155
2156 } else if (!strcmp(cur_argv, "-Wl,-z,defs") ||
2157
2158 !strcmp(cur_argv, "-Wl,--no-undefined") ||
2159 !strcmp(cur_argv, "-Wl,-no-undefined") ||
2160 !strcmp(cur_argv, "--no-undefined") ||
2161 strstr(cur_argv, "afl-compiler-rt") ||
2162 strstr(cur_argv, "afl-llvm-rt")) {
2163
2164 if (scan) {
2165
2166 final_ = PARAM_SCAN;
2167
2168 } else {
2169
2170 final_ = PARAM_DROP;
2171
2172 }
2173
2174 } else if (!strcmp(cur_argv, "-z") || !strcmp(cur_argv, "-Wl,-z")) {
2175
2176 u8 *param = *(argv + 1);
2177 if (param && (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs"))) {
2178
2179 *skip_next = 1;
2180
2181 if (scan) {
2182
2183 final_ = PARAM_SCAN;
2184
2185 } else {
2186
2187 final_ = PARAM_DROP;
2188
2189 }
2190
2191 }
2192
2193 }
2194
2195 // Try to warn user for some unsupported cases
2196 if (scan && final_ == PARAM_MISS) {
2197
2198 u8 *ptr_ = NULL;
2199
2200 if (!strcmp(cur_argv, "-Xlinker") && (ptr_ = *(argv + 1))) {
2201
2202 if (!strcmp(ptr_, "defs")) {
2203
2204 WARNF("'-Xlinker' 'defs' detected. This may result in a bad link.");
2205
2206 } else if (strstr(ptr_, "-no-undefined")) {
2207
2208 WARNF(
2209 "'-Xlinker' '%s' detected. The latter option may be dropped and "
2210 "result in a bad link.",
2211 ptr_);
2212
2213 }
2214
2215 } else if (!strncmp(cur_argv, "-Wl,", 4) &&
2216
2217 (u8 *)strrchr(cur_argv, ',') != (cur_argv + 3)) {
2218
2219 ptr_ = cur_argv + 4;
2220
2221 if (strstr(ptr_, "-shared") || strstr(ptr_, "-dynamiclib")) {
2222
2223 WARNF(
2224 "'%s': multiple link options after '-Wl,' may break shared "
2225 "linking.",
2226 ptr_);
2227
2228 }
2229
2230 if (strstr(ptr_, "-r,") || strstr(ptr_, "-i,") || strstr(ptr_, ",-r") ||
2231 strstr(ptr_, ",-i") || strstr(ptr_, "--relocatable")) {
2232
2233 WARNF(
2234 "'%s': multiple link options after '-Wl,' may break partial "
2235 "linking.",
2236 ptr_);
2237
2238 }
2239
2240 if (strstr(ptr_, "defs") || strstr(ptr_, "no-undefined")) {
2241
2242 WARNF(
2243 "'%s': multiple link options after '-Wl,' may enable report "
2244 "unresolved symbol references and result in a bad link.",
2245 ptr_);
2246
2247 }
2248
2249 }
2250
2251 }
2252
2253 if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
2254
2255 return final_;
2256
2257 }
2258
2259 /* Add params to specify the linker used in LTO */
add_lto_linker(aflcc_state_t * aflcc)2260 void add_lto_linker(aflcc_state_t *aflcc) {
2261
2262 unsetenv("AFL_LD");
2263 unsetenv("AFL_LD_CALLER");
2264
2265 u8 *ld_path = NULL;
2266 if (getenv("AFL_REAL_LD")) {
2267
2268 ld_path = strdup(getenv("AFL_REAL_LD"));
2269
2270 } else {
2271
2272 ld_path = strdup(AFL_REAL_LD);
2273
2274 }
2275
2276 if (!ld_path || !*ld_path) {
2277
2278 if (ld_path) {
2279
2280 // Freeing empty string
2281 free(ld_path);
2282
2283 }
2284
2285 ld_path = strdup("ld.lld");
2286
2287 }
2288
2289 if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); }
2290 #if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12
2291 insert_param(aflcc, alloc_printf("--ld-path=%s", ld_path));
2292 #else
2293 insert_param(aflcc, alloc_printf("-fuse-ld=%s", ld_path));
2294 #endif
2295 free(ld_path);
2296
2297 }
2298
2299 /* Add params to launch SanitizerCoverageLTO.so when linking */
add_lto_passes(aflcc_state_t * aflcc)2300 void add_lto_passes(aflcc_state_t *aflcc) {
2301
2302 #if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 15
2303 // The NewPM implementation only works fully since LLVM 15.
2304 insert_object(aflcc, "SanitizerCoverageLTO.so", "-Wl,--load-pass-plugin=%s",
2305 0);
2306 #elif defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 13
2307 insert_param(aflcc, "-Wl,--lto-legacy-pass-manager");
2308 insert_object(aflcc, "SanitizerCoverageLTO.so", "-Wl,-mllvm=-load=%s", 0);
2309 #else
2310 insert_param(aflcc, "-fno-experimental-new-pass-manager");
2311 insert_object(aflcc, "SanitizerCoverageLTO.so", "-Wl,-mllvm=-load=%s", 0);
2312 #endif
2313
2314 insert_param(aflcc, "-Wl,--allow-multiple-definition");
2315
2316 }
2317
2318 /* Add params to link with libAFLDriver.a on request */
add_aflpplib(aflcc_state_t * aflcc)2319 static void add_aflpplib(aflcc_state_t *aflcc) {
2320
2321 if (!aflcc->need_aflpplib) return;
2322
2323 u8 *afllib = find_object(aflcc, "libAFLDriver.a");
2324
2325 if (!be_quiet) {
2326
2327 OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
2328
2329 }
2330
2331 if (!afllib) {
2332
2333 if (!be_quiet) {
2334
2335 WARNF(
2336 "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
2337 "the flags - this will fail!");
2338
2339 }
2340
2341 } else {
2342
2343 insert_param(aflcc, afllib);
2344
2345 #ifdef __APPLE__
2346 insert_param(aflcc, "-Wl,-undefined");
2347 insert_param(aflcc, "dynamic_lookup");
2348 #endif
2349
2350 }
2351
2352 }
2353
2354 /* Add params to link with runtimes depended by our instrumentation */
add_runtime(aflcc_state_t * aflcc)2355 void add_runtime(aflcc_state_t *aflcc) {
2356
2357 if (aflcc->preprocessor_only || aflcc->have_c || !aflcc->non_dash) {
2358
2359 /* In the preprocessor_only case (-E), we are not actually compiling at
2360 all but requesting the compiler to output preprocessed sources only.
2361 We must not add the runtime in this case because the compiler will
2362 simply output its binary content back on stdout, breaking any build
2363 systems that rely on a separate source preprocessing step. */
2364 return;
2365
2366 }
2367
2368 if (aflcc->compiler_mode != GCC_PLUGIN && aflcc->compiler_mode != GCC &&
2369 !getenv("AFL_LLVM_NO_RPATH")) {
2370
2371 // in case LLVM is installed not via a package manager or "make install"
2372 // e.g. compiled download or compiled from github then its ./lib directory
2373 // might not be in the search path. Add it if so.
2374 const char *libdir = LLVM_LIBDIR;
2375 if (aflcc->plusplus_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) &&
2376 strncmp(libdir, "/lib", 4)) {
2377
2378 u8 *libdir_opt = strdup("-Wl,-rpath=" LLVM_LIBDIR);
2379 insert_param(aflcc, libdir_opt);
2380
2381 }
2382
2383 }
2384
2385 #ifndef __ANDROID__
2386
2387 #define M32_ERR_MSG "-m32 is not supported by your compiler"
2388 #define M64_ERR_MSG "-m64 is not supported by your compiler"
2389
2390 if (aflcc->compiler_mode != GCC && aflcc->compiler_mode != CLANG) {
2391
2392 switch (aflcc->bit_mode) {
2393
2394 case 0:
2395 if (!aflcc->shared_linking && !aflcc->partial_linking)
2396 insert_object(aflcc, "afl-compiler-rt.o", 0, 0);
2397 if (aflcc->lto_mode) insert_object(aflcc, "afl-llvm-rt-lto.o", 0, 0);
2398 break;
2399
2400 case 32:
2401 if (!aflcc->shared_linking && !aflcc->partial_linking)
2402 insert_object(aflcc, "afl-compiler-rt-32.o", 0, M32_ERR_MSG);
2403 if (aflcc->lto_mode)
2404 insert_object(aflcc, "afl-llvm-rt-lto-32.o", 0, M32_ERR_MSG);
2405 break;
2406
2407 case 64:
2408 if (!aflcc->shared_linking && !aflcc->partial_linking)
2409 insert_object(aflcc, "afl-compiler-rt-64.o", 0, M64_ERR_MSG);
2410 if (aflcc->lto_mode)
2411 insert_object(aflcc, "afl-llvm-rt-lto-64.o", 0, M64_ERR_MSG);
2412 break;
2413
2414 }
2415
2416 #if __AFL_CODE_COVERAGE
2417 // Required for dladdr used in afl-compiler-rt.o
2418 insert_param(aflcc, "-ldl");
2419 #endif
2420
2421 #if !defined(__APPLE__) && !defined(__sun)
2422 if (!aflcc->shared_linking && !aflcc->partial_linking)
2423 insert_object(aflcc, "dynamic_list.txt", "-Wl,--dynamic-list=%s", 0);
2424 #endif
2425
2426 #if defined(__APPLE__)
2427 if (aflcc->shared_linking || aflcc->partial_linking) {
2428
2429 insert_param(aflcc, "-Wl,-U");
2430 insert_param(aflcc, "-Wl,___afl_area_ptr");
2431 insert_param(aflcc, "-Wl,-U");
2432 insert_param(aflcc, "-Wl,___sanitizer_cov_trace_pc_guard_init");
2433
2434 }
2435
2436 #endif
2437
2438 }
2439
2440 #endif
2441
2442 add_aflpplib(aflcc);
2443
2444 #if defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
2445 insert_param(aflcc, "-Wl,-lrt");
2446 #endif
2447
2448 }
2449
2450 /** Linking behaviors -----END----- **/
2451
2452 /** Miscellaneous routines -----BEGIN----- **/
2453
2454 /*
2455 Add params to make compiler driver use our afl-as
2456 as assembler, required by the vanilla instrumentation.
2457 */
add_assembler(aflcc_state_t * aflcc)2458 void add_assembler(aflcc_state_t *aflcc) {
2459
2460 u8 *afl_as = find_object(aflcc, "as");
2461
2462 if (!afl_as) FATAL("Cannot find 'as' (symlink to 'afl-as').");
2463
2464 u8 *slash = strrchr(afl_as, '/');
2465 if (slash) *slash = 0;
2466
2467 insert_param(aflcc, "-B");
2468 insert_param(aflcc, afl_as);
2469
2470 if (aflcc->compiler_mode == CLANG) insert_param(aflcc, "-no-integrated-as");
2471
2472 }
2473
2474 /* Add params to launch the gcc plugins for instrumentation. */
add_gcc_plugin(aflcc_state_t * aflcc)2475 void add_gcc_plugin(aflcc_state_t *aflcc) {
2476
2477 if (aflcc->cmplog_mode) {
2478
2479 insert_object(aflcc, "afl-gcc-cmplog-pass.so", "-fplugin=%s", 0);
2480 insert_object(aflcc, "afl-gcc-cmptrs-pass.so", "-fplugin=%s", 0);
2481
2482 }
2483
2484 insert_object(aflcc, "afl-gcc-pass.so", "-fplugin=%s", 0);
2485
2486 insert_param(aflcc, "-fno-if-conversion");
2487 insert_param(aflcc, "-fno-if-conversion2");
2488
2489 }
2490
2491 /* Add some miscellaneous params required by our instrumentation. */
add_misc_params(aflcc_state_t * aflcc)2492 void add_misc_params(aflcc_state_t *aflcc) {
2493
2494 if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
2495 getenv("AFL_LLVM_LAF_ALL") || getenv("AFL_LLVM_CMPLOG") ||
2496 aflcc->lto_mode) {
2497
2498 insert_param(aflcc, "-fno-builtin-strcmp");
2499 insert_param(aflcc, "-fno-builtin-strncmp");
2500 insert_param(aflcc, "-fno-builtin-strcasecmp");
2501 insert_param(aflcc, "-fno-builtin-strncasecmp");
2502 insert_param(aflcc, "-fno-builtin-memcmp");
2503 insert_param(aflcc, "-fno-builtin-bcmp");
2504 insert_param(aflcc, "-fno-builtin-strstr");
2505 insert_param(aflcc, "-fno-builtin-strcasestr");
2506
2507 }
2508
2509 if (!aflcc->have_pic) { insert_param(aflcc, "-fPIC"); }
2510
2511 if (getenv("AFL_HARDEN")) {
2512
2513 insert_param(aflcc, "-fstack-protector-all");
2514
2515 if (!aflcc->fortify_set) add_defs_fortify(aflcc, 2);
2516
2517 }
2518
2519 if (!getenv("AFL_DONT_OPTIMIZE")) {
2520
2521 insert_param(aflcc, "-g");
2522 if (!aflcc->have_o) insert_param(aflcc, "-O3");
2523 if (!aflcc->have_unroll) insert_param(aflcc, "-funroll-loops");
2524 // if (strlen(aflcc->march_opt) > 1 && aflcc->march_opt[0] == '-')
2525 // insert_param(aflcc, aflcc->march_opt);
2526
2527 }
2528
2529 if (aflcc->x_set) {
2530
2531 insert_param(aflcc, "-x");
2532 insert_param(aflcc, "none");
2533
2534 }
2535
2536 }
2537
2538 /*
2539 Parse and process a variety of args under our matching rules,
2540 return PARAM_MISS if nothing matched.
2541 */
parse_misc_params(aflcc_state_t * aflcc,u8 * cur_argv,u8 scan)2542 param_st parse_misc_params(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
2543
2544 param_st final_ = PARAM_MISS;
2545
2546 // MACRO START
2547 #define SCAN_KEEP(dst, src) \
2548 do { \
2549 \
2550 if (scan) { \
2551 \
2552 dst = src; \
2553 final_ = PARAM_SCAN; \
2554 \
2555 } else { \
2556 \
2557 final_ = PARAM_KEEP; \
2558 \
2559 } \
2560 \
2561 } while (0)
2562
2563 // MACRO END
2564
2565 if (!strncasecmp(cur_argv, "-fpic", 5)) {
2566
2567 SCAN_KEEP(aflcc->have_pic, 1);
2568
2569 } else if (!strcmp(cur_argv, "-m32") ||
2570
2571 !strcmp(cur_argv, "armv7a-linux-androideabi")) {
2572
2573 SCAN_KEEP(aflcc->bit_mode, 32);
2574
2575 } else if (!strcmp(cur_argv, "-m64")) {
2576
2577 SCAN_KEEP(aflcc->bit_mode, 64);
2578
2579 } else if (strstr(cur_argv, "FORTIFY_SOURCE")) {
2580
2581 SCAN_KEEP(aflcc->fortify_set, 1);
2582
2583 } else if (!strcmp(cur_argv, "-x")) {
2584
2585 SCAN_KEEP(aflcc->x_set, 1);
2586
2587 } else if (!strcmp(cur_argv, "-E")) {
2588
2589 SCAN_KEEP(aflcc->preprocessor_only, 1);
2590
2591 } else if (!strcmp(cur_argv, "--target=wasm32-wasi")) {
2592
2593 SCAN_KEEP(aflcc->passthrough, 1);
2594
2595 } else if (!strcmp(cur_argv, "-c")) {
2596
2597 SCAN_KEEP(aflcc->have_c, 1);
2598
2599 } else if (!strcmp(cur_argv, "-static-libasan")) {
2600
2601 SCAN_KEEP(aflcc->have_staticasan, 1);
2602
2603 } else if (strstr(cur_argv, "librustc") && strstr(cur_argv, "_rt.asan.a")) {
2604
2605 SCAN_KEEP(aflcc->have_rust_asanrt, 1);
2606
2607 } else if (!strcmp(cur_argv, "-fno-omit-frame-pointer")) {
2608
2609 SCAN_KEEP(aflcc->have_fp, 1);
2610
2611 } else if (!strcmp(cur_argv, "-fvisibility=hidden")) {
2612
2613 SCAN_KEEP(aflcc->have_hidden, 1);
2614
2615 } else if (!strcmp(cur_argv, "-flto") || !strcmp(cur_argv, "-flto=full")) {
2616
2617 SCAN_KEEP(aflcc->have_flto, 1);
2618
2619 } else if (!strncmp(cur_argv, "-D_FORTIFY_SOURCE",
2620
2621 strlen("-D_FORTIFY_SOURCE"))) {
2622
2623 SCAN_KEEP(aflcc->have_fortify, 1);
2624
2625 } else if (!strncmp(cur_argv, "-fcf-protection", strlen("-fcf-protection"))) {
2626
2627 SCAN_KEEP(aflcc->have_cfisan, 1);
2628
2629 } else if (!strncmp(cur_argv, "-O", 2)) {
2630
2631 SCAN_KEEP(aflcc->have_o, 1);
2632
2633 } else if (!strncmp(cur_argv, "-funroll-loop", 13)) {
2634
2635 SCAN_KEEP(aflcc->have_unroll, 1);
2636
2637 } else if (!strncmp(cur_argv, "--afl", 5)) {
2638
2639 if (scan)
2640 final_ = PARAM_SCAN;
2641 else
2642 final_ = PARAM_DROP;
2643
2644 } else if (!strncmp(cur_argv, "-fno-unroll", 11)) {
2645
2646 if (scan)
2647 final_ = PARAM_SCAN;
2648 else
2649 final_ = PARAM_DROP;
2650
2651 } else if (!strcmp(cur_argv, "-pipe") && aflcc->compiler_mode == GCC_PLUGIN) {
2652
2653 if (scan)
2654 final_ = PARAM_SCAN;
2655 else
2656 final_ = PARAM_DROP;
2657
2658 } else if (!strncmp(cur_argv, "-stdlib=", 8) &&
2659
2660 (aflcc->compiler_mode == GCC ||
2661 aflcc->compiler_mode == GCC_PLUGIN)) {
2662
2663 if (scan) {
2664
2665 final_ = PARAM_SCAN;
2666
2667 } else {
2668
2669 if (!be_quiet) WARNF("Found '%s' - stripping!", cur_argv);
2670 final_ = PARAM_DROP;
2671
2672 }
2673
2674 } else if (cur_argv[0] != '-') {
2675
2676 /* It's a weak, loose pattern, with very different purpose
2677 than others. We handle it at last, cautiously and robustly. */
2678
2679 if (scan && cur_argv[0] != '@') // response file support
2680 aflcc->non_dash = 1;
2681
2682 }
2683
2684 #undef SCAN_KEEP
2685
2686 if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
2687
2688 return final_;
2689
2690 }
2691
2692 /** Miscellaneous routines -----END----- **/
2693
2694 /* Print help message on request */
maybe_usage(aflcc_state_t * aflcc,int argc,char ** argv)2695 static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
2696
2697 if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) {
2698
2699 printf("afl-cc" VERSION
2700 " by Michal Zalewski, Laszlo Szekeres, Marc Heuse\n");
2701
2702 SAYF(
2703 "\n"
2704 "afl-cc/afl-c++ [options]\n"
2705 "\n"
2706 "This is a helper application for afl-fuzz. It serves as a drop-in "
2707 "replacement\n"
2708 "for gcc and clang, letting you recompile third-party code with the "
2709 "required\n"
2710 "runtime instrumentation. A common use pattern would be one of the "
2711 "following:\n\n"
2712
2713 " CC=afl-cc CXX=afl-c++ ./configure --disable-shared\n"
2714 " cmake -DCMAKE_C_COMPILERC=afl-cc -DCMAKE_CXX_COMPILER=afl-c++ .\n"
2715 " CC=afl-cc CXX=afl-c++ meson\n\n");
2716
2717 SAYF(
2718 " |------------- FEATURES "
2719 "-------------|\n"
2720 "MODES: NCC PERSIST DICT LAF "
2721 "CMPLOG SELECT\n"
2722 " [LLVM] LLVM: %s%s\n"
2723 " PCGUARD %s yes yes module yes yes "
2724 "yes\n"
2725 " NATIVE AVAILABLE no yes no no "
2726 "part. yes\n"
2727 " CLASSIC %s no yes module yes yes "
2728 "yes\n"
2729 " - NORMAL\n"
2730 " - CALLER\n"
2731 " - CTX\n"
2732 " - NGRAM-{2-16}\n"
2733 " [LTO] LLVM LTO: %s%s\n"
2734 " PCGUARD DEFAULT yes yes yes yes yes "
2735 " yes\n"
2736 " CLASSIC yes yes yes yes yes "
2737 " yes\n"
2738 " [GCC_PLUGIN] gcc plugin: %s%s\n"
2739 " CLASSIC DEFAULT no yes no no no "
2740 "yes\n"
2741 " [GCC/CLANG] simple gcc/clang: %s%s\n"
2742 " CLASSIC DEFAULT no no no no no "
2743 "no\n\n",
2744 aflcc->have_llvm ? "AVAILABLE" : "unavailable!",
2745 aflcc->compiler_mode == LLVM ? " [SELECTED]" : "",
2746 aflcc->have_llvm ? "AVAILABLE" : "unavailable!",
2747 aflcc->have_llvm ? "AVAILABLE" : "unavailable!",
2748 aflcc->have_lto ? "AVAILABLE" : "unavailable!",
2749 aflcc->compiler_mode == LTO ? " [SELECTED]" : "",
2750 aflcc->have_gcc_plugin ? "AVAILABLE" : "unavailable!",
2751 aflcc->compiler_mode == GCC_PLUGIN ? " [SELECTED]" : "",
2752 aflcc->have_gcc && aflcc->have_clang
2753 ? "AVAILABLE"
2754 : (aflcc->have_gcc
2755 ? "GCC ONLY "
2756 : (aflcc->have_clang ? "CLANG ONLY" : "unavailable!")),
2757 (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG)
2758 ? " [SELECTED]"
2759 : "");
2760
2761 SAYF(
2762 "Modes:\n"
2763 " To select the compiler mode use a symlink version (e.g. "
2764 "afl-clang-fast), set\n"
2765 " the environment variable AFL_CC_COMPILER to a mode (e.g. LLVM) or "
2766 "use the\n"
2767 " command line parameter --afl-MODE (e.g. --afl-llvm). If none is "
2768 "selected,\n"
2769 " afl-cc will select the best available (LLVM -> GCC_PLUGIN -> GCC).\n"
2770 " The best is LTO but it often needs RANLIB and AR settings outside "
2771 "of afl-cc.\n\n");
2772
2773 #if LLVM_MAJOR > 10 || (LLVM_MAJOR == 10 && LLVM_MINOR > 0)
2774 #define NATIVE_MSG \
2775 " LLVM-NATIVE: use llvm's native PCGUARD instrumentation (less " \
2776 "performant)\n"
2777 #else
2778 #define NATIVE_MSG ""
2779 #endif
2780
2781 SAYF(
2782 "Sub-Modes: (set via env AFL_LLVM_INSTRUMENT, afl-cc selects the best "
2783 "available)\n"
2784 " PCGUARD: Dominator tree instrumentation (best!) (README.llvm.md)\n"
2785
2786 NATIVE_MSG
2787
2788 " CLASSIC: decision target instrumentation (README.llvm.md)\n"
2789 " CALLER: CLASSIC + single callee context "
2790 "(instrumentation/README.ctx.md)\n"
2791 " CTX: CLASSIC + full callee context "
2792 "(instrumentation/README.ctx.md)\n"
2793 " NGRAM-x: CLASSIC + previous path "
2794 "((instrumentation/README.ngram.md)\n\n");
2795
2796 #undef NATIVE_MSG
2797
2798 SAYF(
2799 "Features: (see documentation links)\n"
2800 " NCC: non-colliding coverage [automatic] (that is an amazing "
2801 "thing!)\n"
2802 " (instrumentation/README.lto.md)\n"
2803 " PERSIST: persistent mode support [code] (huge speed increase!)\n"
2804 " (instrumentation/README.persistent_mode.md)\n"
2805 " DICT: dictionary in the target [yes=automatic or LLVM module "
2806 "pass]\n"
2807 " (instrumentation/README.lto.md + "
2808 "instrumentation/README.llvm.md)\n"
2809 " LAF: comparison splitting [env] "
2810 "(instrumentation/README.laf-intel.md)\n"
2811 " CMPLOG: input2state exploration [env] "
2812 "(instrumentation/README.cmplog.md)\n"
2813 " SELECT: selective instrumentation (allow/deny) on filename or "
2814 "function [env]\n"
2815 " (instrumentation/README.instrument_list.md)\n\n");
2816
2817 if (argc < 2 || strncmp(argv[1], "-hh", 3)) {
2818
2819 SAYF(
2820 "To see all environment variables for the configuration of afl-cc "
2821 "use \"-hh\".\n");
2822
2823 } else {
2824
2825 SAYF(
2826 "Environment variables used:\n"
2827 " AFL_CC: path to the C compiler to use\n"
2828 " AFL_CXX: path to the C++ compiler to use\n"
2829 " AFL_DEBUG: enable developer debugging output\n"
2830 " AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
2831 " AFL_NO_BUILTIN: no builtins for string compare functions (for "
2832 "libtokencap.so)\n"
2833 " AFL_NOOPT: behave like a normal compiler (to pass configure "
2834 "tests)\n"
2835 " AFL_PATH: path to instrumenting pass and runtime "
2836 "(afl-compiler-rt.*o)\n"
2837 " AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
2838 " AFL_INST_RATIO: percentage of branches to instrument\n"
2839 " AFL_QUIET: suppress verbose output\n"
2840 " AFL_HARDEN: adds code hardening to catch memory bugs\n"
2841 " AFL_USE_ASAN: activate address sanitizer\n"
2842 " AFL_USE_CFISAN: activate control flow sanitizer\n"
2843 " AFL_USE_MSAN: activate memory sanitizer\n"
2844 " AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
2845 " AFL_USE_TSAN: activate thread sanitizer\n"
2846 " AFL_USE_LSAN: activate leak-checker sanitizer\n");
2847
2848 if (aflcc->have_gcc_plugin)
2849 SAYF(
2850 "\nGCC Plugin-specific environment variables:\n"
2851 " AFL_GCC_CMPLOG: log operands of comparisons (RedQueen mutator)\n"
2852 " AFL_GCC_OUT_OF_LINE: disable inlined instrumentation\n"
2853 " AFL_GCC_SKIP_NEVERZERO: do not skip zero on trace counters\n"
2854 " AFL_GCC_INSTRUMENT_FILE: enable selective instrumentation by "
2855 "filename\n");
2856
2857 #if LLVM_MAJOR >= 9
2858 #define COUNTER_BEHAVIOUR \
2859 " AFL_LLVM_SKIP_NEVERZERO: do not skip zero on trace counters\n"
2860 #else
2861 #define COUNTER_BEHAVIOUR \
2862 " AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
2863 #endif
2864 if (aflcc->have_llvm)
2865 SAYF(
2866 "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment "
2867 "variables:\n"
2868 " AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters, "
2869 "disables neverzero\n"
2870
2871 COUNTER_BEHAVIOUR
2872
2873 " AFL_LLVM_DICT2FILE: generate an afl dictionary based on found "
2874 "comparisons\n"
2875 " AFL_LLVM_DICT2FILE_NO_MAIN: skip parsing main() for the "
2876 "dictionary\n"
2877 " AFL_LLVM_INJECTIONS_ALL: enables all injections hooking\n"
2878 " AFL_LLVM_INJECTIONS_SQL: enables SQL injections hooking\n"
2879 " AFL_LLVM_INJECTIONS_LDAP: enables LDAP injections hooking\n"
2880 " AFL_LLVM_INJECTIONS_XSS: enables XSS injections hooking\n"
2881 " AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n"
2882 " AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n"
2883 " AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n"
2884 " AFL_LLVM_LAF_SPLIT_SWITCHES: cascaded comparisons on switches\n"
2885 " AFL_LLVM_LAF_SPLIT_FLOATS: cascaded comparisons on floats\n"
2886 " AFL_LLVM_LAF_TRANSFORM_COMPARES: cascade comparisons for string "
2887 "functions\n"
2888 " AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST: enable "
2889 "instrument allow/\n"
2890 " deny listing (selective instrumentation)\n");
2891
2892 if (aflcc->have_llvm)
2893 SAYF(
2894 " AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen "
2895 "mutator)\n"
2896 " AFL_LLVM_INSTRUMENT: set instrumentation mode:\n"
2897 " CLASSIC, PCGUARD, LTO, GCC, CLANG, CALLER, CTX, NGRAM-2 "
2898 "..-16\n"
2899 " You can also use the old environment variables instead:\n"
2900 " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n"
2901 " AFL_LLVM_CALLER: use single context sensitive coverage (for "
2902 "CLASSIC)\n"
2903 " AFL_LLVM_CTX: use full context sensitive coverage (for "
2904 "CLASSIC)\n"
2905 " AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for "
2906 "CLASSIC)\n"
2907 " AFL_LLVM_NO_RPATH: disable rpath setting for custom LLVM "
2908 "locations\n");
2909
2910 #ifdef AFL_CLANG_FLTO
2911 if (aflcc->have_lto)
2912 SAYF(
2913 "\nLTO/afl-clang-lto specific environment variables:\n"
2914 " AFL_LLVM_MAP_ADDR: use a fixed coverage map address (speed), "
2915 "e.g. "
2916 "0x10000\n"
2917 " AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding "
2918 "functions\n"
2919 " into this file (LTO mode)\n"
2920 " AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
2921 "global var\n"
2922 " AFL_LLVM_LTO_STARTID: from which ID to start counting from for "
2923 "a "
2924 "bb\n"
2925 " AFL_REAL_LD: use this lld linker instead of the compiled in "
2926 "path\n"
2927 " AFL_LLVM_LTO_SKIPINIT: don't inject initialization code "
2928 "(used in WAFL mode)\n"
2929 "If anything fails - be sure to read README.lto.md!\n");
2930 #endif
2931
2932 SAYF(
2933 "\nYou can supply --afl-noopt to not instrument, like AFL_NOOPT. "
2934 "(this is helpful\n"
2935 "in some build systems if you do not want to instrument "
2936 "everything.\n");
2937
2938 }
2939
2940 SAYF(
2941 "\nFor any information on the available instrumentations and options "
2942 "please \n"
2943 "consult the README.md, especially section 3.1 about instrumenting "
2944 "targets.\n\n");
2945
2946 #if (LLVM_MAJOR >= 3)
2947 if (aflcc->have_lto)
2948 SAYF("afl-cc LTO with ld=%s %s\n", AFL_REAL_LD, AFL_CLANG_FLTO);
2949 if (aflcc->have_llvm)
2950 SAYF("afl-cc LLVM version %d using the binary path \"%s\".\n", LLVM_MAJOR,
2951 LLVM_BINDIR);
2952 #endif
2953
2954 #ifdef USEMMAP
2955 #if !defined(__HAIKU__)
2956 SAYF("Compiled with shm_open support.\n");
2957 #else
2958 SAYF("Compiled with shm_open support (adds -lrt when linking).\n");
2959 #endif
2960 #else
2961 SAYF("Compiled with shmat support.\n");
2962 #endif
2963 SAYF("\n");
2964
2965 SAYF(
2966 "Do not be overwhelmed :) afl-cc uses good defaults if no options are "
2967 "selected.\n"
2968 "Read the documentation for FEATURES though, all are good but few are "
2969 "defaults.\n"
2970 "Recommended is afl-clang-lto with AFL_LLVM_CMPLOG or afl-clang-fast "
2971 "with\n"
2972 "AFL_LLVM_CMPLOG and "
2973 "AFL_LLVM_DICT2FILE+AFL_LLVM_DICT2FILE_NO_MAIN.\n\n");
2974
2975 if (LLVM_MAJOR < 13) {
2976
2977 SAYF(
2978 "Warning: It is highly recommended to use at least LLVM version 13 "
2979 "(or better, higher) rather than %d!\n\n",
2980 LLVM_MAJOR);
2981
2982 }
2983
2984 exit(1);
2985
2986 }
2987
2988 }
2989
2990 /*
2991 Process params passed to afl-cc.
2992
2993 We have two working modes, *scan* and *non-scan*. In scan mode,
2994 the main task is to set some variables in aflcc according to current argv[i],
2995 while in non-scan mode, is to choose keep or drop current argv[i].
2996
2997 We have several matching routines being called sequentially in the while-loop,
2998 and each of them try to parse and match current argv[i] according to their own
2999 rules. If one miss match, the next will then take over. In non-scan mode, each
3000 argv[i] mis-matched by all the routines will be kept.
3001
3002 These routines are:
3003 1. parse_misc_params
3004 2. parse_fsanitize
3005 3. parse_linking_params
3006 4. `if (*cur == '@') {...}`, i.e., parse response files
3007 */
process_params(aflcc_state_t * aflcc,u8 scan,u32 argc,char ** argv)3008 static void process_params(aflcc_state_t *aflcc, u8 scan, u32 argc,
3009 char **argv) {
3010
3011 // for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]);
3012
3013 /* Process the argument list. */
3014
3015 u8 skip_next = 0;
3016 while (--argc) {
3017
3018 u8 *cur = *(++argv);
3019
3020 if (skip_next > 0) {
3021
3022 skip_next--;
3023 continue;
3024
3025 }
3026
3027 if (PARAM_MISS != parse_misc_params(aflcc, cur, scan)) continue;
3028
3029 if (PARAM_MISS != parse_fsanitize(aflcc, cur, scan)) continue;
3030
3031 if (PARAM_MISS != parse_linking_params(aflcc, cur, scan, &skip_next, argv))
3032 continue;
3033
3034 /* Response file support -----BEGIN-----
3035 We have two choices - move everything to the command line or
3036 rewrite the response files to temporary files and delete them
3037 afterwards. We choose the first for easiness.
3038 For clang, llvm::cl::ExpandResponseFiles does this, however it
3039 only has C++ interface. And for gcc there is expandargv in libiberty,
3040 written in C, but we can't simply copy-paste since its LGPL licensed.
3041 So here we use an equivalent FSM as alternative, and try to be compatible
3042 with the two above. See:
3043 - https://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html
3044 - driver::expand_at_files in gcc.git/gcc/gcc.c
3045 - expandargv in gcc.git/libiberty/argv.c
3046 - llvm-project.git/clang/tools/driver/driver.cpp
3047 - ExpandResponseFiles in
3048 llvm-project.git/llvm/lib/Support/CommandLine.cpp
3049 */
3050 if (*cur == '@') {
3051
3052 u8 *filename = cur + 1;
3053 if (aflcc->debug) { DEBUGF("response file=%s\n", filename); }
3054
3055 // Check not found or empty? let the compiler complain if so.
3056 FILE *f = fopen(filename, "r");
3057 if (!f) {
3058
3059 if (!scan) insert_param(aflcc, cur);
3060 continue;
3061
3062 }
3063
3064 struct stat st;
3065 if (fstat(fileno(f), &st) || !S_ISREG(st.st_mode) || st.st_size < 1) {
3066
3067 fclose(f);
3068 if (!scan) insert_param(aflcc, cur);
3069 continue;
3070
3071 }
3072
3073 // Limit the number of response files, the max value
3074 // just keep consistent with expandargv. Only do this in
3075 // scan mode, and not touch rsp_count anymore in the next.
3076 static u32 rsp_count = 2000;
3077 if (scan) {
3078
3079 if (rsp_count == 0) FATAL("Too many response files provided!");
3080
3081 --rsp_count;
3082
3083 }
3084
3085 // argc, argv acquired from this rsp file. Note that
3086 // process_params ignores argv[0], we need to put a const "" here.
3087 u32 argc_read = 1;
3088 char **argv_read = ck_alloc(sizeof(char *));
3089 argv_read[0] = "";
3090
3091 char *arg_buf = NULL;
3092 u64 arg_len = 0;
3093
3094 enum fsm_state {
3095
3096 fsm_whitespace, // whitespace seen so far
3097 fsm_double_quote, // have unpaired double quote
3098 fsm_single_quote, // have unpaired single quote
3099 fsm_backslash, // a backslash is seen with no unpaired quote
3100 fsm_normal // a normal char is seen
3101
3102 };
3103
3104 // Workaround to append c to arg buffer, and append the buffer to argv
3105 #define ARG_ALLOC(c) \
3106 do { \
3107 \
3108 ++arg_len; \
3109 arg_buf = ck_realloc(arg_buf, (arg_len + 1) * sizeof(char)); \
3110 arg_buf[arg_len] = '\0'; \
3111 arg_buf[arg_len - 1] = (char)c; \
3112 \
3113 } while (0)
3114
3115 #define ARG_STORE() \
3116 do { \
3117 \
3118 ++argc_read; \
3119 argv_read = ck_realloc(argv_read, argc_read * sizeof(char *)); \
3120 argv_read[argc_read - 1] = arg_buf; \
3121 arg_buf = NULL; \
3122 arg_len = 0; \
3123 \
3124 } while (0)
3125
3126 int cur_chr = (int)' '; // init as whitespace, as a good start :)
3127 enum fsm_state state_ = fsm_whitespace;
3128
3129 while (cur_chr != EOF) {
3130
3131 switch (state_) {
3132
3133 case fsm_whitespace:
3134
3135 if (arg_buf) {
3136
3137 ARG_STORE();
3138 break;
3139
3140 }
3141
3142 if (isspace(cur_chr)) {
3143
3144 cur_chr = fgetc(f);
3145
3146 } else if (cur_chr == (int)'\'') {
3147
3148 state_ = fsm_single_quote;
3149 cur_chr = fgetc(f);
3150
3151 } else if (cur_chr == (int)'"') {
3152
3153 state_ = fsm_double_quote;
3154 cur_chr = fgetc(f);
3155
3156 } else if (cur_chr == (int)'\\') {
3157
3158 state_ = fsm_backslash;
3159 cur_chr = fgetc(f);
3160
3161 } else {
3162
3163 state_ = fsm_normal;
3164
3165 }
3166
3167 break;
3168
3169 case fsm_normal:
3170
3171 if (isspace(cur_chr)) {
3172
3173 state_ = fsm_whitespace;
3174
3175 } else if (cur_chr == (int)'\'') {
3176
3177 state_ = fsm_single_quote;
3178 cur_chr = fgetc(f);
3179
3180 } else if (cur_chr == (int)'\"') {
3181
3182 state_ = fsm_double_quote;
3183 cur_chr = fgetc(f);
3184
3185 } else if (cur_chr == (int)'\\') {
3186
3187 state_ = fsm_backslash;
3188 cur_chr = fgetc(f);
3189
3190 } else {
3191
3192 ARG_ALLOC(cur_chr);
3193 cur_chr = fgetc(f);
3194
3195 }
3196
3197 break;
3198
3199 case fsm_backslash:
3200
3201 ARG_ALLOC(cur_chr);
3202 cur_chr = fgetc(f);
3203 state_ = fsm_normal;
3204
3205 break;
3206
3207 case fsm_single_quote:
3208
3209 if (cur_chr == (int)'\\') {
3210
3211 cur_chr = fgetc(f);
3212 if (cur_chr == EOF) break;
3213 ARG_ALLOC(cur_chr);
3214
3215 } else if (cur_chr == (int)'\'') {
3216
3217 state_ = fsm_normal;
3218
3219 } else {
3220
3221 ARG_ALLOC(cur_chr);
3222
3223 }
3224
3225 cur_chr = fgetc(f);
3226 break;
3227
3228 case fsm_double_quote:
3229
3230 if (cur_chr == (int)'\\') {
3231
3232 cur_chr = fgetc(f);
3233 if (cur_chr == EOF) break;
3234 ARG_ALLOC(cur_chr);
3235
3236 } else if (cur_chr == (int)'"') {
3237
3238 state_ = fsm_normal;
3239
3240 } else {
3241
3242 ARG_ALLOC(cur_chr);
3243
3244 }
3245
3246 cur_chr = fgetc(f);
3247 break;
3248
3249 default:
3250 break;
3251
3252 }
3253
3254 }
3255
3256 if (arg_buf) { ARG_STORE(); } // save the pending arg after EOF
3257
3258 #undef ARG_ALLOC
3259 #undef ARG_STORE
3260
3261 if (argc_read > 1) { process_params(aflcc, scan, argc_read, argv_read); }
3262
3263 // We cannot free argv_read[] unless we don't need to keep any
3264 // reference in cc_params. Never free argv[0], the const "".
3265 if (scan) {
3266
3267 while (argc_read > 1)
3268 ck_free(argv_read[--argc_read]);
3269
3270 ck_free(argv_read);
3271
3272 }
3273
3274 continue;
3275
3276 } /* Response file support -----END----- */
3277
3278 if (!scan) insert_param(aflcc, cur);
3279
3280 }
3281
3282 }
3283
3284 /* Process each of the existing argv, also add a few new args. */
edit_params(aflcc_state_t * aflcc,u32 argc,char ** argv,char ** envp)3285 static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv,
3286 char **envp) {
3287
3288 add_real_argv0(aflcc);
3289
3290 // prevent unnecessary build errors
3291 if (aflcc->compiler_mode != GCC_PLUGIN && aflcc->compiler_mode != GCC) {
3292
3293 insert_param(aflcc, "-Wno-unused-command-line-argument");
3294
3295 }
3296
3297 if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG) {
3298
3299 add_assembler(aflcc);
3300
3301 }
3302
3303 if (aflcc->compiler_mode == GCC_PLUGIN) { add_gcc_plugin(aflcc); }
3304
3305 if (aflcc->compiler_mode == LLVM || aflcc->compiler_mode == LTO) {
3306
3307 if (aflcc->lto_mode && aflcc->have_instr_env) {
3308
3309 load_llvm_pass(aflcc, "afl-llvm-lto-instrumentlist.so");
3310
3311 }
3312
3313 if (getenv("AFL_LLVM_DICT2FILE")) {
3314
3315 load_llvm_pass(aflcc, "afl-llvm-dict2file.so");
3316
3317 }
3318
3319 // laf
3320 if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
3321
3322 load_llvm_pass(aflcc, "split-switches-pass.so");
3323
3324 }
3325
3326 if (getenv("LAF_TRANSFORM_COMPARES") ||
3327 getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
3328
3329 load_llvm_pass(aflcc, "compare-transform-pass.so");
3330
3331 }
3332
3333 if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
3334 getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
3335
3336 load_llvm_pass(aflcc, "split-compares-pass.so");
3337
3338 }
3339
3340 // /laf
3341
3342 if (aflcc->cmplog_mode) {
3343
3344 insert_param(aflcc, "-fno-inline");
3345
3346 load_llvm_pass(aflcc, "cmplog-switches-pass.so");
3347 // reuse split switches from laf
3348 load_llvm_pass(aflcc, "split-switches-pass.so");
3349
3350 }
3351
3352 // #if LLVM_MAJOR >= 13
3353 // // Use the old pass manager in LLVM 14 which the AFL++ passes still
3354 // use. insert_param(aflcc, "-flegacy-pass-manager");
3355 // #endif
3356
3357 if (aflcc->lto_mode) {
3358
3359 insert_param(aflcc, aflcc->lto_flag);
3360
3361 if (!aflcc->have_c) {
3362
3363 add_lto_linker(aflcc);
3364 add_lto_passes(aflcc);
3365
3366 }
3367
3368 } else {
3369
3370 if (aflcc->instrument_mode == INSTRUMENT_PCGUARD) {
3371
3372 add_optimized_pcguard(aflcc);
3373
3374 } else if (aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE) {
3375
3376 add_native_pcguard(aflcc);
3377
3378 } else {
3379
3380 load_llvm_pass(aflcc, "afl-llvm-pass.so");
3381
3382 }
3383
3384 }
3385
3386 if (aflcc->cmplog_mode) {
3387
3388 load_llvm_pass(aflcc, "cmplog-instructions-pass.so");
3389 load_llvm_pass(aflcc, "cmplog-routines-pass.so");
3390
3391 }
3392
3393 if (getenv("AFL_LLVM_INJECTIONS_ALL") ||
3394 getenv("AFL_LLVM_INJECTIONS_SQL") ||
3395 getenv("AFL_LLVM_INJECTIONS_LDAP") ||
3396 getenv("AFL_LLVM_INJECTIONS_XSS")) {
3397
3398 load_llvm_pass(aflcc, "injection-pass.so");
3399
3400 }
3401
3402 // insert_param(aflcc, "-Qunused-arguments");
3403
3404 }
3405
3406 /* Inspect the command line parameters. */
3407
3408 process_params(aflcc, 0, argc, argv);
3409
3410 add_sanitizers(aflcc, envp);
3411
3412 add_misc_params(aflcc);
3413
3414 add_defs_common(aflcc);
3415 add_defs_selective_instr(aflcc);
3416 add_defs_persistent_mode(aflcc);
3417
3418 add_runtime(aflcc);
3419
3420 insert_param(aflcc, NULL);
3421
3422 }
3423
3424 /* Main entry point */
main(int argc,char ** argv,char ** envp)3425 int main(int argc, char **argv, char **envp) {
3426
3427 aflcc_state_t *aflcc = malloc(sizeof(aflcc_state_t));
3428 aflcc_state_init(aflcc, (u8 *)argv[0]);
3429
3430 check_environment_vars(envp);
3431
3432 find_built_deps(aflcc);
3433
3434 compiler_mode_by_callname(aflcc);
3435 compiler_mode_by_environ(aflcc);
3436 compiler_mode_by_cmdline(aflcc, argc, argv);
3437
3438 instrument_mode_by_environ(aflcc);
3439
3440 mode_final_checkout(aflcc, argc, argv);
3441
3442 process_params(aflcc, 1, argc, argv);
3443
3444 maybe_usage(aflcc, argc, argv);
3445
3446 mode_notification(aflcc);
3447
3448 if (aflcc->debug) debugf_args(argc, argv);
3449
3450 edit_params(aflcc, argc, argv, envp);
3451
3452 if (aflcc->debug)
3453 debugf_args((s32)aflcc->cc_par_cnt, (char **)aflcc->cc_params);
3454
3455 if (aflcc->passthrough) {
3456
3457 argv[0] = aflcc->cc_params[0];
3458 execvp(aflcc->cc_params[0], (char **)argv);
3459
3460 } else {
3461
3462 execvp(aflcc->cc_params[0], (char **)aflcc->cc_params);
3463
3464 }
3465
3466 FATAL("Oops, failed to execute '%s' - check your PATH", aflcc->cc_params[0]);
3467
3468 return 0;
3469
3470 }
3471
3472