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