Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(221)

Side by Side Diff: third_party/afl/src/afl-showmap.c

Issue 2075883002: Add American Fuzzy Lop (afl) to third_party/afl/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix nits Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/afl/src/afl-plot ('k') | third_party/afl/src/afl-tmin.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 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
68 static volatile u8
69 stop_soon, /* Ctrl-C pressed? */
70 child_timed_out, /* Child timed out? */
71 child_crashed; /* Child crashed? */
72
73 /* Classify tuple counts. Instead of mapping to individual bits, as in
74 afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
75
76 #define AREP4(_sym) (_sym), (_sym), (_sym), (_sym)
77 #define AREP8(_sym) AREP4(_sym), AREP4(_sym)
78 #define AREP16(_sym) AREP8(_sym), AREP8(_sym)
79 #define AREP32(_sym) AREP16(_sym), AREP16(_sym)
80 #define AREP64(_sym) AREP32(_sym), AREP32(_sym)
81 #define AREP128(_sym) AREP64(_sym), AREP64(_sym)
82
83 static u8 count_class_lookup[256] = {
84
85 /* 0 - 3: 4 */ 0, 1, 2, 3,
86 /* 4 - 7: +4 */ AREP4(4),
87 /* 8 - 15: +8 */ AREP8(5),
88 /* 16 - 31: +16 */ AREP16(6),
89 /* 32 - 127: +96 */ AREP64(7), AREP32(7),
90 /* 128+: +128 */ AREP128(8)
91
92 };
93
94 static void classify_counts(u8* mem) {
95
96 u32 i = MAP_SIZE;
97
98 if (edges_only) {
99
100 while (i--) {
101 if (*mem) *mem = 1;
102 mem++;
103 }
104
105 } else {
106
107 while (i--) {
108 *mem = count_class_lookup[*mem];
109 mem++;
110 }
111
112 }
113
114 }
115
116
117 /* Get rid of shared memory (atexit handler). */
118
119 static void remove_shm(void) {
120
121 shmctl(shm_id, IPC_RMID, NULL);
122
123 }
124
125
126 /* Configure shared memory. */
127
128 static void setup_shm(void) {
129
130 u8* shm_str;
131
132 shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
133
134 if (shm_id < 0) PFATAL("shmget() failed");
135
136 atexit(remove_shm);
137
138 shm_str = alloc_printf("%d", shm_id);
139
140 setenv(SHM_ENV_VAR, shm_str, 1);
141
142 ck_free(shm_str);
143
144 trace_bits = shmat(shm_id, NULL, 0);
145
146 if (!trace_bits) PFATAL("shmat() failed");
147
148 }
149
150 /* Write results. */
151
152 static u32 write_results(void) {
153
154 s32 fd;
155 FILE* f;
156 u32 i, ret = 0;
157 u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"),
158 caa = !!getenv("AFL_CMIN_ALLOW_ANY");
159
160 if (!strncmp(out_file, "/dev/", 5)) {
161
162 fd = open(out_file, O_WRONLY, 0600);
163 if (fd < 0) PFATAL("Unable to open '%s'", out_file);
164
165 } else if (!strcmp(out_file, "-")) {
166
167 fd = dup(1);
168 if (fd < 0) PFATAL("Unable to open stdout");
169
170 } else {
171
172 unlink(out_file); /* Ignore errors */
173 fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
174 if (fd < 0) PFATAL("Unable to create '%s'", out_file);
175
176 }
177
178 f = fdopen(fd, "w");
179
180 if (!f) PFATAL("fdopen() failed");
181
182 for (i = 0; i < MAP_SIZE; i++) {
183
184 if (!trace_bits[i]) continue;
185 ret++;
186
187 if (cmin_mode) {
188
189 if (child_timed_out) break;
190 if (!caa && child_crashed != cco) break;
191
192 fprintf(f, "%u%u\n", trace_bits[i], i);
193
194 } else fprintf(f, "%06u:%u\n", i, trace_bits[i]);
195
196 }
197
198 fclose(f);
199
200 return ret;
201
202 }
203
204
205 /* Handle timeout signal. */
206
207 static void handle_timeout(int sig) {
208
209 child_timed_out = 1;
210 if (child_pid > 0) kill(child_pid, SIGKILL);
211
212 }
213
214
215 /* Execute target application. */
216
217 static void run_target(char** argv) {
218
219 static struct itimerval it;
220 int status = 0;
221
222 if (!quiet_mode)
223 SAYF("-- Program output begins --\n" cRST);
224
225 MEM_BARRIER();
226
227 child_pid = fork();
228
229 if (child_pid < 0) PFATAL("fork() failed");
230
231 if (!child_pid) {
232
233 struct rlimit r;
234
235 if (quiet_mode) {
236
237 s32 fd = open("/dev/null", O_RDWR);
238
239 if (fd < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) {
240 *(u32*)trace_bits = EXEC_FAIL_SIG;
241 PFATAL("Descriptor initialization failed");
242 }
243
244 close(fd);
245
246 }
247
248 if (mem_limit) {
249
250 r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20;
251
252 #ifdef RLIMIT_AS
253
254 setrlimit(RLIMIT_AS, &r); /* Ignore errors */
255
256 #else
257
258 setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
259
260 #endif /* ^RLIMIT_AS */
261
262 }
263
264 r.rlim_max = r.rlim_cur = 0;
265 setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
266
267 execv(target_path, argv);
268
269 *(u32*)trace_bits = EXEC_FAIL_SIG;
270 exit(0);
271
272 }
273
274 /* Configure timeout, wait for child, cancel timeout. */
275
276 if (exec_tmout) {
277
278 child_timed_out = 0;
279 it.it_value.tv_sec = (exec_tmout / 1000);
280 it.it_value.tv_usec = (exec_tmout % 1000) * 1000;
281
282 }
283
284 setitimer(ITIMER_REAL, &it, NULL);
285
286 if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed");
287
288 child_pid = 0;
289 it.it_value.tv_sec = 0;
290 it.it_value.tv_usec = 0;
291 setitimer(ITIMER_REAL, &it, NULL);
292
293 MEM_BARRIER();
294
295 /* Clean up bitmap, analyze exit condition, etc. */
296
297 if (*(u32*)trace_bits == EXEC_FAIL_SIG)
298 FATAL("Unable to execute '%s'", argv[0]);
299
300 classify_counts(trace_bits);
301
302 if (!quiet_mode)
303 SAYF(cRST "-- Program output ends --\n");
304
305 if (!child_timed_out && !stop_soon && WIFSIGNALED(status))
306 child_crashed = 1;
307
308 if (!quiet_mode) {
309
310 if (child_timed_out)
311 SAYF(cLRD "\n+++ Program timed off +++\n" cRST);
312 else if (stop_soon)
313 SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST);
314 else if (child_crashed)
315 SAYF(cLRD "\n+++ Program killed by signal %u +++\n" cRST, WTERMSIG(status) );
316
317 }
318
319
320 }
321
322
323 /* Handle Ctrl-C and the like. */
324
325 static void handle_stop_sig(int sig) {
326
327 stop_soon = 1;
328
329 if (child_pid > 0) kill(child_pid, SIGKILL);
330
331 }
332
333
334 /* Do basic preparations - persistent fds, filenames, etc. */
335
336 static void set_up_environment(void) {
337
338 setenv("ASAN_OPTIONS", "abort_on_error=1:"
339 "detect_leaks=0:"
340 "symbolize=0:"
341 "allocator_may_return_null=1", 0);
342
343 setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
344 "symbolize=0:"
345 "abort_on_error=1:"
346 "allocator_may_return_null=1:"
347 "msan_track_origins=0", 0);
348
349 if (getenv("AFL_LD_PRELOAD"))
350 setenv("LD_PRELOAD", getenv("AFL_LD_PRELOAD"), 1);
351
352 }
353
354
355 /* Setup signal handlers, duh. */
356
357 static void setup_signal_handlers(void) {
358
359 struct sigaction sa;
360
361 sa.sa_handler = NULL;
362 sa.sa_flags = SA_RESTART;
363 sa.sa_sigaction = NULL;
364
365 sigemptyset(&sa.sa_mask);
366
367 /* Various ways of saying "stop". */
368
369 sa.sa_handler = handle_stop_sig;
370 sigaction(SIGHUP, &sa, NULL);
371 sigaction(SIGINT, &sa, NULL);
372 sigaction(SIGTERM, &sa, NULL);
373
374 /* Exec timeout notifications. */
375
376 sa.sa_handler = handle_timeout;
377 sigaction(SIGALRM, &sa, NULL);
378
379 }
380
381
382 /* Detect @@ in args. */
383
384 static void detect_file_args(char** argv) {
385
386 u32 i = 0;
387 u8* cwd = getcwd(NULL, 0);
388
389 if (!cwd) PFATAL("getcwd() failed");
390
391 while (argv[i]) {
392
393 u8* aa_loc = strstr(argv[i], "@@");
394
395 if (aa_loc) {
396
397 u8 *aa_subst, *n_arg;
398
399 if (!at_file) FATAL("@@ syntax is not supported by this tool.");
400
401 /* Be sure that we're always using fully-qualified paths. */
402
403 if (at_file[0] == '/') aa_subst = at_file;
404 else aa_subst = alloc_printf("%s/%s", cwd, at_file);
405
406 /* Construct a replacement argv value. */
407
408 *aa_loc = 0;
409 n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
410 argv[i] = n_arg;
411 *aa_loc = '@';
412
413 if (at_file[0] != '/') ck_free(aa_subst);
414
415 }
416
417 i++;
418
419 }
420
421 free(cwd); /* not tracked */
422
423 }
424
425
426 /* Show banner. */
427
428 static void show_banner(void) {
429
430 SAYF(cCYA "afl-showmap " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
431
432 }
433
434 /* Display usage hints. */
435
436 static void usage(u8* argv0) {
437
438 show_banner();
439
440 SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
441
442 "Required parameters:\n\n"
443
444 " -o file - file to write the trace data to\n\n"
445
446 "Execution control settings:\n\n"
447
448 " -t msec - timeout for each run (none)\n"
449 " -m megs - memory limit for child process (%u MB)\n"
450 " -Q - use binary-only instrumentation (QEMU mode)\n\n"
451
452 "Other settings:\n\n"
453
454 " -q - sink program's output and don't show messages\n"
455 " -e - show edge coverage only, ignore hit counts\n\n"
456
457 "This tool displays raw tuple data captured by AFL instrumentation.\n"
458 "For additional help, consult %s/README.\n\n" cRST,
459
460 argv0, MEM_LIMIT, doc_path);
461
462 exit(1);
463
464 }
465
466
467 /* Find binary. */
468
469 static void find_binary(u8* fname) {
470
471 u8* env_path = 0;
472 struct stat st;
473
474 if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
475
476 target_path = ck_strdup(fname);
477
478 if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
479 !(st.st_mode & 0111) || st.st_size < 4)
480 FATAL("Program '%s' not found or not executable", fname);
481
482 } else {
483
484 while (env_path) {
485
486 u8 *cur_elem, *delim = strchr(env_path, ':');
487
488 if (delim) {
489
490 cur_elem = ck_alloc(delim - env_path + 1);
491 memcpy(cur_elem, env_path, delim - env_path);
492 delim++;
493
494 } else cur_elem = ck_strdup(env_path);
495
496 env_path = delim;
497
498 if (cur_elem[0])
499 target_path = alloc_printf("%s/%s", cur_elem, fname);
500 else
501 target_path = ck_strdup(fname);
502
503 ck_free(cur_elem);
504
505 if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
506 (st.st_mode & 0111) && st.st_size >= 4) break;
507
508 ck_free(target_path);
509 target_path = 0;
510
511 }
512
513 if (!target_path) FATAL("Program '%s' not found or not executable", fname);
514
515 }
516
517 }
518
519
520 /* Fix up argv for QEMU. */
521
522 static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
523
524 char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
525 u8 *tmp, *cp, *rsl, *own_copy;
526
527 memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
528
529 new_argv[2] = target_path;
530 new_argv[1] = "--";
531
532 /* Now we need to actually find qemu for argv[0]. */
533
534 tmp = getenv("AFL_PATH");
535
536 if (tmp) {
537
538 cp = alloc_printf("%s/afl-qemu-trace", tmp);
539
540 if (access(cp, X_OK))
541 FATAL("Unable to find '%s'", tmp);
542
543 target_path = new_argv[0] = cp;
544 return new_argv;
545
546 }
547
548 own_copy = ck_strdup(own_loc);
549 rsl = strrchr(own_copy, '/');
550
551 if (rsl) {
552
553 *rsl = 0;
554
555 cp = alloc_printf("%s/afl-qemu-trace", own_copy);
556 ck_free(own_copy);
557
558 if (!access(cp, X_OK)) {
559
560 target_path = new_argv[0] = cp;
561 return new_argv;
562
563 }
564
565 } else ck_free(own_copy);
566
567 if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
568
569 target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace";
570 return new_argv;
571
572 }
573
574 FATAL("Unable to find 'afl-qemu-trace'.");
575
576 }
577
578
579 /* Main entry point */
580
581 int main(int argc, char** argv) {
582
583 s32 opt;
584 u8 mem_limit_given = 0, timeout_given = 0, qemu_mode = 0;
585 u32 tcnt;
586 char** use_argv;
587
588 doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
589
590 while ((opt = getopt(argc,argv,"+o:m:t:A:eqZQ")) > 0)
591
592 switch (opt) {
593
594 case 'o':
595
596 if (out_file) FATAL("Multiple -o options not supported");
597 out_file = optarg;
598 break;
599
600 case 'm': {
601
602 u8 suffix = 'M';
603
604 if (mem_limit_given) FATAL("Multiple -m options not supported");
605 mem_limit_given = 1;
606
607 if (!strcmp(optarg, "none")) {
608
609 mem_limit = 0;
610 break;
611
612 }
613
614 if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
615 optarg[0] == '-') FATAL("Bad syntax used for -m");
616
617 switch (suffix) {
618
619 case 'T': mem_limit *= 1024 * 1024; break;
620 case 'G': mem_limit *= 1024; break;
621 case 'k': mem_limit /= 1024; break;
622 case 'M': break;
623
624 default: FATAL("Unsupported suffix or bad syntax for -m");
625
626 }
627
628 if (mem_limit < 5) FATAL("Dangerously low value of -m");
629
630 if (sizeof(rlim_t) == 4 && mem_limit > 2000)
631 FATAL("Value of -m out of range on 32-bit systems");
632
633 }
634
635 break;
636
637 case 't':
638
639 if (timeout_given) FATAL("Multiple -t options not supported");
640 timeout_given = 1;
641
642 if (strcmp(optarg, "none")) {
643 exec_tmout = atoi(optarg);
644
645 if (exec_tmout < 20 || optarg[0] == '-')
646 FATAL("Dangerously low value of -t");
647
648 }
649
650 break;
651
652 case 'e':
653
654 if (edges_only) FATAL("Multiple -e options not supported");
655 edges_only = 1;
656 break;
657
658 case 'q':
659
660 if (quiet_mode) FATAL("Multiple -q options not supported");
661 quiet_mode = 1;
662 break;
663
664 case 'Z':
665
666 /* This is an undocumented option to write data in the syntax expected
667 by afl-cmin. Nobody else should have any use for this. */
668
669 cmin_mode = 1;
670 quiet_mode = 1;
671 break;
672
673 case 'A':
674
675 /* Another afl-cmin specific feature. */
676 at_file = optarg;
677 break;
678
679 case 'Q':
680
681 if (qemu_mode) FATAL("Multiple -Q options not supported");
682 if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU;
683
684 qemu_mode = 1;
685 break;
686
687 default:
688
689 usage(argv[0]);
690
691 }
692
693 if (optind == argc || !out_file) usage(argv[0]);
694
695 setup_shm();
696 setup_signal_handlers();
697
698 set_up_environment();
699
700 find_binary(argv[optind]);
701
702 if (!quiet_mode) {
703 show_banner();
704 ACTF("Executing '%s'...\n", target_path);
705 }
706
707 detect_file_args(argv + optind);
708
709 if (qemu_mode)
710 use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
711 else
712 use_argv = argv + optind;
713
714 run_target(use_argv);
715
716 tcnt = write_results();
717
718 if (!quiet_mode) {
719
720 if (!tcnt) FATAL("No instrumentation detected" cRST);
721 OKF("Captured %u tuples in '%s'." cRST, tcnt, out_file);
722
723 }
724
725 exit(child_crashed * 2 + child_timed_out);
726
727 }
728
OLDNEW
« no previous file with comments | « third_party/afl/src/afl-plot ('k') | third_party/afl/src/afl-tmin.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698