1 /*
2    american fuzzy lop - map display utility
3    ----------------------------------------
4 
5    Written and maintained by Michal Zalewski <lcamtuf@google.com>
6 
7    Copyright 2013, 2014, 2015, 2016, 2017 Google Inc. All rights reserved.
8 
9    Licensed under the Apache License, Version 2.0 (the "License");
10    you may not use this file except in compliance with the License.
11    You may obtain a copy of the License at:
12 
13      http://www.apache.org/licenses/LICENSE-2.0
14 
15    A very simple tool that runs the targeted binary and displays
16    the contents of the trace bitmap in a human-readable form. Useful in
17    scripts to eliminate redundant inputs and perform other checks.
18 
19    Exit code is 2 if the target program crashes; 1 if it times out or
20    there is a problem executing it; or 0 if execution is successful.
21 
22  */
23 
24 #define AFL_MAIN
25 
26 #include "config.h"
27 #include "types.h"
28 #include "debug.h"
29 #include "alloc-inl.h"
30 #include "hash.h"
31 
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include <errno.h>
38 #include <signal.h>
39 #include <dirent.h>
40 #include <fcntl.h>
41 
42 #include <sys/wait.h>
43 #include <sys/time.h>
44 #include <sys/shm.h>
45 #include <sys/stat.h>
46 #include <sys/types.h>
47 #include <sys/resource.h>
48 
49 static s32 child_pid;                 /* PID of the tested program         */
50 
51 static u8* trace_bits;                /* SHM with instrumentation bitmap   */
52 
53 static u8 *out_file,                  /* Trace output file                 */
54           *doc_path,                  /* Path to docs                      */
55           *target_path,               /* Path to target binary             */
56           *at_file;                   /* Substitution string for @@        */
57 
58 static u32 exec_tmout;                /* Exec timeout (ms)                 */
59 
60 static u64 mem_limit = MEM_LIMIT;     /* Memory limit (MB)                 */
61 
62 static s32 shm_id;                    /* ID of the SHM region              */
63 
64 static u8  quiet_mode,                /* Hide non-essential messages?      */
65            edges_only,                /* Ignore hit counts?                */
66            cmin_mode,                 /* Generate output in afl-cmin mode? */
67            binary_mode,               /* Write output as a binary map      */
68            keep_cores;                /* Allow coredumps?                  */
69 
70 static volatile u8
71            stop_soon,                 /* Ctrl-C pressed?                   */
72            child_timed_out,           /* Child timed out?                  */
73            child_crashed;             /* Child crashed?                    */
74 
75 /* Classify tuple counts. Instead of mapping to individual bits, as in
76    afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
77 
78 static const u8 count_class_human[256] = {
79 
80   [0]           = 0,
81   [1]           = 1,
82   [2]           = 2,
83   [3]           = 3,
84   [4 ... 7]     = 4,
85   [8 ... 15]    = 5,
86   [16 ... 31]   = 6,
87   [32 ... 127]  = 7,
88   [128 ... 255] = 8
89 
90 };
91 
92 static const u8 count_class_binary[256] = {
93 
94   [0]           = 0,
95   [1]           = 1,
96   [2]           = 2,
97   [3]           = 4,
98   [4 ... 7]     = 8,
99   [8 ... 15]    = 16,
100   [16 ... 31]   = 32,
101   [32 ... 127]  = 64,
102   [128 ... 255] = 128
103 
104 };
105 
classify_counts(u8 * mem,const u8 * map)106 static void classify_counts(u8* mem, const u8* map) {
107 
108   u32 i = MAP_SIZE;
109 
110   if (edges_only) {
111 
112     while (i--) {
113       if (*mem) *mem = 1;
114       mem++;
115     }
116 
117   } else {
118 
119     while (i--) {
120       *mem = map[*mem];
121       mem++;
122     }
123 
124   }
125 
126 }
127 
128 
129 /* Get rid of shared memory (atexit handler). */
130 
remove_shm(void)131 static void remove_shm(void) {
132 
133   shmctl(shm_id, IPC_RMID, NULL);
134 
135 }
136 
137 
138 /* Configure shared memory. */
139 
setup_shm(void)140 static void setup_shm(void) {
141 
142   u8* shm_str;
143 
144   shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
145 
146   if (shm_id < 0) PFATAL("shmget() failed");
147 
148   atexit(remove_shm);
149 
150   shm_str = alloc_printf("%d", shm_id);
151 
152   setenv(SHM_ENV_VAR, shm_str, 1);
153 
154   ck_free(shm_str);
155 
156   trace_bits = shmat(shm_id, NULL, 0);
157 
158   if (!trace_bits) PFATAL("shmat() failed");
159 
160 }
161 
162 /* Write results. */
163 
write_results(void)164 static u32 write_results(void) {
165 
166   s32 fd;
167   u32 i, ret = 0;
168 
169   u8  cco = !!getenv("AFL_CMIN_CRASHES_ONLY"),
170       caa = !!getenv("AFL_CMIN_ALLOW_ANY");
171 
172   if (!strncmp(out_file, "/dev/", 5)) {
173 
174     fd = open(out_file, O_WRONLY, 0600);
175     if (fd < 0) PFATAL("Unable to open '%s'", out_file);
176 
177   } else if (!strcmp(out_file, "-")) {
178 
179     fd = dup(1);
180     if (fd < 0) PFATAL("Unable to open stdout");
181 
182   } else {
183 
184     unlink(out_file); /* Ignore errors */
185     fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
186     if (fd < 0) PFATAL("Unable to create '%s'", out_file);
187 
188   }
189 
190 
191   if (binary_mode) {
192 
193     for (i = 0; i < MAP_SIZE; i++)
194       if (trace_bits[i]) ret++;
195 
196     ck_write(fd, trace_bits, MAP_SIZE, out_file);
197     close(fd);
198 
199   } else {
200 
201     FILE* f = fdopen(fd, "w");
202 
203     if (!f) PFATAL("fdopen() failed");
204 
205     for (i = 0; i < MAP_SIZE; i++) {
206 
207       if (!trace_bits[i]) continue;
208       ret++;
209 
210       if (cmin_mode) {
211 
212         if (child_timed_out) break;
213         if (!caa && child_crashed != cco) break;
214 
215         fprintf(f, "%u%u\n", trace_bits[i], i);
216 
217       } else fprintf(f, "%06u:%u\n", i, trace_bits[i]);
218 
219     }
220 
221     fclose(f);
222 
223   }
224 
225   return ret;
226 
227 }
228 
229 
230 /* Handle timeout signal. */
231 
handle_timeout(int sig)232 static void handle_timeout(int sig) {
233 
234   child_timed_out = 1;
235   if (child_pid > 0) kill(child_pid, SIGKILL);
236 
237 }
238 
239 
240 /* Execute target application. */
241 
run_target(char ** argv)242 static void run_target(char** argv) {
243 
244   static struct itimerval it;
245   int status = 0;
246 
247   if (!quiet_mode)
248     SAYF("-- Program output begins --\n" cRST);
249 
250   MEM_BARRIER();
251 
252   child_pid = fork();
253 
254   if (child_pid < 0) PFATAL("fork() failed");
255 
256   if (!child_pid) {
257 
258     struct rlimit r;
259 
260     if (quiet_mode) {
261 
262       s32 fd = open("/dev/null", O_RDWR);
263 
264       if (fd < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) {
265         *(u32*)trace_bits = EXEC_FAIL_SIG;
266         PFATAL("Descriptor initialization failed");
267       }
268 
269       close(fd);
270 
271     }
272 
273     if (mem_limit) {
274 
275       r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20;
276 
277 #ifdef RLIMIT_AS
278 
279       setrlimit(RLIMIT_AS, &r); /* Ignore errors */
280 
281 #else
282 
283       setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
284 
285 #endif /* ^RLIMIT_AS */
286 
287     }
288 
289     if (!keep_cores) r.rlim_max = r.rlim_cur = 0;
290     else r.rlim_max = r.rlim_cur = RLIM_INFINITY;
291 
292     setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
293 
294     if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0);
295 
296     setsid();
297 
298     execv(target_path, argv);
299 
300     *(u32*)trace_bits = EXEC_FAIL_SIG;
301     exit(0);
302 
303   }
304 
305   /* Configure timeout, wait for child, cancel timeout. */
306 
307   if (exec_tmout) {
308 
309     child_timed_out = 0;
310     it.it_value.tv_sec = (exec_tmout / 1000);
311     it.it_value.tv_usec = (exec_tmout % 1000) * 1000;
312 
313   }
314 
315   setitimer(ITIMER_REAL, &it, NULL);
316 
317   if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed");
318 
319   child_pid = 0;
320   it.it_value.tv_sec = 0;
321   it.it_value.tv_usec = 0;
322   setitimer(ITIMER_REAL, &it, NULL);
323 
324   MEM_BARRIER();
325 
326   /* Clean up bitmap, analyze exit condition, etc. */
327 
328   if (*(u32*)trace_bits == EXEC_FAIL_SIG)
329     FATAL("Unable to execute '%s'", argv[0]);
330 
331   classify_counts(trace_bits, binary_mode ?
332                   count_class_binary : count_class_human);
333 
334   if (!quiet_mode)
335     SAYF(cRST "-- Program output ends --\n");
336 
337   if (!child_timed_out && !stop_soon && WIFSIGNALED(status))
338     child_crashed = 1;
339 
340   if (!quiet_mode) {
341 
342     if (child_timed_out)
343       SAYF(cLRD "\n+++ Program timed off +++\n" cRST);
344     else if (stop_soon)
345       SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST);
346     else if (child_crashed)
347       SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST, WTERMSIG(status));
348 
349   }
350 
351 
352 }
353 
354 
355 /* Handle Ctrl-C and the like. */
356 
handle_stop_sig(int sig)357 static void handle_stop_sig(int sig) {
358 
359   stop_soon = 1;
360 
361   if (child_pid > 0) kill(child_pid, SIGKILL);
362 
363 }
364 
365 
366 /* Do basic preparations - persistent fds, filenames, etc. */
367 
set_up_environment(void)368 static void set_up_environment(void) {
369 
370   setenv("ASAN_OPTIONS", "abort_on_error=1:"
371                          "detect_leaks=0:"
372                          "symbolize=0:"
373                          "allocator_may_return_null=1", 0);
374 
375   setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
376                          "symbolize=0:"
377                          "abort_on_error=1:"
378                          "allocator_may_return_null=1:"
379                          "msan_track_origins=0", 0);
380 
381   if (getenv("AFL_PRELOAD")) {
382     setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
383     setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
384   }
385 
386 }
387 
388 
389 /* Setup signal handlers, duh. */
390 
setup_signal_handlers(void)391 static void setup_signal_handlers(void) {
392 
393   struct sigaction sa;
394 
395   sa.sa_handler   = NULL;
396   sa.sa_flags     = SA_RESTART;
397   sa.sa_sigaction = NULL;
398 
399   sigemptyset(&sa.sa_mask);
400 
401   /* Various ways of saying "stop". */
402 
403   sa.sa_handler = handle_stop_sig;
404   sigaction(SIGHUP, &sa, NULL);
405   sigaction(SIGINT, &sa, NULL);
406   sigaction(SIGTERM, &sa, NULL);
407 
408   /* Exec timeout notifications. */
409 
410   sa.sa_handler = handle_timeout;
411   sigaction(SIGALRM, &sa, NULL);
412 
413 }
414 
415 
416 /* Detect @@ in args. */
417 
detect_file_args(char ** argv)418 static void detect_file_args(char** argv) {
419 
420   u32 i = 0;
421   u8* cwd = getcwd(NULL, 0);
422 
423   if (!cwd) PFATAL("getcwd() failed");
424 
425   while (argv[i]) {
426 
427     u8* aa_loc = strstr(argv[i], "@@");
428 
429     if (aa_loc) {
430 
431       u8 *aa_subst, *n_arg;
432 
433       if (!at_file) FATAL("@@ syntax is not supported by this tool.");
434 
435       /* Be sure that we're always using fully-qualified paths. */
436 
437       if (at_file[0] == '/') aa_subst = at_file;
438       else aa_subst = alloc_printf("%s/%s", cwd, at_file);
439 
440       /* Construct a replacement argv value. */
441 
442       *aa_loc = 0;
443       n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
444       argv[i] = n_arg;
445       *aa_loc = '@';
446 
447       if (at_file[0] != '/') ck_free(aa_subst);
448 
449     }
450 
451     i++;
452 
453   }
454 
455   free(cwd); /* not tracked */
456 
457 }
458 
459 
460 /* Show banner. */
461 
show_banner(void)462 static void show_banner(void) {
463 
464   SAYF(cCYA "afl-showmap " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
465 
466 }
467 
468 /* Display usage hints. */
469 
usage(u8 * argv0)470 static void usage(u8* argv0) {
471 
472   show_banner();
473 
474   SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
475 
476        "Required parameters:\n\n"
477 
478        "  -o file       - file to write the trace data to\n\n"
479 
480        "Execution control settings:\n\n"
481 
482        "  -t msec       - timeout for each run (none)\n"
483        "  -m megs       - memory limit for child process (%u MB)\n"
484        "  -Q            - use binary-only instrumentation (QEMU mode)\n\n"
485 
486        "Other settings:\n\n"
487 
488        "  -q            - sink program's output and don't show messages\n"
489        "  -e            - show edge coverage only, ignore hit counts\n"
490        "  -c            - allow core dumps\n\n"
491 
492        "This tool displays raw tuple data captured by AFL instrumentation.\n"
493        "For additional help, consult %s/README.\n\n" cRST,
494 
495        argv0, MEM_LIMIT, doc_path);
496 
497   exit(1);
498 
499 }
500 
501 
502 /* Find binary. */
503 
find_binary(u8 * fname)504 static void find_binary(u8* fname) {
505 
506   u8* env_path = 0;
507   struct stat st;
508 
509   if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
510 
511     target_path = ck_strdup(fname);
512 
513     if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
514         !(st.st_mode & 0111) || st.st_size < 4)
515       FATAL("Program '%s' not found or not executable", fname);
516 
517   } else {
518 
519     while (env_path) {
520 
521       u8 *cur_elem, *delim = strchr(env_path, ':');
522 
523       if (delim) {
524 
525         cur_elem = ck_alloc(delim - env_path + 1);
526         memcpy(cur_elem, env_path, delim - env_path);
527         delim++;
528 
529       } else cur_elem = ck_strdup(env_path);
530 
531       env_path = delim;
532 
533       if (cur_elem[0])
534         target_path = alloc_printf("%s/%s", cur_elem, fname);
535       else
536         target_path = ck_strdup(fname);
537 
538       ck_free(cur_elem);
539 
540       if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
541           (st.st_mode & 0111) && st.st_size >= 4) break;
542 
543       ck_free(target_path);
544       target_path = 0;
545 
546     }
547 
548     if (!target_path) FATAL("Program '%s' not found or not executable", fname);
549 
550   }
551 
552 }
553 
554 
555 /* Fix up argv for QEMU. */
556 
get_qemu_argv(u8 * own_loc,char ** argv,int argc)557 static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
558 
559   char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
560   u8 *tmp, *cp, *rsl, *own_copy;
561 
562   /* Workaround for a QEMU stability glitch. */
563 
564   setenv("QEMU_LOG", "nochain", 1);
565 
566   memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
567 
568   new_argv[2] = target_path;
569   new_argv[1] = "--";
570 
571   /* Now we need to actually find qemu for argv[0]. */
572 
573   tmp = getenv("AFL_PATH");
574 
575   if (tmp) {
576 
577     cp = alloc_printf("%s/afl-qemu-trace", tmp);
578 
579     if (access(cp, X_OK))
580       FATAL("Unable to find '%s'", tmp);
581 
582     target_path = new_argv[0] = cp;
583     return new_argv;
584 
585   }
586 
587   own_copy = ck_strdup(own_loc);
588   rsl = strrchr(own_copy, '/');
589 
590   if (rsl) {
591 
592     *rsl = 0;
593 
594     cp = alloc_printf("%s/afl-qemu-trace", own_copy);
595     ck_free(own_copy);
596 
597     if (!access(cp, X_OK)) {
598 
599       target_path = new_argv[0] = cp;
600       return new_argv;
601 
602     }
603 
604   } else ck_free(own_copy);
605 
606   if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
607 
608     target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace";
609     return new_argv;
610 
611   }
612 
613   FATAL("Unable to find 'afl-qemu-trace'.");
614 
615 }
616 
617 
618 /* Main entry point */
619 
main(int argc,char ** argv)620 int main(int argc, char** argv) {
621 
622   s32 opt;
623   u8  mem_limit_given = 0, timeout_given = 0, qemu_mode = 0;
624   u32 tcnt;
625   char** use_argv;
626 
627   doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
628 
629   while ((opt = getopt(argc,argv,"+o:m:t:A:eqZQbc")) > 0)
630 
631     switch (opt) {
632 
633       case 'o':
634 
635         if (out_file) FATAL("Multiple -o options not supported");
636         out_file = optarg;
637         break;
638 
639       case 'm': {
640 
641           u8 suffix = 'M';
642 
643           if (mem_limit_given) FATAL("Multiple -m options not supported");
644           mem_limit_given = 1;
645 
646           if (!strcmp(optarg, "none")) {
647 
648             mem_limit = 0;
649             break;
650 
651           }
652 
653           if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
654               optarg[0] == '-') FATAL("Bad syntax used for -m");
655 
656           switch (suffix) {
657 
658             case 'T': mem_limit *= 1024 * 1024; break;
659             case 'G': mem_limit *= 1024; break;
660             case 'k': mem_limit /= 1024; break;
661             case 'M': break;
662 
663             default:  FATAL("Unsupported suffix or bad syntax for -m");
664 
665           }
666 
667           if (mem_limit < 5) FATAL("Dangerously low value of -m");
668 
669           if (sizeof(rlim_t) == 4 && mem_limit > 2000)
670             FATAL("Value of -m out of range on 32-bit systems");
671 
672         }
673 
674         break;
675 
676       case 't':
677 
678         if (timeout_given) FATAL("Multiple -t options not supported");
679         timeout_given = 1;
680 
681         if (strcmp(optarg, "none")) {
682           exec_tmout = atoi(optarg);
683 
684           if (exec_tmout < 20 || optarg[0] == '-')
685             FATAL("Dangerously low value of -t");
686 
687         }
688 
689         break;
690 
691       case 'e':
692 
693         if (edges_only) FATAL("Multiple -e options not supported");
694         edges_only = 1;
695         break;
696 
697       case 'q':
698 
699         if (quiet_mode) FATAL("Multiple -q options not supported");
700         quiet_mode = 1;
701         break;
702 
703       case 'Z':
704 
705         /* This is an undocumented option to write data in the syntax expected
706            by afl-cmin. Nobody else should have any use for this. */
707 
708         cmin_mode  = 1;
709         quiet_mode = 1;
710         break;
711 
712       case 'A':
713 
714         /* Another afl-cmin specific feature. */
715         at_file = optarg;
716         break;
717 
718       case 'Q':
719 
720         if (qemu_mode) FATAL("Multiple -Q options not supported");
721         if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU;
722 
723         qemu_mode = 1;
724         break;
725 
726       case 'b':
727 
728         /* Secret undocumented mode. Writes output in raw binary format
729            similar to that dumped by afl-fuzz in <out_dir/queue/fuzz_bitmap. */
730 
731         binary_mode = 1;
732         break;
733 
734       case 'c':
735 
736         if (keep_cores) FATAL("Multiple -c options not supported");
737         keep_cores = 1;
738         break;
739 
740       default:
741 
742         usage(argv[0]);
743 
744     }
745 
746   if (optind == argc || !out_file) usage(argv[0]);
747 
748   setup_shm();
749   setup_signal_handlers();
750 
751   set_up_environment();
752 
753   find_binary(argv[optind]);
754 
755   if (!quiet_mode) {
756     show_banner();
757     ACTF("Executing '%s'...\n", target_path);
758   }
759 
760   detect_file_args(argv + optind);
761 
762   if (qemu_mode)
763     use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
764   else
765     use_argv = argv + optind;
766 
767   run_target(use_argv);
768 
769   tcnt = write_results();
770 
771   if (!quiet_mode) {
772 
773     if (!tcnt) FATAL("No instrumentation detected" cRST);
774     OKF("Captured %u tuples in '%s'." cRST, tcnt, out_file);
775 
776   }
777 
778   exit(child_crashed * 2 + child_timed_out);
779 
780 }
781 
782