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