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