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