1 /*
2 american fuzzy lop++ - map display utility
3 ------------------------------------------
4
5 Originally written by Michal Zalewski
6
7 Forkserver design by Jann Horn <jannhorn@googlemail.com>
8
9 Now maintained by Marc Heuse <mh@mh-sec.de>,
10 Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
11 Andrea Fioraldi <andreafioraldi@gmail.com> and
12 Dominik Maier <mail@dmnk.co>
13
14 Copyright 2016, 2017 Google Inc. All rights reserved.
15 Copyright 2019-2022 AFLplusplus Project. All rights reserved.
16
17 Licensed under the Apache License, Version 2.0 (the "License");
18 you may not use this file except in compliance with the License.
19 You may obtain a copy of the License at:
20
21 https://www.apache.org/licenses/LICENSE-2.0
22
23 A very simple tool that runs the targeted binary and displays
24 the contents of the trace bitmap in a human-readable form. Useful in
25 scripts to eliminate redundant inputs and perform other checks.
26
27 Exit code is 2 if the target program crashes; 1 if it times out or
28 there is a problem executing it; or 0 if execution is successful.
29
30 */
31
32 #define AFL_MAIN
33
34 #include "config.h"
35 #include "types.h"
36 #include "debug.h"
37 #include "alloc-inl.h"
38 #include "hash.h"
39 #include "sharedmem.h"
40 #include "forkserver.h"
41 #include "common.h"
42 #include "hash.h"
43
44 #include <stdio.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <time.h>
49 #include <errno.h>
50 #include <signal.h>
51 #include <dirent.h>
52 #include <fcntl.h>
53 #include <limits.h>
54
55 #include <dirent.h>
56 #include <sys/wait.h>
57 #include <sys/time.h>
58 #ifndef USEMMAP
59 #include <sys/shm.h>
60 #endif
61 #include <sys/stat.h>
62 #include <sys/types.h>
63 #include <sys/resource.h>
64
65 static char *stdin_file; /* stdin file */
66
67 static u8 *in_dir = NULL, /* input folder */
68 *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */
69
70 static u8 outfile[PATH_MAX];
71
72 static u8 *in_data, /* Input data */
73 *coverage_map; /* Coverage map */
74
75 static u64 total; /* tuple content information */
76 static u32 tcnt, highest; /* tuple content information */
77
78 static u32 in_len; /* Input data length */
79
80 static u32 map_size = MAP_SIZE, timed_out = 0;
81
82 static bool quiet_mode, /* Hide non-essential messages? */
83 edges_only, /* Ignore hit counts? */
84 raw_instr_output, /* Do not apply AFL filters */
85 cmin_mode, /* Generate output in afl-cmin mode? */
86 binary_mode, /* Write output as a binary map */
87 keep_cores, /* Allow coredumps? */
88 remove_shm = true, /* remove shmem? */
89 collect_coverage, /* collect coverage */
90 have_coverage, /* have coverage? */
91 no_classify, /* do not classify counts */
92 debug, /* debug mode */
93 print_filenames, /* print the current filename */
94 wait_for_gdb;
95
96 static volatile u8 stop_soon, /* Ctrl-C pressed? */
97 child_crashed; /* Child crashed? */
98
99 static sharedmem_t shm;
100 static afl_forkserver_t *fsrv;
101 static sharedmem_t * shm_fuzz;
102
103 /* Classify tuple counts. Instead of mapping to individual bits, as in
104 afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
105
106 static const u8 count_class_human[256] = {
107
108 [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4,
109 [8] = 5, [16] = 6, [32] = 7, [128] = 8
110
111 };
112
113 static const u8 count_class_binary[256] = {
114
115 [0] = 0,
116 [1] = 1,
117 [2] = 2,
118 [3] = 4,
119 [4 ... 7] = 8,
120 [8 ... 15] = 16,
121 [16 ... 31] = 32,
122 [32 ... 127] = 64,
123 [128 ... 255] = 128
124
125 };
126
kill_child()127 static void kill_child() {
128
129 timed_out = 1;
130 if (fsrv->child_pid > 0) {
131
132 kill(fsrv->child_pid, fsrv->kill_signal);
133 fsrv->child_pid = -1;
134
135 }
136
137 }
138
classify_counts(afl_forkserver_t * fsrv)139 static void classify_counts(afl_forkserver_t *fsrv) {
140
141 u8 * mem = fsrv->trace_bits;
142 const u8 *map = binary_mode ? count_class_binary : count_class_human;
143
144 u32 i = map_size;
145
146 if (edges_only) {
147
148 while (i--) {
149
150 if (*mem) { *mem = 1; }
151 mem++;
152
153 }
154
155 } else if (!raw_instr_output) {
156
157 while (i--) {
158
159 *mem = map[*mem];
160 mem++;
161
162 }
163
164 }
165
166 }
167
deinit_shmem(afl_forkserver_t * fsrv,sharedmem_t * shm_fuzz)168 static sharedmem_t *deinit_shmem(afl_forkserver_t *fsrv,
169 sharedmem_t * shm_fuzz) {
170
171 afl_shm_deinit(shm_fuzz);
172 fsrv->support_shmem_fuzz = 0;
173 fsrv->shmem_fuzz_len = NULL;
174 fsrv->shmem_fuzz = NULL;
175 ck_free(shm_fuzz);
176 return NULL;
177
178 }
179
180 /* Get rid of temp files (atexit handler). */
181
at_exit_handler(void)182 static void at_exit_handler(void) {
183
184 if (stdin_file) { unlink(stdin_file); }
185
186 if (remove_shm) {
187
188 if (shm.map) afl_shm_deinit(&shm);
189 if (fsrv->use_shmem_fuzz) deinit_shmem(fsrv, shm_fuzz);
190
191 }
192
193 afl_fsrv_killall();
194
195 }
196
197 /* Analyze results. */
198
analyze_results(afl_forkserver_t * fsrv)199 static void analyze_results(afl_forkserver_t *fsrv) {
200
201 u32 i;
202 for (i = 0; i < map_size; i++) {
203
204 if (fsrv->trace_bits[i]) {
205
206 total += fsrv->trace_bits[i];
207 if (fsrv->trace_bits[i] > highest) highest = fsrv->trace_bits[i];
208 if (!coverage_map[i]) { coverage_map[i] = 1; }
209
210 }
211
212 }
213
214 }
215
216 /* Write results. */
217
write_results_to_file(afl_forkserver_t * fsrv,u8 * outfile)218 static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
219
220 s32 fd;
221 u32 i, ret = 0;
222
223 u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"),
224 caa = !!getenv("AFL_CMIN_ALLOW_ANY");
225
226 if (!outfile || !*outfile) {
227
228 FATAL("Output filename not set (Bug in AFL++?)");
229
230 }
231
232 if (cmin_mode &&
233 (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) {
234
235 if (strcmp(outfile, "-")) {
236
237 // create empty file to prevent error messages in afl-cmin
238 fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
239 close(fd);
240
241 }
242
243 return ret;
244
245 }
246
247 if (!strncmp(outfile, "/dev/", 5)) {
248
249 fd = open(outfile, O_WRONLY);
250
251 if (fd < 0) { PFATAL("Unable to open '%s'", out_file); }
252
253 } else if (!strcmp(outfile, "-")) {
254
255 fd = dup(1);
256 if (fd < 0) { PFATAL("Unable to open stdout"); }
257
258 } else {
259
260 unlink(outfile); /* Ignore errors */
261 fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
262 if (fd < 0) { PFATAL("Unable to create '%s'", outfile); }
263
264 }
265
266 if (binary_mode) {
267
268 for (i = 0; i < map_size; i++) {
269
270 if (fsrv->trace_bits[i]) { ret++; }
271
272 }
273
274 ck_write(fd, fsrv->trace_bits, map_size, outfile);
275 close(fd);
276
277 } else {
278
279 FILE *f = fdopen(fd, "w");
280
281 if (!f) { PFATAL("fdopen() failed"); }
282
283 for (i = 0; i < map_size; i++) {
284
285 if (!fsrv->trace_bits[i]) { continue; }
286 ret++;
287
288 total += fsrv->trace_bits[i];
289 if (highest < fsrv->trace_bits[i]) { highest = fsrv->trace_bits[i]; }
290
291 if (cmin_mode) {
292
293 fprintf(f, "%u%u\n", fsrv->trace_bits[i], i);
294
295 } else {
296
297 fprintf(f, "%06u:%u\n", i, fsrv->trace_bits[i]);
298
299 }
300
301 }
302
303 fclose(f);
304
305 }
306
307 return ret;
308
309 }
310
311 /* Execute target application. */
312
showmap_run_target_forkserver(afl_forkserver_t * fsrv,u8 * mem,u32 len)313 static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
314 u32 len) {
315
316 afl_fsrv_write_to_testcase(fsrv, mem, len);
317
318 if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); }
319
320 if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon) ==
321 FSRV_RUN_ERROR) {
322
323 FATAL("Error running target");
324
325 }
326
327 if (fsrv->trace_bits[0] == 1) {
328
329 fsrv->trace_bits[0] = 0;
330 have_coverage = true;
331
332 } else {
333
334 have_coverage = false;
335
336 }
337
338 if (!no_classify) { classify_counts(fsrv); }
339
340 if (!quiet_mode) { SAYF(cRST "-- Program output ends --\n"); }
341
342 if (!fsrv->last_run_timed_out && !stop_soon &&
343 WIFSIGNALED(fsrv->child_status)) {
344
345 child_crashed = true;
346
347 } else {
348
349 child_crashed = false;
350
351 }
352
353 if (!quiet_mode) {
354
355 if (timed_out || fsrv->last_run_timed_out) {
356
357 SAYF(cLRD "\n+++ Program timed off +++\n" cRST);
358 timed_out = 0;
359
360 } else if (stop_soon) {
361
362 SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST);
363
364 } else if (child_crashed) {
365
366 SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST,
367 WTERMSIG(fsrv->child_status));
368
369 }
370
371 }
372
373 if (stop_soon) {
374
375 SAYF(cRST cLRD "\n+++ afl-showmap folder mode aborted by user +++\n" cRST);
376 exit(1);
377
378 }
379
380 }
381
382 /* Read initial file. */
383
read_file(u8 * in_file)384 static u32 read_file(u8 *in_file) {
385
386 if (print_filenames) {
387
388 SAYF("Processing %s\n", in_file);
389 fflush(stdout);
390
391 }
392
393 struct stat st;
394 s32 fd = open(in_file, O_RDONLY);
395
396 if (fd < 0) { WARNF("Unable to open '%s'", in_file); }
397
398 if (fstat(fd, &st) || !st.st_size) {
399
400 if (!be_quiet && !quiet_mode) {
401
402 WARNF("Zero-sized input file '%s'.", in_file);
403
404 }
405
406 }
407
408 if (st.st_size > MAX_FILE) {
409
410 if (!be_quiet && !quiet_mode) {
411
412 WARNF("Input file '%s' is too large, only reading %ld bytes.", in_file,
413 MAX_FILE);
414
415 }
416
417 in_len = MAX_FILE;
418
419 } else {
420
421 in_len = st.st_size;
422
423 }
424
425 in_data = ck_alloc_nozero(in_len);
426
427 ck_read(fd, in_data, in_len, in_file);
428
429 close(fd);
430
431 // OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
432
433 return in_len;
434
435 }
436
437 /* Execute target application. */
438
showmap_run_target(afl_forkserver_t * fsrv,char ** argv)439 static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
440
441 static struct itimerval it;
442 int status = 0;
443
444 if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); }
445
446 MEM_BARRIER();
447
448 fsrv->child_pid = fork();
449
450 if (fsrv->child_pid < 0) { PFATAL("fork() failed"); }
451
452 if (!fsrv->child_pid) {
453
454 struct rlimit r;
455
456 if (quiet_mode) {
457
458 s32 fd = open("/dev/null", O_RDWR);
459
460 if (fd < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) {
461
462 *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
463 PFATAL("Descriptor initialization failed");
464
465 }
466
467 close(fd);
468
469 }
470
471 if (fsrv->mem_limit) {
472
473 r.rlim_max = r.rlim_cur = ((rlim_t)fsrv->mem_limit) << 20;
474
475 #ifdef RLIMIT_AS
476
477 setrlimit(RLIMIT_AS, &r); /* Ignore errors */
478
479 #else
480
481 setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
482
483 #endif /* ^RLIMIT_AS */
484
485 }
486
487 if (!keep_cores) {
488
489 r.rlim_max = r.rlim_cur = 0;
490
491 } else {
492
493 r.rlim_max = r.rlim_cur = RLIM_INFINITY;
494
495 }
496
497 setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
498
499 if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 0); }
500
501 setsid();
502
503 execv(fsrv->target_path, argv);
504
505 *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
506 exit(0);
507
508 }
509
510 /* Configure timeout, wait for child, cancel timeout. */
511
512 if (fsrv->exec_tmout) {
513
514 fsrv->last_run_timed_out = 0;
515 it.it_value.tv_sec = (fsrv->exec_tmout / 1000);
516 it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000;
517
518 }
519
520 signal(SIGALRM, kill_child);
521
522 setitimer(ITIMER_REAL, &it, NULL);
523
524 if (waitpid(fsrv->child_pid, &status, 0) <= 0) { FATAL("waitpid() failed"); }
525
526 fsrv->child_pid = 0;
527 it.it_value.tv_sec = 0;
528 it.it_value.tv_usec = 0;
529 setitimer(ITIMER_REAL, &it, NULL);
530
531 MEM_BARRIER();
532
533 /* Clean up bitmap, analyze exit condition, etc. */
534
535 if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) {
536
537 FATAL("Unable to execute '%s'", argv[0]);
538
539 }
540
541 if (fsrv->trace_bits[0] == 1) {
542
543 fsrv->trace_bits[0] = 0;
544 have_coverage = true;
545
546 } else {
547
548 have_coverage = false;
549
550 }
551
552 if (!no_classify) { classify_counts(fsrv); }
553
554 if (!quiet_mode) { SAYF(cRST "-- Program output ends --\n"); }
555
556 if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) {
557
558 child_crashed = true;
559
560 }
561
562 if (!quiet_mode) {
563
564 if (timed_out || fsrv->last_run_timed_out) {
565
566 SAYF(cLRD "\n+++ Program timed off +++\n" cRST);
567 timed_out = 0;
568
569 } else if (stop_soon) {
570
571 SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST);
572
573 } else if (child_crashed) {
574
575 SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST,
576 WTERMSIG(status));
577
578 }
579
580 }
581
582 }
583
584 /* Handle Ctrl-C and the like. */
585
handle_stop_sig(int sig)586 static void handle_stop_sig(int sig) {
587
588 (void)sig;
589 stop_soon = true;
590 afl_fsrv_killall();
591
592 }
593
594 /* Do basic preparations - persistent fds, filenames, etc. */
595
set_up_environment(afl_forkserver_t * fsrv,char ** argv)596 static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
597
598 char *afl_preload;
599 char *frida_afl_preload = NULL;
600 setenv("ASAN_OPTIONS",
601 "abort_on_error=1:"
602 "detect_leaks=0:"
603 "allocator_may_return_null=1:"
604 "symbolize=0:"
605 "detect_odr_violation=0:"
606 "handle_segv=0:"
607 "handle_sigbus=0:"
608 "handle_abort=0:"
609 "handle_sigfpe=0:"
610 "handle_sigill=0",
611 0);
612
613 setenv("LSAN_OPTIONS",
614 "exitcode=" STRINGIFY(LSAN_ERROR) ":"
615 "fast_unwind_on_malloc=0:"
616 "symbolize=0:"
617 "print_suppressions=0",
618 0);
619
620 setenv("UBSAN_OPTIONS",
621 "halt_on_error=1:"
622 "abort_on_error=1:"
623 "malloc_context_size=0:"
624 "allocator_may_return_null=1:"
625 "symbolize=0:"
626 "handle_segv=0:"
627 "handle_sigbus=0:"
628 "handle_abort=0:"
629 "handle_sigfpe=0:"
630 "handle_sigill=0",
631 0);
632
633 setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
634 "abort_on_error=1:"
635 "msan_track_origins=0"
636 "allocator_may_return_null=1:"
637 "symbolize=0:"
638 "handle_segv=0:"
639 "handle_sigbus=0:"
640 "handle_abort=0:"
641 "handle_sigfpe=0:"
642 "handle_sigill=0", 0);
643
644 if (get_afl_env("AFL_PRELOAD")) {
645
646 if (fsrv->qemu_mode) {
647
648 /* afl-qemu-trace takes care of converting AFL_PRELOAD. */
649
650 } else if (fsrv->frida_mode) {
651
652 afl_preload = getenv("AFL_PRELOAD");
653 u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
654 if (afl_preload) {
655
656 frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);
657
658 } else {
659
660 frida_afl_preload = alloc_printf("%s", frida_binary);
661
662 }
663
664 ck_free(frida_binary);
665
666 setenv("LD_PRELOAD", frida_afl_preload, 1);
667 setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
668
669 } else {
670
671 /* CoreSight mode uses the default behavior. */
672
673 setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
674 setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
675
676 }
677
678 } else if (fsrv->frida_mode) {
679
680 u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
681 setenv("LD_PRELOAD", frida_binary, 1);
682 setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
683 ck_free(frida_binary);
684
685 }
686
687 if (frida_afl_preload) { ck_free(frida_afl_preload); }
688
689 }
690
691 /* Setup signal handlers, duh. */
692
setup_signal_handlers(void)693 static void setup_signal_handlers(void) {
694
695 struct sigaction sa;
696
697 sa.sa_handler = NULL;
698 sa.sa_flags = SA_RESTART;
699 sa.sa_sigaction = NULL;
700
701 sigemptyset(&sa.sa_mask);
702
703 /* Various ways of saying "stop". */
704
705 sa.sa_handler = handle_stop_sig;
706 sigaction(SIGHUP, &sa, NULL);
707 sigaction(SIGINT, &sa, NULL);
708 sigaction(SIGTERM, &sa, NULL);
709
710 }
711
execute_testcases(u8 * dir)712 u32 execute_testcases(u8 *dir) {
713
714 struct dirent **nl;
715 s32 nl_cnt, subdirs = 1;
716 u32 i, done = 0;
717 u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
718
719 if (!be_quiet) { ACTF("Scanning '%s'...", dir); }
720
721 /* We use scandir() + alphasort() rather than readdir() because otherwise,
722 the ordering of test cases would vary somewhat randomly and would be
723 difficult to control. */
724
725 nl_cnt = scandir(dir, &nl, NULL, alphasort);
726
727 if (nl_cnt < 0) { return 0; }
728
729 for (i = 0; i < (u32)nl_cnt; ++i) {
730
731 struct stat st;
732
733 u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name);
734
735 if (lstat(fn2, &st) || access(fn2, R_OK)) {
736
737 PFATAL("Unable to access '%s'", fn2);
738
739 }
740
741 /* obviously we want to skip "descending" into . and .. directories,
742 however it is a good idea to skip also directories that start with
743 a dot */
744 if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') {
745
746 free(nl[i]); /* not tracked */
747 done += execute_testcases(fn2);
748 ck_free(fn2);
749 continue;
750
751 }
752
753 if (!S_ISREG(st.st_mode) || !st.st_size) {
754
755 free(nl[i]);
756 ck_free(fn2);
757 continue;
758
759 }
760
761 if (st.st_size > MAX_FILE && !be_quiet && !quiet_mode) {
762
763 WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2,
764 stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
765 stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
766
767 }
768
769 if (!collect_coverage)
770 snprintf(outfile, sizeof(outfile), "%s/%s", out_file, nl[i]->d_name);
771
772 free(nl[i]);
773
774 if (read_file(fn2)) {
775
776 if (wait_for_gdb) {
777
778 fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid);
779 fprintf(stderr, "exec: kill -CONT %d\n", getpid());
780 kill(0, SIGSTOP);
781
782 }
783
784 showmap_run_target_forkserver(fsrv, in_data, in_len);
785 ck_free(in_data);
786 ++done;
787
788 if (collect_coverage)
789 analyze_results(fsrv);
790 else
791 tcnt = write_results_to_file(fsrv, outfile);
792
793 }
794
795 }
796
797 free(nl); /* not tracked */
798 return done;
799
800 }
801
802 /* Show banner. */
803
show_banner(void)804 static void show_banner(void) {
805
806 SAYF(cCYA "afl-showmap" VERSION cRST " by Michal Zalewski\n");
807
808 }
809
810 /* Display usage hints. */
811
usage(u8 * argv0)812 static void usage(u8 *argv0) {
813
814 show_banner();
815
816 SAYF(
817 "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
818
819 "Required parameters:\n"
820 " -o file - file to write the trace data to\n\n"
821
822 "Execution control settings:\n"
823 " -t msec - timeout for each run (none)\n"
824 " -m megs - memory limit for child process (%u MB)\n"
825 #if defined(__linux__) && defined(__aarch64__)
826 " -A - use binary-only instrumentation (ARM CoreSight mode)\n"
827 #endif
828 " -O - use binary-only instrumentation (FRIDA mode)\n"
829 #if defined(__linux__)
830 " -Q - use binary-only instrumentation (QEMU mode)\n"
831 " -U - use Unicorn-based instrumentation (Unicorn mode)\n"
832 " -W - use qemu-based instrumentation with Wine (Wine mode)\n"
833 " (Not necessary, here for consistency with other afl-* "
834 "tools)\n"
835 #endif
836 "\n"
837 "Other settings:\n"
838 " -i dir - process all files below this directory, must be combined "
839 "with -o.\n"
840 " With -C, -o is a file, without -C it must be a "
841 "directory\n"
842 " and each bitmap will be written there individually.\n"
843 " -C - collect coverage, writes all edges to -o and gives a "
844 "summary\n"
845 " Must be combined with -i.\n"
846 " -q - sink program's output and don't show messages\n"
847 " -e - show edge coverage only, ignore hit counts\n"
848 " -r - show real tuple values instead of AFL filter values\n"
849 " -s - do not classify the map\n"
850 " -c - allow core dumps\n\n"
851
852 "This tool displays raw tuple data captured by AFL instrumentation.\n"
853 "For additional help, consult %s/README.md.\n\n"
854
855 "Environment variables used:\n"
856 "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
857 "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
858 "inputs\n"
859 "AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n"
860 "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as "
861 "crash\n"
862 "AFL_DEBUG: enable extra developer output\n"
863 "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during "
864 "startup (in milliseconds)\n"
865 "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, "
866 "etc. (default: SIGKILL)\n"
867 "AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
868 "size the target was compiled for\n"
869 "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
870 "AFL_PRINT_FILENAMES: If set, the filename currently processed will be "
871 "printed to stdout\n"
872 "AFL_QUIET: do not print extra informational output\n"
873 "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n",
874 argv0, MEM_LIMIT, doc_path);
875
876 exit(1);
877
878 }
879
880 /* Main entry point */
881
main(int argc,char ** argv_orig,char ** envp)882 int main(int argc, char **argv_orig, char **envp) {
883
884 // TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
885
886 s32 opt, i;
887 bool mem_limit_given = false, timeout_given = false, unicorn_mode = false,
888 use_wine = false;
889 char **use_argv;
890
891 char **argv = argv_cpy_dup(argc, argv_orig);
892
893 afl_forkserver_t fsrv_var = {0};
894 if (getenv("AFL_DEBUG")) { debug = true; }
895 if (get_afl_env("AFL_PRINT_FILENAMES")) { print_filenames = true; }
896
897 fsrv = &fsrv_var;
898 afl_fsrv_init(fsrv);
899 map_size = get_map_size();
900 fsrv->map_size = map_size;
901
902 doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
903
904 if (getenv("AFL_QUIET") != NULL) { be_quiet = true; }
905
906 while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrsh")) > 0) {
907
908 switch (opt) {
909
910 case 's':
911 no_classify = true;
912 break;
913
914 case 'C':
915 collect_coverage = true;
916 quiet_mode = true;
917 break;
918
919 case 'i':
920 if (in_dir) { FATAL("Multiple -i options not supported"); }
921 in_dir = optarg;
922 break;
923
924 case 'o':
925
926 if (out_file) { FATAL("Multiple -o options not supported"); }
927 out_file = optarg;
928 break;
929
930 case 'm': {
931
932 u8 suffix = 'M';
933
934 if (mem_limit_given) { FATAL("Multiple -m options not supported"); }
935 mem_limit_given = true;
936
937 if (!optarg) { FATAL("Wrong usage of -m"); }
938
939 if (!strcmp(optarg, "none")) {
940
941 fsrv->mem_limit = 0;
942 break;
943
944 }
945
946 if (sscanf(optarg, "%llu%c", &fsrv->mem_limit, &suffix) < 1 ||
947 optarg[0] == '-') {
948
949 FATAL("Bad syntax used for -m");
950
951 }
952
953 switch (suffix) {
954
955 case 'T':
956 fsrv->mem_limit *= 1024 * 1024;
957 break;
958 case 'G':
959 fsrv->mem_limit *= 1024;
960 break;
961 case 'k':
962 fsrv->mem_limit /= 1024;
963 break;
964 case 'M':
965 break;
966
967 default:
968 FATAL("Unsupported suffix or bad syntax for -m");
969
970 }
971
972 if (fsrv->mem_limit < 5) { FATAL("Dangerously low value of -m"); }
973
974 if (sizeof(rlim_t) == 4 && fsrv->mem_limit > 2000) {
975
976 FATAL("Value of -m out of range on 32-bit systems");
977
978 }
979
980 }
981
982 break;
983
984 case 'f': // only in here to avoid a compiler warning for use_stdin
985
986 FATAL("Option -f is not supported in afl-showmap");
987 // currently not reached:
988 fsrv->use_stdin = 0;
989 fsrv->out_file = strdup(optarg);
990
991 break;
992
993 case 't':
994
995 if (timeout_given) { FATAL("Multiple -t options not supported"); }
996 timeout_given = true;
997
998 if (!optarg) { FATAL("Wrong usage of -t"); }
999
1000 if (strcmp(optarg, "none")) {
1001
1002 fsrv->exec_tmout = atoi(optarg);
1003
1004 if (fsrv->exec_tmout < 20 || optarg[0] == '-') {
1005
1006 FATAL("Dangerously low value of -t");
1007
1008 }
1009
1010 }
1011
1012 break;
1013
1014 case 'e':
1015
1016 if (edges_only) { FATAL("Multiple -e options not supported"); }
1017 if (raw_instr_output) { FATAL("-e and -r are mutually exclusive"); }
1018 edges_only = true;
1019 break;
1020
1021 case 'q':
1022
1023 quiet_mode = true;
1024 break;
1025
1026 case 'Z':
1027
1028 /* This is an undocumented option to write data in the syntax expected
1029 by afl-cmin. Nobody else should have any use for this. */
1030
1031 cmin_mode = true;
1032 quiet_mode = true;
1033 break;
1034
1035 case 'H':
1036 /* Another afl-cmin specific feature. */
1037 at_file = optarg;
1038 break;
1039
1040 case 'O': /* FRIDA mode */
1041
1042 if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
1043
1044 fsrv->frida_mode = true;
1045 setenv("AFL_FRIDA_INST_SEED", "1", 1);
1046
1047 break;
1048
1049 /* FIXME: We want to use -P for consistency, but it is already unsed for
1050 * undocumenetd feature "Another afl-cmin specific feature." */
1051 case 'A': /* CoreSight mode */
1052
1053 #if !defined(__aarch64__) || !defined(__linux__)
1054 FATAL("-A option is not supported on this platform");
1055 #endif
1056
1057 if (fsrv->cs_mode) { FATAL("Multiple -A options not supported"); }
1058
1059 fsrv->cs_mode = true;
1060 break;
1061
1062 case 'Q':
1063
1064 if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
1065
1066 fsrv->qemu_mode = true;
1067 break;
1068
1069 case 'U':
1070
1071 if (unicorn_mode) { FATAL("Multiple -U options not supported"); }
1072
1073 unicorn_mode = true;
1074 break;
1075
1076 case 'W': /* Wine+QEMU mode */
1077
1078 if (use_wine) { FATAL("Multiple -W options not supported"); }
1079 fsrv->qemu_mode = true;
1080 use_wine = true;
1081
1082 break;
1083
1084 case 'b':
1085
1086 /* Secret undocumented mode. Writes output in raw binary format
1087 similar to that dumped by afl-fuzz in <out_dir/queue/fuzz_bitmap. */
1088
1089 binary_mode = true;
1090 break;
1091
1092 case 'c':
1093
1094 if (keep_cores) { FATAL("Multiple -c options not supported"); }
1095 keep_cores = true;
1096 break;
1097
1098 case 'r':
1099
1100 if (raw_instr_output) { FATAL("Multiple -r options not supported"); }
1101 if (edges_only) { FATAL("-e and -r are mutually exclusive"); }
1102 raw_instr_output = true;
1103 break;
1104
1105 case 'h':
1106 usage(argv[0]);
1107 return -1;
1108 break;
1109
1110 default:
1111 usage(argv[0]);
1112
1113 }
1114
1115 }
1116
1117 if (optind == argc || !out_file) { usage(argv[0]); }
1118
1119 if (in_dir) {
1120
1121 if (!out_file && !collect_coverage)
1122 FATAL("for -i you need to specify either -C and/or -o");
1123
1124 }
1125
1126 if (fsrv->qemu_mode && !mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; }
1127 if (unicorn_mode && !mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; }
1128
1129 check_environment_vars(envp);
1130
1131 if (getenv("AFL_NO_FORKSRV")) { /* if set, use the fauxserver */
1132 fsrv->use_fauxsrv = true;
1133
1134 }
1135
1136 if (getenv("AFL_DEBUG")) {
1137
1138 DEBUGF("");
1139 for (i = 0; i < argc; i++)
1140 SAYF(" %s", argv[i]);
1141 SAYF("\n");
1142
1143 }
1144
1145 // if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); }
1146
1147 setenv("AFL_NO_AUTODICT", "1", 1);
1148
1149 /* initialize cmplog_mode */
1150 shm.cmplog_mode = 0;
1151 setup_signal_handlers();
1152
1153 set_up_environment(fsrv, argv);
1154
1155 fsrv->target_path = find_binary(argv[optind]);
1156 fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
1157
1158 if (!quiet_mode) {
1159
1160 show_banner();
1161 ACTF("Executing '%s'...", fsrv->target_path);
1162
1163 }
1164
1165 if (in_dir) {
1166
1167 /* If we don't have a file name chosen yet, use a safe default. */
1168 u8 *use_dir = ".";
1169
1170 if (access(use_dir, R_OK | W_OK | X_OK)) {
1171
1172 use_dir = get_afl_env("TMPDIR");
1173 if (!use_dir) { use_dir = "/tmp"; }
1174
1175 }
1176
1177 stdin_file = at_file ? strdup(at_file)
1178 : (char *)alloc_printf("%s/.afl-showmap-temp-%u",
1179 use_dir, (u32)getpid());
1180 unlink(stdin_file);
1181
1182 // If @@ are in the target args, replace them and also set use_stdin=false.
1183 detect_file_args(argv + optind, stdin_file, &fsrv->use_stdin);
1184
1185 } else {
1186
1187 // If @@ are in the target args, replace them and also set use_stdin=false.
1188 detect_file_args(argv + optind, at_file, &fsrv->use_stdin);
1189
1190 }
1191
1192 if (fsrv->qemu_mode) {
1193
1194 if (use_wine) {
1195
1196 use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
1197 argv + optind);
1198
1199 } else {
1200
1201 use_argv = get_qemu_argv(argv[0], &fsrv->target_path, argc - optind,
1202 argv + optind);
1203
1204 }
1205
1206 } else if (fsrv->cs_mode) {
1207
1208 use_argv =
1209 get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
1210
1211 } else {
1212
1213 use_argv = argv + optind;
1214
1215 }
1216
1217 if (in_dir) { (void)check_binary_signatures(fsrv->target_path); }
1218
1219 shm_fuzz = ck_alloc(sizeof(sharedmem_t));
1220
1221 /* initialize cmplog_mode */
1222 shm_fuzz->cmplog_mode = 0;
1223 u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1);
1224 shm_fuzz->shmemfuzz_mode = true;
1225 if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
1226 #ifdef USEMMAP
1227 setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1);
1228 #else
1229 u8 *shm_str = alloc_printf("%d", shm_fuzz->shm_id);
1230 setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
1231 ck_free(shm_str);
1232 #endif
1233 fsrv->support_shmem_fuzz = true;
1234 fsrv->shmem_fuzz_len = (u32 *)map;
1235 fsrv->shmem_fuzz = map + sizeof(u32);
1236
1237 if (!fsrv->cs_mode && !fsrv->qemu_mode && !unicorn_mode) {
1238
1239 u32 save_be_quiet = be_quiet;
1240 be_quiet = !debug;
1241 fsrv->map_size = 4194304; // dummy temporary value
1242 u32 new_map_size =
1243 afl_fsrv_get_mapsize(fsrv, use_argv, &stop_soon,
1244 (get_afl_env("AFL_DEBUG_CHILD") ||
1245 get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
1246 ? 1
1247 : 0);
1248 be_quiet = save_be_quiet;
1249
1250 fsrv->kill_signal =
1251 parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL);
1252
1253 if (new_map_size) {
1254
1255 // only reinitialize when it makes sense
1256 if (map_size < new_map_size ||
1257 (new_map_size > map_size && new_map_size - map_size > MAP_SIZE)) {
1258
1259 if (!be_quiet)
1260 ACTF("Aquired new map size for target: %u bytes\n", new_map_size);
1261
1262 afl_shm_deinit(&shm);
1263 afl_fsrv_kill(fsrv);
1264 fsrv->map_size = new_map_size;
1265 fsrv->trace_bits = afl_shm_init(&shm, new_map_size, 0);
1266
1267 }
1268
1269 map_size = new_map_size;
1270
1271 }
1272
1273 fsrv->map_size = map_size;
1274
1275 }
1276
1277 if (in_dir) {
1278
1279 DIR *dir_in, *dir_out = NULL;
1280
1281 if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true;
1282
1283 fsrv->dev_null_fd = open("/dev/null", O_RDWR);
1284 if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
1285
1286 // if a queue subdirectory exists switch to that
1287 u8 *dn = alloc_printf("%s/queue", in_dir);
1288 if ((dir_in = opendir(dn)) != NULL) {
1289
1290 closedir(dir_in);
1291 in_dir = dn;
1292
1293 } else
1294
1295 ck_free(dn);
1296 if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
1297
1298 if (!collect_coverage) {
1299
1300 if (!(dir_out = opendir(out_file))) {
1301
1302 if (mkdir(out_file, 0700)) {
1303
1304 PFATAL("cannot create output directory %s", out_file);
1305
1306 }
1307
1308 }
1309
1310 } else {
1311
1312 if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL)
1313 FATAL("coult not grab memory");
1314 edges_only = false;
1315 raw_instr_output = true;
1316
1317 }
1318
1319 atexit(at_exit_handler);
1320 fsrv->out_file = stdin_file;
1321 fsrv->out_fd =
1322 open(stdin_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
1323 if (fsrv->out_fd < 0) { PFATAL("Unable to create '%s'", out_file); }
1324
1325 if (get_afl_env("AFL_DEBUG")) {
1326
1327 int j = optind;
1328 DEBUGF("%s:", fsrv->target_path);
1329 while (argv[j] != NULL) {
1330
1331 SAYF(" \"%s\"", argv[j++]);
1332
1333 }
1334
1335 SAYF("\n");
1336
1337 }
1338
1339 if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
1340
1341 s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
1342 if (forksrv_init_tmout < 1) {
1343
1344 FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
1345
1346 }
1347
1348 fsrv->init_tmout = (u32)forksrv_init_tmout;
1349
1350 }
1351
1352 if (getenv("AFL_CRASH_EXITCODE")) {
1353
1354 long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
1355 if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
1356 exitcode < -127 || exitcode > 128) {
1357
1358 FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
1359 getenv("AFL_CRASH_EXITCODE"));
1360
1361 }
1362
1363 fsrv->uses_crash_exitcode = true;
1364 // WEXITSTATUS is 8 bit unsigned
1365 fsrv->crash_exitcode = (u8)exitcode;
1366
1367 }
1368
1369 afl_fsrv_start(fsrv, use_argv, &stop_soon,
1370 (get_afl_env("AFL_DEBUG_CHILD") ||
1371 get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
1372 ? 1
1373 : 0);
1374
1375 map_size = fsrv->map_size;
1376
1377 if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
1378 shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
1379
1380 if (execute_testcases(in_dir) == 0) {
1381
1382 FATAL("could not read input testcases from %s", in_dir);
1383
1384 }
1385
1386 if (!quiet_mode) { OKF("Processed %llu input files.", fsrv->total_execs); }
1387
1388 if (dir_out) { closedir(dir_out); }
1389
1390 if (collect_coverage) {
1391
1392 memcpy(fsrv->trace_bits, coverage_map, map_size);
1393 tcnt = write_results_to_file(fsrv, out_file);
1394
1395 }
1396
1397 } else {
1398
1399 if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
1400 shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
1401
1402 showmap_run_target(fsrv, use_argv);
1403 tcnt = write_results_to_file(fsrv, out_file);
1404 if (!quiet_mode) {
1405
1406 OKF("Hash of coverage map: %llx",
1407 hash64(fsrv->trace_bits, fsrv->map_size, HASH_CONST));
1408
1409 }
1410
1411 }
1412
1413 if (!quiet_mode || collect_coverage) {
1414
1415 if (!tcnt && !have_coverage) { FATAL("No instrumentation detected" cRST); }
1416 OKF("Captured %u tuples (map size %u, highest value %u, total values %llu) "
1417 "in '%s'." cRST,
1418 tcnt, fsrv->real_map_size, highest, total, out_file);
1419 if (collect_coverage)
1420 OKF("A coverage of %u edges were achieved out of %u existing (%.02f%%) "
1421 "with %llu input files.",
1422 tcnt, map_size, ((float)tcnt * 100) / (float)map_size,
1423 fsrv->total_execs);
1424
1425 }
1426
1427 if (stdin_file) {
1428
1429 unlink(stdin_file);
1430 ck_free(stdin_file);
1431 stdin_file = NULL;
1432
1433 }
1434
1435 remove_shm = 0;
1436 afl_shm_deinit(&shm);
1437 if (fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
1438
1439 u32 ret;
1440
1441 if (cmin_mode && !!getenv("AFL_CMIN_CRASHES_ONLY")) {
1442
1443 ret = fsrv->last_run_timed_out;
1444
1445 } else {
1446
1447 ret = child_crashed * 2 + fsrv->last_run_timed_out;
1448
1449 }
1450
1451 if (fsrv->target_path) { ck_free(fsrv->target_path); }
1452
1453 afl_fsrv_deinit(fsrv);
1454
1455 if (stdin_file) { ck_free(stdin_file); }
1456 if (collect_coverage) { free(coverage_map); }
1457
1458 argv_cpy_free(argv);
1459 if (fsrv->qemu_mode) { free(use_argv[2]); }
1460
1461 exit(ret);
1462
1463 }
1464
1465