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