1 /*
2 american fuzzy lop - test case minimizer
3 ----------------------------------------
4
5 Written and maintained by Michal Zalewski <lcamtuf@google.com>
6
7 Copyright 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 simple test case minimizer that takes an input file and tries to remove
16 as much data as possible while keeping the binary in a crashing state
17 *or* producing consistent instrumentation output (the mode is auto-selected
18 based on the initially observed behavior).
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
40 #include <sys/wait.h>
41 #include <sys/time.h>
42 #include <sys/shm.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <sys/resource.h>
46
47 static s32 child_pid; /* PID of the tested program */
48
49 static u8 *trace_bits, /* SHM with instrumentation bitmap */
50 *mask_bitmap; /* Mask for trace bits (-B) */
51
52 static u8 *in_file, /* Minimizer input test case */
53 *out_file, /* Minimizer output file */
54 *prog_in, /* Targeted program input file */
55 *target_path, /* Path to target binary */
56 *doc_path; /* Path to docs */
57
58 static u8* in_data; /* Input data for trimming */
59
60 static u32 in_len, /* Input data length */
61 orig_cksum, /* Original checksum */
62 total_execs, /* Total number of execs */
63 missed_hangs, /* Misses due to hangs */
64 missed_crashes, /* Misses due to crashes */
65 missed_paths, /* Misses due to exec path diffs */
66 exec_tmout = EXEC_TIMEOUT; /* Exec timeout (ms) */
67
68 static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
69
70 static s32 shm_id, /* ID of the SHM region */
71 dev_null_fd = -1; /* FD to /dev/null */
72
73 static u8 crash_mode, /* Crash-centric mode? */
74 exit_crash, /* Treat non-zero exit as crash? */
75 edges_only, /* Ignore hit counts? */
76 exact_mode, /* Require path match for crashes? */
77 use_stdin = 1; /* Use stdin for program input? */
78
79 static volatile u8
80 stop_soon, /* Ctrl-C pressed? */
81 child_timed_out; /* Child timed out? */
82
83
84 /* Classify tuple counts. This is a slow & naive version, but good enough here. */
85
86 static const u8 count_class_lookup[256] = {
87
88 [0] = 0,
89 [1] = 1,
90 [2] = 2,
91 [3] = 4,
92 [4 ... 7] = 8,
93 [8 ... 15] = 16,
94 [16 ... 31] = 32,
95 [32 ... 127] = 64,
96 [128 ... 255] = 128
97
98 };
99
classify_counts(u8 * mem)100 static void classify_counts(u8* mem) {
101
102 u32 i = MAP_SIZE;
103
104 if (edges_only) {
105
106 while (i--) {
107 if (*mem) *mem = 1;
108 mem++;
109 }
110
111 } else {
112
113 while (i--) {
114 *mem = count_class_lookup[*mem];
115 mem++;
116 }
117
118 }
119
120 }
121
122
123 /* Apply mask to classified bitmap (if set). */
124
apply_mask(u32 * mem,u32 * mask)125 static void apply_mask(u32* mem, u32* mask) {
126
127 u32 i = (MAP_SIZE >> 2);
128
129 if (!mask) return;
130
131 while (i--) {
132
133 *mem &= ~*mask;
134 mem++;
135 mask++;
136
137 }
138
139 }
140
141
142 /* See if any bytes are set in the bitmap. */
143
anything_set(void)144 static inline u8 anything_set(void) {
145
146 u32* ptr = (u32*)trace_bits;
147 u32 i = (MAP_SIZE >> 2);
148
149 while (i--) if (*(ptr++)) return 1;
150
151 return 0;
152
153 }
154
155
156
157 /* Get rid of shared memory and temp files (atexit handler). */
158
remove_shm(void)159 static void remove_shm(void) {
160
161 if (prog_in) unlink(prog_in); /* Ignore errors */
162 shmctl(shm_id, IPC_RMID, NULL);
163
164 }
165
166
167 /* Configure shared memory. */
168
setup_shm(void)169 static void setup_shm(void) {
170
171 u8* shm_str;
172
173 shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
174
175 if (shm_id < 0) PFATAL("shmget() failed");
176
177 atexit(remove_shm);
178
179 shm_str = alloc_printf("%d", shm_id);
180
181 setenv(SHM_ENV_VAR, shm_str, 1);
182
183 ck_free(shm_str);
184
185 trace_bits = shmat(shm_id, NULL, 0);
186
187 if (!trace_bits) PFATAL("shmat() failed");
188
189 }
190
191
192 /* Read initial file. */
193
read_initial_file(void)194 static void read_initial_file(void) {
195
196 struct stat st;
197 s32 fd = open(in_file, O_RDONLY);
198
199 if (fd < 0) PFATAL("Unable to open '%s'", in_file);
200
201 if (fstat(fd, &st) || !st.st_size)
202 FATAL("Zero-sized input file.");
203
204 if (st.st_size >= TMIN_MAX_FILE)
205 FATAL("Input file is too large (%u MB max)", TMIN_MAX_FILE / 1024 / 1024);
206
207 in_len = st.st_size;
208 in_data = ck_alloc_nozero(in_len);
209
210 ck_read(fd, in_data, in_len, in_file);
211
212 close(fd);
213
214 OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
215
216 }
217
218
219 /* Write output file. */
220
write_to_file(u8 * path,u8 * mem,u32 len)221 static s32 write_to_file(u8* path, u8* mem, u32 len) {
222
223 s32 ret;
224
225 unlink(path); /* Ignore errors */
226
227 ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
228
229 if (ret < 0) PFATAL("Unable to create '%s'", path);
230
231 ck_write(ret, mem, len, path);
232
233 lseek(ret, 0, SEEK_SET);
234
235 return ret;
236
237 }
238
239
240 /* Handle timeout signal. */
241
handle_timeout(int sig)242 static void handle_timeout(int sig) {
243
244 child_timed_out = 1;
245 if (child_pid > 0) kill(child_pid, SIGKILL);
246
247 }
248
249
250 /* Execute target application. Returns 0 if the changes are a dud, or
251 1 if they should be kept. */
252
run_target(char ** argv,u8 * mem,u32 len,u8 first_run)253 static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
254
255 static struct itimerval it;
256 int status = 0;
257
258 s32 prog_in_fd;
259 u32 cksum;
260
261 memset(trace_bits, 0, MAP_SIZE);
262 MEM_BARRIER();
263
264 prog_in_fd = write_to_file(prog_in, mem, len);
265
266 child_pid = fork();
267
268 if (child_pid < 0) PFATAL("fork() failed");
269
270 if (!child_pid) {
271
272 struct rlimit r;
273
274 if (dup2(use_stdin ? prog_in_fd : dev_null_fd, 0) < 0 ||
275 dup2(dev_null_fd, 1) < 0 ||
276 dup2(dev_null_fd, 2) < 0) {
277
278 *(u32*)trace_bits = EXEC_FAIL_SIG;
279 PFATAL("dup2() failed");
280
281 }
282
283 close(dev_null_fd);
284 close(prog_in_fd);
285
286 setsid();
287
288 if (mem_limit) {
289
290 r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20;
291
292 #ifdef RLIMIT_AS
293
294 setrlimit(RLIMIT_AS, &r); /* Ignore errors */
295
296 #else
297
298 setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
299
300 #endif /* ^RLIMIT_AS */
301
302 }
303
304 r.rlim_max = r.rlim_cur = 0;
305 setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
306
307 execv(target_path, argv);
308
309 *(u32*)trace_bits = EXEC_FAIL_SIG;
310 exit(0);
311
312 }
313
314 close(prog_in_fd);
315
316 /* Configure timeout, wait for child, cancel timeout. */
317
318 child_timed_out = 0;
319 it.it_value.tv_sec = (exec_tmout / 1000);
320 it.it_value.tv_usec = (exec_tmout % 1000) * 1000;
321
322 setitimer(ITIMER_REAL, &it, NULL);
323
324 if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed");
325
326 child_pid = 0;
327 it.it_value.tv_sec = 0;
328 it.it_value.tv_usec = 0;
329
330 setitimer(ITIMER_REAL, &it, NULL);
331
332 MEM_BARRIER();
333
334 /* Clean up bitmap, analyze exit condition, etc. */
335
336 if (*(u32*)trace_bits == EXEC_FAIL_SIG)
337 FATAL("Unable to execute '%s'", argv[0]);
338
339 classify_counts(trace_bits);
340 apply_mask((u32*)trace_bits, (u32*)mask_bitmap);
341 total_execs++;
342
343 if (stop_soon) {
344
345 SAYF(cRST cLRD "\n+++ Minimization aborted by user +++\n" cRST);
346 close(write_to_file(out_file, in_data, in_len));
347 exit(1);
348
349 }
350
351 /* Always discard inputs that time out. */
352
353 if (child_timed_out) {
354
355 missed_hangs++;
356 return 0;
357
358 }
359
360 /* Handle crashing inputs depending on current mode. */
361
362 if (WIFSIGNALED(status) ||
363 (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
364 (WIFEXITED(status) && WEXITSTATUS(status) && exit_crash)) {
365
366 if (first_run) crash_mode = 1;
367
368 if (crash_mode) {
369
370 if (!exact_mode) return 1;
371
372 } else {
373
374 missed_crashes++;
375 return 0;
376
377 }
378
379 } else
380
381 /* Handle non-crashing inputs appropriately. */
382
383 if (crash_mode) {
384
385 missed_paths++;
386 return 0;
387
388 }
389
390 cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);
391
392 if (first_run) orig_cksum = cksum;
393
394 if (orig_cksum == cksum) return 1;
395
396 missed_paths++;
397 return 0;
398
399 }
400
401
402 /* Find first power of two greater or equal to val. */
403
next_p2(u32 val)404 static u32 next_p2(u32 val) {
405
406 u32 ret = 1;
407 while (val > ret) ret <<= 1;
408 return ret;
409
410 }
411
412
413 /* Actually minimize! */
414
minimize(char ** argv)415 static void minimize(char** argv) {
416
417 static u32 alpha_map[256];
418
419 u8* tmp_buf = ck_alloc_nozero(in_len);
420 u32 orig_len = in_len, stage_o_len;
421
422 u32 del_len, set_len, del_pos, set_pos, i, alpha_size, cur_pass = 0;
423 u32 syms_removed, alpha_del0 = 0, alpha_del1, alpha_del2, alpha_d_total = 0;
424 u8 changed_any, prev_del;
425
426 /***********************
427 * BLOCK NORMALIZATION *
428 ***********************/
429
430 set_len = next_p2(in_len / TMIN_SET_STEPS);
431 set_pos = 0;
432
433 if (set_len < TMIN_SET_MIN_SIZE) set_len = TMIN_SET_MIN_SIZE;
434
435 ACTF(cBRI "Stage #0: " cRST "One-time block normalization...");
436
437 while (set_pos < in_len) {
438
439 u8 res;
440 u32 use_len = MIN(set_len, in_len - set_pos);
441
442 for (i = 0; i < use_len; i++)
443 if (in_data[set_pos + i] != '0') break;
444
445 if (i != use_len) {
446
447 memcpy(tmp_buf, in_data, in_len);
448 memset(tmp_buf + set_pos, '0', use_len);
449
450 res = run_target(argv, tmp_buf, in_len, 0);
451
452 if (res) {
453
454 memset(in_data + set_pos, '0', use_len);
455 changed_any = 1;
456 alpha_del0 += use_len;
457
458 }
459
460 }
461
462 set_pos += set_len;
463
464 }
465
466 alpha_d_total += alpha_del0;
467
468 OKF("Block normalization complete, %u byte%s replaced.", alpha_del0,
469 alpha_del0 == 1 ? "" : "s");
470
471 next_pass:
472
473 ACTF(cYEL "--- " cBRI "Pass #%u " cYEL "---", ++cur_pass);
474 changed_any = 0;
475
476 /******************
477 * BLOCK DELETION *
478 ******************/
479
480 del_len = next_p2(in_len / TRIM_START_STEPS);
481 stage_o_len = in_len;
482
483 ACTF(cBRI "Stage #1: " cRST "Removing blocks of data...");
484
485 next_del_blksize:
486
487 if (!del_len) del_len = 1;
488 del_pos = 0;
489 prev_del = 1;
490
491 SAYF(cGRA " Block length = %u, remaining size = %u\n" cRST,
492 del_len, in_len);
493
494 while (del_pos < in_len) {
495
496 u8 res;
497 s32 tail_len;
498
499 tail_len = in_len - del_pos - del_len;
500 if (tail_len < 0) tail_len = 0;
501
502 /* If we have processed at least one full block (initially, prev_del == 1),
503 and we did so without deleting the previous one, and we aren't at the
504 very end of the buffer (tail_len > 0), and the current block is the same
505 as the previous one... skip this step as a no-op. */
506
507 if (!prev_del && tail_len && !memcmp(in_data + del_pos - del_len,
508 in_data + del_pos, del_len)) {
509
510 del_pos += del_len;
511 continue;
512
513 }
514
515 prev_del = 0;
516
517 /* Head */
518 memcpy(tmp_buf, in_data, del_pos);
519
520 /* Tail */
521 memcpy(tmp_buf + del_pos, in_data + del_pos + del_len, tail_len);
522
523 res = run_target(argv, tmp_buf, del_pos + tail_len, 0);
524
525 if (res) {
526
527 memcpy(in_data, tmp_buf, del_pos + tail_len);
528 prev_del = 1;
529 in_len = del_pos + tail_len;
530
531 changed_any = 1;
532
533 } else del_pos += del_len;
534
535 }
536
537 if (del_len > 1 && in_len >= 1) {
538
539 del_len /= 2;
540 goto next_del_blksize;
541
542 }
543
544 OKF("Block removal complete, %u bytes deleted.", stage_o_len - in_len);
545
546 if (!in_len && changed_any)
547 WARNF(cLRD "Down to zero bytes - check the command line and mem limit!" cRST);
548
549 if (cur_pass > 1 && !changed_any) goto finalize_all;
550
551 /*************************
552 * ALPHABET MINIMIZATION *
553 *************************/
554
555 alpha_size = 0;
556 alpha_del1 = 0;
557 syms_removed = 0;
558
559 memset(alpha_map, 0, 256 * sizeof(u32));
560
561 for (i = 0; i < in_len; i++) {
562 if (!alpha_map[in_data[i]]) alpha_size++;
563 alpha_map[in_data[i]]++;
564 }
565
566 ACTF(cBRI "Stage #2: " cRST "Minimizing symbols (%u code point%s)...",
567 alpha_size, alpha_size == 1 ? "" : "s");
568
569 for (i = 0; i < 256; i++) {
570
571 u32 r;
572 u8 res;
573
574 if (i == '0' || !alpha_map[i]) continue;
575
576 memcpy(tmp_buf, in_data, in_len);
577
578 for (r = 0; r < in_len; r++)
579 if (tmp_buf[r] == i) tmp_buf[r] = '0';
580
581 res = run_target(argv, tmp_buf, in_len, 0);
582
583 if (res) {
584
585 memcpy(in_data, tmp_buf, in_len);
586 syms_removed++;
587 alpha_del1 += alpha_map[i];
588 changed_any = 1;
589
590 }
591
592 }
593
594 alpha_d_total += alpha_del1;
595
596 OKF("Symbol minimization finished, %u symbol%s (%u byte%s) replaced.",
597 syms_removed, syms_removed == 1 ? "" : "s",
598 alpha_del1, alpha_del1 == 1 ? "" : "s");
599
600 /**************************
601 * CHARACTER MINIMIZATION *
602 **************************/
603
604 alpha_del2 = 0;
605
606 ACTF(cBRI "Stage #3: " cRST "Character minimization...");
607
608 memcpy(tmp_buf, in_data, in_len);
609
610 for (i = 0; i < in_len; i++) {
611
612 u8 res, orig = tmp_buf[i];
613
614 if (orig == '0') continue;
615 tmp_buf[i] = '0';
616
617 res = run_target(argv, tmp_buf, in_len, 0);
618
619 if (res) {
620
621 in_data[i] = '0';
622 alpha_del2++;
623 changed_any = 1;
624
625 } else tmp_buf[i] = orig;
626
627 }
628
629 alpha_d_total += alpha_del2;
630
631 OKF("Character minimization done, %u byte%s replaced.",
632 alpha_del2, alpha_del2 == 1 ? "" : "s");
633
634 if (changed_any) goto next_pass;
635
636 finalize_all:
637
638 SAYF("\n"
639 cGRA " File size reduced by : " cRST "%0.02f%% (to %u byte%s)\n"
640 cGRA " Characters simplified : " cRST "%0.02f%%\n"
641 cGRA " Number of execs done : " cRST "%u\n"
642 cGRA " Fruitless execs : " cRST "path=%u crash=%u hang=%s%u\n\n",
643 100 - ((double)in_len) * 100 / orig_len, in_len, in_len == 1 ? "" : "s",
644 ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1),
645 total_execs, missed_paths, missed_crashes, missed_hangs ? cLRD : "",
646 missed_hangs);
647
648 if (total_execs > 50 && missed_hangs * 10 > total_execs)
649 WARNF(cLRD "Frequent timeouts - results may be skewed." cRST);
650
651 }
652
653
654
655 /* Handle Ctrl-C and the like. */
656
handle_stop_sig(int sig)657 static void handle_stop_sig(int sig) {
658
659 stop_soon = 1;
660
661 if (child_pid > 0) kill(child_pid, SIGKILL);
662
663 }
664
665
666 /* Do basic preparations - persistent fds, filenames, etc. */
667
set_up_environment(void)668 static void set_up_environment(void) {
669
670 u8* x;
671
672 dev_null_fd = open("/dev/null", O_RDWR);
673 if (dev_null_fd < 0) PFATAL("Unable to open /dev/null");
674
675 if (!prog_in) {
676
677 u8* use_dir = ".";
678
679 if (access(use_dir, R_OK | W_OK | X_OK)) {
680
681 use_dir = getenv("TMPDIR");
682 if (!use_dir) use_dir = "/tmp";
683
684 }
685
686 prog_in = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, getpid());
687
688 }
689
690 /* Set sane defaults... */
691
692 x = getenv("ASAN_OPTIONS");
693
694 if (x) {
695
696 if (!strstr(x, "abort_on_error=1"))
697 FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
698
699 if (!strstr(x, "symbolize=0"))
700 FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
701
702 }
703
704 x = getenv("MSAN_OPTIONS");
705
706 if (x) {
707
708 if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR)))
709 FATAL("Custom MSAN_OPTIONS set without exit_code="
710 STRINGIFY(MSAN_ERROR) " - please fix!");
711
712 if (!strstr(x, "symbolize=0"))
713 FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
714
715 }
716
717 setenv("ASAN_OPTIONS", "abort_on_error=1:"
718 "detect_leaks=0:"
719 "symbolize=0:"
720 "allocator_may_return_null=1", 0);
721
722 setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
723 "symbolize=0:"
724 "abort_on_error=1:"
725 "allocator_may_return_null=1:"
726 "msan_track_origins=0", 0);
727
728 if (getenv("AFL_PRELOAD")) {
729 setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
730 setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
731 }
732
733 }
734
735
736 /* Setup signal handlers, duh. */
737
setup_signal_handlers(void)738 static void setup_signal_handlers(void) {
739
740 struct sigaction sa;
741
742 sa.sa_handler = NULL;
743 sa.sa_flags = SA_RESTART;
744 sa.sa_sigaction = NULL;
745
746 sigemptyset(&sa.sa_mask);
747
748 /* Various ways of saying "stop". */
749
750 sa.sa_handler = handle_stop_sig;
751 sigaction(SIGHUP, &sa, NULL);
752 sigaction(SIGINT, &sa, NULL);
753 sigaction(SIGTERM, &sa, NULL);
754
755 /* Exec timeout notifications. */
756
757 sa.sa_handler = handle_timeout;
758 sigaction(SIGALRM, &sa, NULL);
759
760 }
761
762
763 /* Detect @@ in args. */
764
detect_file_args(char ** argv)765 static void detect_file_args(char** argv) {
766
767 u32 i = 0;
768 u8* cwd = getcwd(NULL, 0);
769
770 if (!cwd) PFATAL("getcwd() failed");
771
772 while (argv[i]) {
773
774 u8* aa_loc = strstr(argv[i], "@@");
775
776 if (aa_loc) {
777
778 u8 *aa_subst, *n_arg;
779
780 /* Be sure that we're always using fully-qualified paths. */
781
782 if (prog_in[0] == '/') aa_subst = prog_in;
783 else aa_subst = alloc_printf("%s/%s", cwd, prog_in);
784
785 /* Construct a replacement argv value. */
786
787 *aa_loc = 0;
788 n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
789 argv[i] = n_arg;
790 *aa_loc = '@';
791
792 if (prog_in[0] != '/') ck_free(aa_subst);
793
794 }
795
796 i++;
797
798 }
799
800 free(cwd); /* not tracked */
801
802 }
803
804
805 /* Display usage hints. */
806
usage(u8 * argv0)807 static void usage(u8* argv0) {
808
809 SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
810
811 "Required parameters:\n\n"
812
813 " -i file - input test case to be shrunk by the tool\n"
814 " -o file - final output location for the minimized data\n\n"
815
816 "Execution control settings:\n\n"
817
818 " -f file - input file read by the tested program (stdin)\n"
819 " -t msec - timeout for each run (%u ms)\n"
820 " -m megs - memory limit for child process (%u MB)\n"
821 " -Q - use binary-only instrumentation (QEMU mode)\n\n"
822
823 "Minimization settings:\n\n"
824
825 " -e - solve for edge coverage only, ignore hit counts\n"
826 " -x - treat non-zero exit codes as crashes\n\n"
827
828 "For additional tips, please consult %s/README.\n\n",
829
830 argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
831
832 exit(1);
833
834 }
835
836
837 /* Find binary. */
838
find_binary(u8 * fname)839 static void find_binary(u8* fname) {
840
841 u8* env_path = 0;
842 struct stat st;
843
844 if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
845
846 target_path = ck_strdup(fname);
847
848 if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
849 !(st.st_mode & 0111) || st.st_size < 4)
850 FATAL("Program '%s' not found or not executable", fname);
851
852 } else {
853
854 while (env_path) {
855
856 u8 *cur_elem, *delim = strchr(env_path, ':');
857
858 if (delim) {
859
860 cur_elem = ck_alloc(delim - env_path + 1);
861 memcpy(cur_elem, env_path, delim - env_path);
862 delim++;
863
864 } else cur_elem = ck_strdup(env_path);
865
866 env_path = delim;
867
868 if (cur_elem[0])
869 target_path = alloc_printf("%s/%s", cur_elem, fname);
870 else
871 target_path = ck_strdup(fname);
872
873 ck_free(cur_elem);
874
875 if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
876 (st.st_mode & 0111) && st.st_size >= 4) break;
877
878 ck_free(target_path);
879 target_path = 0;
880
881 }
882
883 if (!target_path) FATAL("Program '%s' not found or not executable", fname);
884
885 }
886
887 }
888
889
890 /* Fix up argv for QEMU. */
891
get_qemu_argv(u8 * own_loc,char ** argv,int argc)892 static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
893
894 char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
895 u8 *tmp, *cp, *rsl, *own_copy;
896
897 /* Workaround for a QEMU stability glitch. */
898
899 setenv("QEMU_LOG", "nochain", 1);
900
901 memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
902
903 /* Now we need to actually find qemu for argv[0]. */
904
905 new_argv[2] = target_path;
906 new_argv[1] = "--";
907
908 tmp = getenv("AFL_PATH");
909
910 if (tmp) {
911
912 cp = alloc_printf("%s/afl-qemu-trace", tmp);
913
914 if (access(cp, X_OK))
915 FATAL("Unable to find '%s'", tmp);
916
917 target_path = new_argv[0] = cp;
918 return new_argv;
919
920 }
921
922 own_copy = ck_strdup(own_loc);
923 rsl = strrchr(own_copy, '/');
924
925 if (rsl) {
926
927 *rsl = 0;
928
929 cp = alloc_printf("%s/afl-qemu-trace", own_copy);
930 ck_free(own_copy);
931
932 if (!access(cp, X_OK)) {
933
934 target_path = new_argv[0] = cp;
935 return new_argv;
936
937 }
938
939 } else ck_free(own_copy);
940
941 if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
942
943 target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace";
944 return new_argv;
945
946 }
947
948 FATAL("Unable to find 'afl-qemu-trace'.");
949
950 }
951
952
953 /* Read mask bitmap from file. This is for the -B option. */
954
read_bitmap(u8 * fname)955 static void read_bitmap(u8* fname) {
956
957 s32 fd = open(fname, O_RDONLY);
958
959 if (fd < 0) PFATAL("Unable to open '%s'", fname);
960
961 ck_read(fd, mask_bitmap, MAP_SIZE, fname);
962
963 close(fd);
964
965 }
966
967
968
969 /* Main entry point */
970
main(int argc,char ** argv)971 int main(int argc, char** argv) {
972
973 s32 opt;
974 u8 mem_limit_given = 0, timeout_given = 0, qemu_mode = 0;
975 char** use_argv;
976
977 doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
978
979 SAYF(cCYA "afl-tmin " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
980
981 while ((opt = getopt(argc,argv,"+i:o:f:m:t:B:xeQ")) > 0)
982
983 switch (opt) {
984
985 case 'i':
986
987 if (in_file) FATAL("Multiple -i options not supported");
988 in_file = optarg;
989 break;
990
991 case 'o':
992
993 if (out_file) FATAL("Multiple -o options not supported");
994 out_file = optarg;
995 break;
996
997 case 'f':
998
999 if (prog_in) FATAL("Multiple -f options not supported");
1000 use_stdin = 0;
1001 prog_in = optarg;
1002 break;
1003
1004 case 'e':
1005
1006 if (edges_only) FATAL("Multiple -e options not supported");
1007 edges_only = 1;
1008 break;
1009
1010 case 'x':
1011
1012 if (exit_crash) FATAL("Multiple -x options not supported");
1013 exit_crash = 1;
1014 break;
1015
1016 case 'm': {
1017
1018 u8 suffix = 'M';
1019
1020 if (mem_limit_given) FATAL("Multiple -m options not supported");
1021 mem_limit_given = 1;
1022
1023 if (!strcmp(optarg, "none")) {
1024
1025 mem_limit = 0;
1026 break;
1027
1028 }
1029
1030 if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
1031 optarg[0] == '-') FATAL("Bad syntax used for -m");
1032
1033 switch (suffix) {
1034
1035 case 'T': mem_limit *= 1024 * 1024; break;
1036 case 'G': mem_limit *= 1024; break;
1037 case 'k': mem_limit /= 1024; break;
1038 case 'M': break;
1039
1040 default: FATAL("Unsupported suffix or bad syntax for -m");
1041
1042 }
1043
1044 if (mem_limit < 5) FATAL("Dangerously low value of -m");
1045
1046 if (sizeof(rlim_t) == 4 && mem_limit > 2000)
1047 FATAL("Value of -m out of range on 32-bit systems");
1048
1049 }
1050
1051 break;
1052
1053 case 't':
1054
1055 if (timeout_given) FATAL("Multiple -t options not supported");
1056 timeout_given = 1;
1057
1058 exec_tmout = atoi(optarg);
1059
1060 if (exec_tmout < 10 || optarg[0] == '-')
1061 FATAL("Dangerously low value of -t");
1062
1063 break;
1064
1065 case 'Q':
1066
1067 if (qemu_mode) FATAL("Multiple -Q options not supported");
1068 if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU;
1069
1070 qemu_mode = 1;
1071 break;
1072
1073 case 'B': /* load bitmap */
1074
1075 /* This is a secret undocumented option! It is speculated to be useful
1076 if you have a baseline "boring" input file and another "interesting"
1077 file you want to minimize.
1078
1079 You can dump a binary bitmap for the boring file using
1080 afl-showmap -b, and then load it into afl-tmin via -B. The minimizer
1081 will then minimize to preserve only the edges that are unique to
1082 the interesting input file, but ignoring everything from the
1083 original map.
1084
1085 The option may be extended and made more official if it proves
1086 to be useful. */
1087
1088 if (mask_bitmap) FATAL("Multiple -B options not supported");
1089 mask_bitmap = ck_alloc(MAP_SIZE);
1090 read_bitmap(optarg);
1091 break;
1092
1093 default:
1094
1095 usage(argv[0]);
1096
1097 }
1098
1099 if (optind == argc || !in_file || !out_file) usage(argv[0]);
1100
1101 setup_shm();
1102 setup_signal_handlers();
1103
1104 set_up_environment();
1105
1106 find_binary(argv[optind]);
1107 detect_file_args(argv + optind);
1108
1109 if (qemu_mode)
1110 use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
1111 else
1112 use_argv = argv + optind;
1113
1114 exact_mode = !!getenv("AFL_TMIN_EXACT");
1115
1116 SAYF("\n");
1117
1118 read_initial_file();
1119
1120 ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
1121 mem_limit, exec_tmout, edges_only ? ", edges only" : "");
1122
1123 run_target(use_argv, in_data, in_len, 1);
1124
1125 if (child_timed_out)
1126 FATAL("Target binary times out (adjusting -t may help).");
1127
1128 if (!crash_mode) {
1129
1130 OKF("Program terminates normally, minimizing in "
1131 cCYA "instrumented" cRST " mode.");
1132
1133 if (!anything_set()) FATAL("No instrumentation detected.");
1134
1135 } else {
1136
1137 OKF("Program exits with a signal, minimizing in " cMGN "%scrash" cRST
1138 " mode.", exact_mode ? "EXACT " : "");
1139
1140 }
1141
1142 minimize(use_argv);
1143
1144 ACTF("Writing output to '%s'...", out_file);
1145
1146 unlink(prog_in);
1147 prog_in = NULL;
1148
1149 close(write_to_file(out_file, in_data, in_len));
1150
1151 OKF("We're done here. Have a nice day!\n");
1152
1153 exit(0);
1154
1155 }
1156
1157