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

Side by Side Diff: third_party/afl/src/afl-analyze.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/README ('k') | third_party/afl/src/afl-as.h » ('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 - file format analyzer
3 -----------------------------------------
4
5 Written and maintained by Michal Zalewski <lcamtuf@google.com>
6
7 Copyright 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 nifty utility that grabs an input file and takes a stab at explaining
16 its structure by observing how changes to it affect the execution path.
17
18 If the output scrolls past the edge of the screen, pipe it to 'less -r'.
19
20 */
21
22 #define AFL_MAIN
23
24 #include "config.h"
25 #include "types.h"
26 #include "debug.h"
27 #include "alloc-inl.h"
28 #include "hash.h"
29
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include <dirent.h>
38 #include <fcntl.h>
39 #include <ctype.h>
40
41 #include <sys/wait.h>
42 #include <sys/time.h>
43 #include <sys/shm.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 #include <sys/resource.h>
47
48 static s32 child_pid; /* PID of the tested program */
49
50 static u8* trace_bits; /* SHM with instrumentation bitmap */
51
52 static u8 *in_file, /* Analyzer input test case */
53 *prog_in, /* Targeted program input file */
54 *target_path, /* Path to target binary */
55 *doc_path; /* Path to docs */
56
57 static u8 *in_data; /* Input data for analysis */
58
59 static u32 in_len, /* Input data length */
60 orig_cksum, /* Original checksum */
61 total_execs, /* Total number of execs */
62 exec_hangs, /* Total number of hangs */
63 exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */
64
65 static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
66
67 static s32 shm_id, /* ID of the SHM region */
68 dev_null_fd = -1; /* FD to /dev/null */
69
70 static u8 edges_only, /* Ignore hit counts? */
71 use_stdin = 1; /* Use stdin for program input? */
72
73 static volatile u8
74 stop_soon, /* Ctrl-C pressed? */
75 child_timed_out; /* Child timed out? */
76
77
78 /* Constants used for describing byte behavior. */
79
80 #define RESP_NONE 0x00 /* Changing byte is a no-op. */
81 #define RESP_MINOR 0x01 /* Some changes have no effect. */
82 #define RESP_VARIABLE 0x02 /* Changes produce variable paths. */
83 #define RESP_FIXED 0x03 /* Changes produce fixed patterns. */
84
85 #define RESP_LEN 0x04 /* Potential length field */
86 #define RESP_CKSUM 0x05 /* Potential checksum */
87 #define RESP_SUSPECT 0x06 /* Potential "suspect" blob */
88
89
90 /* Classify tuple counts. This is a slow & naive version, but good enough here. */
91
92 #define AREP4(_sym) (_sym), (_sym), (_sym), (_sym)
93 #define AREP8(_sym) AREP4(_sym), AREP4(_sym)
94 #define AREP16(_sym) AREP8(_sym), AREP8(_sym)
95 #define AREP32(_sym) AREP16(_sym), AREP16(_sym)
96 #define AREP64(_sym) AREP32(_sym), AREP32(_sym)
97 #define AREP128(_sym) AREP64(_sym), AREP64(_sym)
98
99 static u8 count_class_lookup[256] = {
100
101 /* 0 - 3: 4 */ 0, 1, 2, 4,
102 /* 4 - 7: +4 */ AREP4(8),
103 /* 8 - 15: +8 */ AREP8(16),
104 /* 16 - 31: +16 */ AREP16(32),
105 /* 32 - 127: +96 */ AREP64(64), AREP32(64),
106 /* 128+: +128 */ AREP128(128)
107
108 };
109
110 static void classify_counts(u8* mem) {
111
112 u32 i = MAP_SIZE;
113
114 if (edges_only) {
115
116 while (i--) {
117 if (*mem) *mem = 1;
118 mem++;
119 }
120
121 } else {
122
123 while (i--) {
124 *mem = count_class_lookup[*mem];
125 mem++;
126 }
127
128 }
129
130 }
131
132
133 /* See if any bytes are set in the bitmap. */
134
135 static inline u8 anything_set(void) {
136
137 u32* ptr = (u32*)trace_bits;
138 u32 i = (MAP_SIZE >> 2);
139
140 while (i--) if (*(ptr++)) return 1;
141
142 return 0;
143
144 }
145
146
147 /* Get rid of shared memory and temp files (atexit handler). */
148
149 static void remove_shm(void) {
150
151 unlink(prog_in); /* Ignore errors */
152 shmctl(shm_id, IPC_RMID, NULL);
153
154 }
155
156
157 /* Configure shared memory. */
158
159 static void setup_shm(void) {
160
161 u8* shm_str;
162
163 shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
164
165 if (shm_id < 0) PFATAL("shmget() failed");
166
167 atexit(remove_shm);
168
169 shm_str = alloc_printf("%d", shm_id);
170
171 setenv(SHM_ENV_VAR, shm_str, 1);
172
173 ck_free(shm_str);
174
175 trace_bits = shmat(shm_id, NULL, 0);
176
177 if (!trace_bits) PFATAL("shmat() failed");
178
179 }
180
181
182 /* Read initial file. */
183
184 static void read_initial_file(void) {
185
186 struct stat st;
187 s32 fd = open(in_file, O_RDONLY);
188
189 if (fd < 0) PFATAL("Unable to open '%s'", in_file);
190
191 if (fstat(fd, &st) || !st.st_size)
192 FATAL("Zero-sized input file.");
193
194 if (st.st_size >= TMIN_MAX_FILE)
195 FATAL("Input file is too large (%u MB max)", TMIN_MAX_FILE / 1024 / 1024);
196
197 in_len = st.st_size;
198 in_data = ck_alloc_nozero(in_len);
199
200 ck_read(fd, in_data, in_len, in_file);
201
202 close(fd);
203
204 OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
205
206 }
207
208
209 /* Write output file. */
210
211 static s32 write_to_file(u8* path, u8* mem, u32 len) {
212
213 s32 ret;
214
215 unlink(path); /* Ignore errors */
216
217 ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
218
219 if (ret < 0) PFATAL("Unable to create '%s'", path);
220
221 ck_write(ret, mem, len, path);
222
223 lseek(ret, 0, SEEK_SET);
224
225 return ret;
226
227 }
228
229
230 /* Handle timeout signal. */
231
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. Returns exec checksum, or 0 if program
241 times out. */
242
243 static u32 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
244
245 static struct itimerval it;
246 int status = 0;
247
248 s32 prog_in_fd;
249 u32 cksum;
250
251 memset(trace_bits, 0, MAP_SIZE);
252 MEM_BARRIER();
253
254 prog_in_fd = write_to_file(prog_in, mem, len);
255
256 child_pid = fork();
257
258 if (child_pid < 0) PFATAL("fork() failed");
259
260 if (!child_pid) {
261
262 struct rlimit r;
263
264 if (dup2(use_stdin ? prog_in_fd : dev_null_fd, 0) < 0 ||
265 dup2(dev_null_fd, 1) < 0 ||
266 dup2(dev_null_fd, 2) < 0) {
267
268 *(u32*)trace_bits = EXEC_FAIL_SIG;
269 PFATAL("dup2() failed");
270
271 }
272
273 close(dev_null_fd);
274 close(prog_in_fd);
275
276 if (mem_limit) {
277
278 r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20;
279
280 #ifdef RLIMIT_AS
281
282 setrlimit(RLIMIT_AS, &r); /* Ignore errors */
283
284 #else
285
286 setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
287
288 #endif /* ^RLIMIT_AS */
289
290 }
291
292 r.rlim_max = r.rlim_cur = 0;
293 setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
294
295 execv(target_path, argv);
296
297 *(u32*)trace_bits = EXEC_FAIL_SIG;
298 exit(0);
299
300 }
301
302 close(prog_in_fd);
303
304 /* Configure timeout, wait for child, cancel timeout. */
305
306 child_timed_out = 0;
307 it.it_value.tv_sec = (exec_tmout / 1000);
308 it.it_value.tv_usec = (exec_tmout % 1000) * 1000;
309
310 setitimer(ITIMER_REAL, &it, NULL);
311
312 if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed");
313
314 child_pid = 0;
315 it.it_value.tv_sec = 0;
316 it.it_value.tv_usec = 0;
317
318 setitimer(ITIMER_REAL, &it, NULL);
319
320 MEM_BARRIER();
321
322 /* Clean up bitmap, analyze exit condition, etc. */
323
324 if (*(u32*)trace_bits == EXEC_FAIL_SIG)
325 FATAL("Unable to execute '%s'", argv[0]);
326
327 classify_counts(trace_bits);
328 total_execs++;
329
330 if (stop_soon) {
331 SAYF(cRST cLRD "\n+++ Analysis aborted by user +++\n" cRST);
332 exit(1);
333 }
334
335 /* Always discard inputs that time out. */
336
337 if (child_timed_out) {
338
339 exec_hangs++;
340 return 0;
341
342 }
343
344 cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);
345
346 /* We don't actually care if the target is crashing or not,
347 except that when it does, the checksum should be different. */
348
349 if (WIFSIGNALED(status) ||
350 (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
351 (WIFEXITED(status) && WEXITSTATUS(status))) {
352
353 cksum ^= 0xffffffff;
354
355 }
356
357 if (first_run) orig_cksum = cksum;
358
359 return cksum;
360
361 }
362
363
364 #ifdef USE_COLOR
365
366 /* Helper function to display a human-readable character. */
367
368 static void show_char(u8 val) {
369
370 switch (val) {
371
372 case 0 ... 32:
373 case 127 ... 255: SAYF("#%02x", val); break;
374
375 default: SAYF(" %c ", val);
376
377 }
378
379 }
380
381
382 /* Show the legend */
383
384 static void show_legend(void) {
385
386 SAYF(" " cLGR bgGRA " 01 " cRST " - no-op block "
387 cBLK bgLGN " 01 " cRST " - suspected length field\n"
388 " " cBRI bgGRA " 01 " cRST " - superficial content "
389 cBLK bgYEL " 01 " cRST " - suspected cksum or magic int\n"
390 " " cBLK bgCYA " 01 " cRST " - critical stream "
391 cBLK bgLRD " 01 " cRST " - suspected checksummed block\n"
392 " " cBLK bgMGN " 01 " cRST " - \"magic value\" section\n\n");
393
394 }
395
396 #endif /* USE_COLOR */
397
398
399 /* Interpret and report a pattern in the input file. */
400
401 static void dump_hex(u8* buf, u32 len, u8* b_data) {
402
403 u32 i;
404
405 for (i = 0; i < len; i++) {
406
407 #ifdef USE_COLOR
408 u32 rlen = 1, off;
409 #else
410 u32 rlen = 1;
411 #endif /* ^USE_COLOR */
412
413 u8 rtype = b_data[i] & 0x0f;
414
415 /* Look ahead to determine the length of run. */
416
417 while (i + rlen < len && (b_data[i] >> 7) == (b_data[i + rlen] >> 7)) {
418
419 if (rtype < (b_data[i + rlen] & 0x0f)) rtype = b_data[i + rlen] & 0x0f;
420 rlen++;
421
422 }
423
424 /* Try to do some further classification based on length & value. */
425
426 if (rtype == RESP_FIXED) {
427
428 switch (rlen) {
429
430 case 2: {
431
432 u16 val = *(u16*)(in_data + i);
433
434 /* Small integers may be length fields. */
435
436 if (val && (val <= in_len || SWAP16(val) <= in_len)) {
437 rtype = RESP_LEN;
438 break;
439 }
440
441 /* Uniform integers may be checksums. */
442
443 if (val && abs(in_data[i] - in_data[i + 1]) > 32) {
444 rtype = RESP_CKSUM;
445 break;
446 }
447
448 break;
449
450 }
451
452 case 4: {
453
454 u32 val = *(u32*)(in_data + i);
455
456 /* Small integers may be length fields. */
457
458 if (val && (val <= in_len || SWAP32(val) <= in_len)) {
459 rtype = RESP_LEN;
460 break;
461 }
462
463 /* Uniform integers may be checksums. */
464
465 if (val && (in_data[i] >> 7 != in_data[i + 1] >> 7 ||
466 in_data[i] >> 7 != in_data[i + 2] >> 7 ||
467 in_data[i] >> 7 != in_data[i + 3] >> 7)) {
468 rtype = RESP_CKSUM;
469 break;
470 }
471
472 break;
473
474 }
475
476 case 1: case 3: case 5 ... MAX_AUTO_EXTRA - 1: break;
477
478 default: rtype = RESP_SUSPECT;
479
480 }
481
482 }
483
484 /* Print out the entire run. */
485
486 #ifdef USE_COLOR
487
488 for (off = 0; off < rlen; off++) {
489
490 /* Every 16 digits, display offset. */
491
492 if (!((i + off) % 16)) {
493
494 if (off) SAYF(cRST cLCY ">");
495 SAYF(cRST cGRA "%s[%06u] " cRST, (i + off) ? "\n" : "", i + off);
496
497 }
498
499 switch (rtype) {
500
501 case RESP_NONE: SAYF(cLGR bgGRA); break;
502 case RESP_MINOR: SAYF(cBRI bgGRA); break;
503 case RESP_VARIABLE: SAYF(cBLK bgCYA); break;
504 case RESP_FIXED: SAYF(cBLK bgMGN); break;
505 case RESP_LEN: SAYF(cBLK bgLGN); break;
506 case RESP_CKSUM: SAYF(cBLK bgYEL); break;
507 case RESP_SUSPECT: SAYF(cBLK bgLRD); break;
508
509 }
510
511 show_char(in_data[i + off]);
512
513 if (off != rlen - 1 && (i + off + 1) % 16) SAYF(" "); else SAYF(cRST " ");
514
515 }
516
517 #else
518
519 SAYF(" Offset %u, length %u: ", i, rlen);
520
521 switch (rtype) {
522
523 case RESP_NONE: SAYF("no-op block\n"); break;
524 case RESP_MINOR: SAYF("superficial content\n"); break;
525 case RESP_VARIABLE: SAYF("critical stream\n"); break;
526 case RESP_FIXED: SAYF("\"magic value\" section\n"); break;
527 case RESP_LEN: SAYF("suspected length field\n"); break;
528 case RESP_CKSUM: SAYF("suspected cksum or magic int\n"); break;
529 case RESP_SUSPECT: SAYF("suspected checksummed block\n"); break;
530
531 }
532
533 #endif /* ^USE_COLOR */
534
535 i += rlen - 1;
536
537 }
538
539 #ifdef USE_COLOR
540 SAYF(cRST "\n");
541 #endif /* USE_COLOR */
542
543 }
544
545
546
547 /* Actually analyze! */
548
549 static void analyze(char** argv) {
550
551 u32 i;
552 u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0;
553
554 u8* b_data = ck_alloc(in_len + 1);
555 u8 seq_byte = 0;
556
557 b_data[in_len] = 0xff; /* Intentional terminator. */
558
559 ACTF("Analyzing input file (this may take a while)...\n");
560
561 #ifdef USE_COLOR
562 show_legend();
563 #endif /* USE_COLOR */
564
565 for (i = 0; i < in_len; i++) {
566
567 u32 xor_ff, xor_01, sub_10, add_10;
568 u8 xff_orig, x01_orig, s10_orig, a10_orig;
569
570 /* Perform walking byte adjustments across the file. We perform four
571 operations designed to elicit some response from the underlying
572 code. */
573
574 in_data[i] ^= 0xff;
575 xor_ff = run_target(argv, in_data, in_len, 0);
576
577 in_data[i] ^= 0xfe;
578 xor_01 = run_target(argv, in_data, in_len, 0);
579
580 in_data[i] = (in_data[i] ^ 0x01) - 0x10;
581 sub_10 = run_target(argv, in_data, in_len, 0);
582
583 in_data[i] += 0x20;
584 add_10 = run_target(argv, in_data, in_len, 0);
585 in_data[i] -= 0x10;
586
587 /* Classify current behavior. */
588
589 xff_orig = (xor_ff == orig_cksum);
590 x01_orig = (xor_01 == orig_cksum);
591 s10_orig = (sub_10 == orig_cksum);
592 a10_orig = (add_10 == orig_cksum);
593
594 if (xff_orig && x01_orig && s10_orig && a10_orig) {
595
596 b_data[i] = RESP_NONE;
597 boring_len++;
598
599 } else if (xff_orig || x01_orig || s10_orig || a10_orig) {
600
601 b_data[i] = RESP_MINOR;
602 boring_len++;
603
604 } else if (xor_ff == xor_01 && xor_ff == sub_10 && xor_ff == add_10) {
605
606 b_data[i] = RESP_FIXED;
607
608 } else b_data[i] = RESP_VARIABLE;
609
610 /* When all checksums change, flip most significant bit of b_data. */
611
612 if (prev_xff != xor_ff && prev_x01 != xor_01 &&
613 prev_s10 != sub_10 && prev_a10 != add_10) seq_byte ^= 0x80;
614
615 b_data[i] |= seq_byte;
616
617 prev_xff = xor_ff;
618 prev_x01 = xor_01;
619 prev_s10 = sub_10;
620 prev_a10 = add_10;
621
622 }
623
624 dump_hex(in_data, in_len, b_data);
625
626 SAYF("\n");
627
628 OKF("Analysis complete. Interesting bits: %0.02f%% of the input file.",
629 100.0 - ((double)boring_len * 100) / in_len);
630
631 if (exec_hangs)
632 WARNF(cLRD "Encountered %u timeouts - results may be skewed." cRST,
633 exec_hangs);
634
635 ck_free(b_data);
636
637 }
638
639
640
641 /* Handle Ctrl-C and the like. */
642
643 static void handle_stop_sig(int sig) {
644
645 stop_soon = 1;
646
647 if (child_pid > 0) kill(child_pid, SIGKILL);
648
649 }
650
651
652 /* Do basic preparations - persistent fds, filenames, etc. */
653
654 static void set_up_environment(void) {
655
656 u8* x;
657
658 dev_null_fd = open("/dev/null", O_RDWR);
659 if (dev_null_fd < 0) PFATAL("Unable to open /dev/null");
660
661 if (!prog_in) {
662
663 u8* use_dir = ".";
664
665 if (!access(use_dir, R_OK | W_OK | X_OK)) {
666
667 use_dir = getenv("TMPDIR");
668 if (!use_dir) use_dir = "/tmp";
669
670 prog_in = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, getpid());
671
672 }
673
674 }
675
676 /* Set sane defaults... */
677
678 x = getenv("ASAN_OPTIONS");
679
680 if (x) {
681
682 if (!strstr(x, "abort_on_error=1"))
683 FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
684
685 if (!strstr(x, "symbolize=0"))
686 FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
687
688 }
689
690 x = getenv("MSAN_OPTIONS");
691
692 if (x) {
693
694 if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR)))
695 FATAL("Custom MSAN_OPTIONS set without exit_code="
696 STRINGIFY(MSAN_ERROR) " - please fix!");
697
698 if (!strstr(x, "symbolize=0"))
699 FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
700
701 }
702
703 setenv("ASAN_OPTIONS", "abort_on_error=1:"
704 "detect_leaks=0:"
705 "symbolize=0:"
706 "allocator_may_return_null=1", 0);
707
708 setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
709 "symbolize=0:"
710 "abort_on_error=1:"
711 "allocator_may_return_null=1:"
712 "msan_track_origins=0", 0);
713
714 if (getenv("AFL_LD_PRELOAD"))
715 setenv("LD_PRELOAD", getenv("AFL_LD_PRELOAD"), 1);
716
717 }
718
719
720 /* Setup signal handlers, duh. */
721
722 static void setup_signal_handlers(void) {
723
724 struct sigaction sa;
725
726 sa.sa_handler = NULL;
727 sa.sa_flags = SA_RESTART;
728 sa.sa_sigaction = NULL;
729
730 sigemptyset(&sa.sa_mask);
731
732 /* Various ways of saying "stop". */
733
734 sa.sa_handler = handle_stop_sig;
735 sigaction(SIGHUP, &sa, NULL);
736 sigaction(SIGINT, &sa, NULL);
737 sigaction(SIGTERM, &sa, NULL);
738
739 /* Exec timeout notifications. */
740
741 sa.sa_handler = handle_timeout;
742 sigaction(SIGALRM, &sa, NULL);
743
744 }
745
746
747 /* Detect @@ in args. */
748
749 static void detect_file_args(char** argv) {
750
751 u32 i = 0;
752 u8* cwd = getcwd(NULL, 0);
753
754 if (!cwd) PFATAL("getcwd() failed");
755
756 while (argv[i]) {
757
758 u8* aa_loc = strstr(argv[i], "@@");
759
760 if (aa_loc) {
761
762 u8 *aa_subst, *n_arg;
763
764 /* Be sure that we're always using fully-qualified paths. */
765
766 if (prog_in[0] == '/') aa_subst = prog_in;
767 else aa_subst = alloc_printf("%s/%s", cwd, prog_in);
768
769 /* Construct a replacement argv value. */
770
771 *aa_loc = 0;
772 n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
773 argv[i] = n_arg;
774 *aa_loc = '@';
775
776 if (prog_in[0] != '/') ck_free(aa_subst);
777
778 }
779
780 i++;
781
782 }
783
784 free(cwd); /* not tracked */
785
786 }
787
788
789 /* Display usage hints. */
790
791 static void usage(u8* argv0) {
792
793 SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
794
795 "Required parameters:\n\n"
796
797 " -i file - input test case to be analyzed by the tool\n"
798
799 "Execution control settings:\n\n"
800
801 " -f file - input file read by the tested program (stdin)\n"
802 " -t msec - timeout for each run (%u ms)\n"
803 " -m megs - memory limit for child process (%u MB)\n"
804 " -Q - use binary-only instrumentation (QEMU mode)\n\n"
805
806 "Analysis settings:\n\n"
807
808 " -e - look for edge coverage only, ignore hit counts\n\n"
809
810 "For additional tips, please consult %s/README.\n\n",
811
812 argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
813
814 exit(1);
815
816 }
817
818
819 /* Find binary. */
820
821 static void find_binary(u8* fname) {
822
823 u8* env_path = 0;
824 struct stat st;
825
826 if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
827
828 target_path = ck_strdup(fname);
829
830 if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
831 !(st.st_mode & 0111) || st.st_size < 4)
832 FATAL("Program '%s' not found or not executable", fname);
833
834 } else {
835
836 while (env_path) {
837
838 u8 *cur_elem, *delim = strchr(env_path, ':');
839
840 if (delim) {
841
842 cur_elem = ck_alloc(delim - env_path + 1);
843 memcpy(cur_elem, env_path, delim - env_path);
844 delim++;
845
846 } else cur_elem = ck_strdup(env_path);
847
848 env_path = delim;
849
850 if (cur_elem[0])
851 target_path = alloc_printf("%s/%s", cur_elem, fname);
852 else
853 target_path = ck_strdup(fname);
854
855 ck_free(cur_elem);
856
857 if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
858 (st.st_mode & 0111) && st.st_size >= 4) break;
859
860 ck_free(target_path);
861 target_path = 0;
862
863 }
864
865 if (!target_path) FATAL("Program '%s' not found or not executable", fname);
866
867 }
868
869 }
870
871
872 /* Fix up argv for QEMU. */
873
874 static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
875
876 char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
877 u8 *tmp, *cp, *rsl, *own_copy;
878
879 memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
880
881 /* Now we need to actually find qemu for argv[0]. */
882
883 new_argv[2] = target_path;
884 new_argv[1] = "--";
885
886 tmp = getenv("AFL_PATH");
887
888 if (tmp) {
889
890 cp = alloc_printf("%s/afl-qemu-trace", tmp);
891
892 if (access(cp, X_OK))
893 FATAL("Unable to find '%s'", tmp);
894
895 target_path = new_argv[0] = cp;
896 return new_argv;
897
898 }
899
900 own_copy = ck_strdup(own_loc);
901 rsl = strrchr(own_copy, '/');
902
903 if (rsl) {
904
905 *rsl = 0;
906
907 cp = alloc_printf("%s/afl-qemu-trace", own_copy);
908 ck_free(own_copy);
909
910 if (!access(cp, X_OK)) {
911
912 target_path = new_argv[0] = cp;
913 return new_argv;
914
915 }
916
917 } else ck_free(own_copy);
918
919 if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
920
921 target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace";
922 return new_argv;
923
924 }
925
926 FATAL("Unable to find 'afl-qemu-trace'.");
927
928 }
929
930
931 /* Main entry point */
932
933 int main(int argc, char** argv) {
934
935 s32 opt;
936 u8 mem_limit_given = 0, timeout_given = 0, qemu_mode = 0;
937 char** use_argv;
938
939 doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
940
941 SAYF(cCYA "afl-analyze " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
942
943 while ((opt = getopt(argc,argv,"+i:f:m:t:eQ")) > 0)
944
945 switch (opt) {
946
947 case 'i':
948
949 if (in_file) FATAL("Multiple -i options not supported");
950 in_file = optarg;
951 break;
952
953 case 'f':
954
955 if (prog_in) FATAL("Multiple -f options not supported");
956 use_stdin = 0;
957 prog_in = optarg;
958 break;
959
960 case 'e':
961
962 if (edges_only) FATAL("Multiple -e options not supported");
963 edges_only = 1;
964 break;
965
966 case 'm': {
967
968 u8 suffix = 'M';
969
970 if (mem_limit_given) FATAL("Multiple -m options not supported");
971 mem_limit_given = 1;
972
973 if (!strcmp(optarg, "none")) {
974
975 mem_limit = 0;
976 break;
977
978 }
979
980 if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
981 optarg[0] == '-') FATAL("Bad syntax used for -m");
982
983 switch (suffix) {
984
985 case 'T': mem_limit *= 1024 * 1024; break;
986 case 'G': mem_limit *= 1024; break;
987 case 'k': mem_limit /= 1024; break;
988 case 'M': break;
989
990 default: FATAL("Unsupported suffix or bad syntax for -m");
991
992 }
993
994 if (mem_limit < 5) FATAL("Dangerously low value of -m");
995
996 if (sizeof(rlim_t) == 4 && mem_limit > 2000)
997 FATAL("Value of -m out of range on 32-bit systems");
998
999 }
1000
1001 break;
1002
1003 case 't':
1004
1005 if (timeout_given) FATAL("Multiple -t options not supported");
1006 timeout_given = 1;
1007
1008 exec_tmout = atoi(optarg);
1009
1010 if (exec_tmout < 10 || optarg[0] == '-')
1011 FATAL("Dangerously low value of -t");
1012
1013 break;
1014
1015 case 'Q':
1016
1017 if (qemu_mode) FATAL("Multiple -Q options not supported");
1018 if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU;
1019
1020 qemu_mode = 1;
1021 break;
1022
1023 default:
1024
1025 usage(argv[0]);
1026
1027 }
1028
1029 if (optind == argc || !in_file) usage(argv[0]);
1030
1031 setup_shm();
1032 setup_signal_handlers();
1033
1034 set_up_environment();
1035
1036 find_binary(argv[optind]);
1037 detect_file_args(argv + optind);
1038
1039 if (qemu_mode)
1040 use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
1041 else
1042 use_argv = argv + optind;
1043
1044 SAYF("\n");
1045
1046 read_initial_file();
1047
1048 ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
1049 mem_limit, exec_tmout, edges_only ? ", edges only" : "");
1050
1051 run_target(use_argv, in_data, in_len, 1);
1052
1053 if (child_timed_out)
1054 FATAL("Target binary times out (adjusting -t may help).");
1055
1056 if (!anything_set()) FATAL("No instrumentation detected.");
1057
1058 analyze(use_argv);
1059
1060 OKF("We're done here. Have a nice day!\n");
1061
1062 exit(0);
1063
1064 }
1065
OLDNEW
« no previous file with comments | « third_party/afl/src/README ('k') | third_party/afl/src/afl-as.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698