1 /*
2 american fuzzy lop++ - initialization related routines
3 ------------------------------------------------------
4
5 Originally written by Michal Zalewski
6
7 Now maintained by Marc Heuse <mh@mh-sec.de>,
8 Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
9 Andrea Fioraldi <andreafioraldi@gmail.com>
10
11 Copyright 2016, 2017 Google Inc. All rights reserved.
12 Copyright 2019-2022 AFLplusplus Project. All rights reserved.
13
14 Licensed under the Apache License, Version 2.0 (the "License");
15 you may not use this file except in compliance with the License.
16 You may obtain a copy of the License at:
17
18 https://www.apache.org/licenses/LICENSE-2.0
19
20 This is the real deal: the program takes an instrumented binary and
21 attempts a variety of basic fuzzing tricks, paying close attention to
22 how they affect the execution path.
23
24 */
25
26 #include "afl-fuzz.h"
27 #include <limits.h>
28 #include "cmplog.h"
29
30 #ifdef HAVE_AFFINITY
31
32 /* bind process to a specific cpu. Returns 0 on failure. */
33
bind_cpu(afl_state_t * afl,s32 cpuid)34 static u8 bind_cpu(afl_state_t *afl, s32 cpuid) {
35
36 #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
37 cpu_set_t c;
38 #elif defined(__NetBSD__)
39 cpuset_t *c;
40 #elif defined(__sun)
41 psetid_t c;
42 #endif
43
44 afl->cpu_aff = cpuid;
45
46 #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
47
48 CPU_ZERO(&c);
49 CPU_SET(cpuid, &c);
50
51 #elif defined(__NetBSD__)
52
53 c = cpuset_create();
54 if (c == NULL) { PFATAL("cpuset_create failed"); }
55 cpuset_set(cpuid, c);
56
57 #elif defined(__sun)
58
59 pset_create(&c);
60 if (pset_assign(c, cpuid, NULL)) { PFATAL("pset_assign failed"); }
61
62 #endif
63
64 #if defined(__linux__)
65
66 return (sched_setaffinity(0, sizeof(c), &c) == 0);
67
68 #elif defined(__FreeBSD__) || defined(__DragonFly__)
69
70 return (pthread_setaffinity_np(pthread_self(), sizeof(c), &c) == 0);
71
72 #elif defined(__NetBSD__)
73
74 if (pthread_setaffinity_np(pthread_self(), cpuset_size(c), c)) {
75
76 cpuset_destroy(c);
77 return 0;
78
79 }
80
81 cpuset_destroy(c);
82 return 1;
83
84 #elif defined(__sun)
85
86 if (pset_bind(c, P_PID, getpid(), NULL)) {
87
88 pset_destroy(c);
89 return 0;
90
91 }
92
93 pset_destroy(c);
94 return 1;
95
96 #else
97
98 // this will need something for other platforms
99 // TODO: Solaris/Illumos has processor_bind ... might worth a try
100 WARNF("Cannot bind to CPU yet on this platform.");
101 return 1;
102
103 #endif
104
105 }
106
107 /* Build a list of processes bound to specific cores. Returns -1 if nothing
108 can be found. Assumes an upper bound of 4k CPUs. */
109
bind_to_free_cpu(afl_state_t * afl)110 void bind_to_free_cpu(afl_state_t *afl) {
111
112 u8 cpu_used[4096] = {0};
113 u8 lockfile[PATH_MAX] = "";
114 s32 i;
115
116 if (afl->afl_env.afl_no_affinity && !afl->afl_env.afl_try_affinity) {
117
118 if (afl->cpu_to_bind != -1) {
119
120 FATAL("-b and AFL_NO_AFFINITY are mututally exclusive.");
121
122 }
123
124 WARNF("Not binding to a CPU core (AFL_NO_AFFINITY set).");
125 return;
126
127 }
128
129 if (afl->cpu_to_bind != -1) {
130
131 if (!bind_cpu(afl, afl->cpu_to_bind)) {
132
133 if (afl->afl_env.afl_try_affinity) {
134
135 WARNF(
136 "Could not bind to requested CPU %d! Make sure you passed a valid "
137 "-b.",
138 afl->cpu_to_bind);
139
140 } else {
141
142 FATAL(
143 "Could not bind to requested CPU %d! Make sure you passed a valid "
144 "-b.",
145 afl->cpu_to_bind);
146
147 }
148
149 }
150
151 return;
152
153 }
154
155 if (afl->cpu_core_count < 2) { return; }
156
157 if (afl->sync_id) {
158
159 s32 lockfd, first = 1;
160
161 snprintf(lockfile, sizeof(lockfile), "%s/.affinity_lock", afl->sync_dir);
162 setenv(CPU_AFFINITY_ENV_VAR, lockfile, 1);
163
164 do {
165
166 if ((lockfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL,
167 DEFAULT_PERMISSION)) < 0) {
168
169 if (first) {
170
171 WARNF("CPU affinity lock file present, waiting ...");
172 first = 0;
173
174 }
175
176 usleep(1000);
177
178 }
179
180 } while (lockfd < 0);
181
182 close(lockfd);
183
184 }
185
186 #if defined(__linux__)
187
188 DIR * d;
189 struct dirent *de;
190 d = opendir("/proc");
191
192 if (!d) {
193
194 if (lockfile[0]) unlink(lockfile);
195 WARNF("Unable to access /proc - can't scan for free CPU cores.");
196 return;
197
198 }
199
200 ACTF("Checking CPU core loadout...");
201
202 /* Scan all /proc/<pid>/status entries, checking for Cpus_allowed_list.
203 Flag all processes bound to a specific CPU using cpu_used[]. This will
204 fail for some exotic binding setups, but is likely good enough in almost
205 all real-world use cases. */
206
207 while ((de = readdir(d))) {
208
209 u8 fn[PATH_MAX];
210 FILE *f;
211 u8 tmp[MAX_LINE];
212 u8 has_vmsize = 0;
213
214 if (!isdigit(de->d_name[0])) { continue; }
215
216 snprintf(fn, PATH_MAX, "/proc/%s/status", de->d_name);
217
218 if (!(f = fopen(fn, "r"))) { continue; }
219
220 while (fgets(tmp, MAX_LINE, f)) {
221
222 u32 hval;
223
224 /* Processes without VmSize are probably kernel tasks. */
225
226 if (!strncmp(tmp, "VmSize:\t", 8)) { has_vmsize = 1; }
227
228 if (!strncmp(tmp, "Cpus_allowed_list:\t", 19) && !strchr(tmp, '-') &&
229 !strchr(tmp, ',') && sscanf(tmp + 19, "%u", &hval) == 1 &&
230 hval < sizeof(cpu_used) && has_vmsize) {
231
232 cpu_used[hval] = 1;
233 break;
234
235 }
236
237 }
238
239 fclose(f);
240
241 }
242
243 closedir(d);
244
245 #elif defined(__FreeBSD__) || defined(__DragonFly__)
246
247 struct kinfo_proc *procs;
248 size_t nprocs;
249 size_t proccount;
250 int s_name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
251 size_t s_name_l = sizeof(s_name) / sizeof(s_name[0]);
252
253 if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) {
254
255 if (lockfile[0]) unlink(lockfile);
256 return;
257
258 }
259
260 proccount = nprocs / sizeof(*procs);
261 nprocs = nprocs * 4 / 3;
262
263 procs = ck_alloc(nprocs);
264 if (sysctl(s_name, s_name_l, procs, &nprocs, NULL, 0) != 0) {
265
266 if (lockfile[0]) unlink(lockfile);
267 ck_free(procs);
268 return;
269
270 }
271
272 for (i = 0; i < (s32)proccount; i++) {
273
274 #if defined(__FreeBSD__)
275
276 if (!strcmp(procs[i].ki_comm, "idle")) continue;
277
278 // fix when ki_oncpu = -1
279 s32 oncpu;
280 oncpu = procs[i].ki_oncpu;
281 if (oncpu == -1) oncpu = procs[i].ki_lastcpu;
282
283 if (oncpu != -1 && oncpu < (s32)sizeof(cpu_used) && procs[i].ki_pctcpu > 60)
284 cpu_used[oncpu] = 1;
285
286 #elif defined(__DragonFly__)
287
288 if (procs[i].kp_lwp.kl_cpuid < (s32)sizeof(cpu_used) &&
289 procs[i].kp_lwp.kl_pctcpu > 10)
290 cpu_used[procs[i].kp_lwp.kl_cpuid] = 1;
291
292 #endif
293
294 }
295
296 ck_free(procs);
297
298 #elif defined(__NetBSD__)
299
300 struct kinfo_proc2 *procs;
301 size_t nprocs;
302 size_t proccount;
303 int s_name[] = {
304
305 CTL_KERN, KERN_PROC2, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), 0};
306 size_t s_name_l = sizeof(s_name) / sizeof(s_name[0]);
307
308 if (sysctl(s_name, s_name_l, NULL, &nprocs, NULL, 0) != 0) {
309
310 if (lockfile[0]) unlink(lockfile);
311 return;
312
313 }
314
315 proccount = nprocs / sizeof(struct kinfo_proc2);
316 procs = ck_alloc(nprocs * sizeof(struct kinfo_proc2));
317 s_name[5] = proccount;
318
319 if (sysctl(s_name, s_name_l, procs, &nprocs, NULL, 0) != 0) {
320
321 if (lockfile[0]) unlink(lockfile);
322 ck_free(procs);
323 return;
324
325 }
326
327 for (i = 0; i < (s32)proccount; i++) {
328
329 if (procs[i].p_cpuid < sizeof(cpu_used) && procs[i].p_pctcpu > 0)
330 cpu_used[procs[i].p_cpuid] = 1;
331
332 }
333
334 ck_free(procs);
335
336 #elif defined(__sun)
337
338 kstat_named_t *n;
339 kstat_ctl_t * m;
340 kstat_t * k;
341 cpu_stat_t cs;
342 u32 ncpus;
343
344 m = kstat_open();
345
346 if (!m) FATAL("kstat_open failed");
347
348 k = kstat_lookup(m, "unix", 0, "system_misc");
349
350 if (!k) {
351
352 if (lockfile[0]) unlink(lockfile);
353 kstat_close(m);
354 return;
355
356 }
357
358 if (kstat_read(m, k, NULL)) {
359
360 if (lockfile[0]) unlink(lockfile);
361 kstat_close(m);
362 return;
363
364 }
365
366 n = kstat_data_lookup(k, "ncpus");
367 ncpus = n->value.i32;
368
369 if (ncpus > sizeof(cpu_used)) ncpus = sizeof(cpu_used);
370
371 for (i = 0; i < (s32)ncpus; i++) {
372
373 k = kstat_lookup(m, "cpu_stat", i, NULL);
374 if (kstat_read(m, k, &cs)) {
375
376 if (lockfile[0]) unlink(lockfile);
377 kstat_close(m);
378 return;
379
380 }
381
382 if (cs.cpu_sysinfo.cpu[CPU_IDLE] > 0) continue;
383
384 if (cs.cpu_sysinfo.cpu[CPU_USER] > 0 || cs.cpu_sysinfo.cpu[CPU_KERNEL] > 0)
385 cpu_used[i] = 1;
386
387 }
388
389 kstat_close(m);
390
391 #else
392 #warning \
393 "For this platform we do not have free CPU binding code yet. If possible, please supply a PR to https://github.com/AFLplusplus/AFLplusplus"
394 #endif
395
396 #if !defined(__aarch64__) && !defined(__arm__) && !defined(__arm64__)
397
398 for (i = 0; i < afl->cpu_core_count; i++) {
399
400 #else
401
402 /* many ARM devices have performance and efficiency cores, the slower
403 efficiency cores seem to always come first */
404
405 for (i = afl->cpu_core_count - 1; i > -1; i--) {
406
407 #endif
408
409 if (cpu_used[i]) { continue; }
410
411 OKF("Found a free CPU core, try binding to #%u.", i);
412
413 if (bind_cpu(afl, i)) {
414
415 #ifdef __linux__
416 if (afl->fsrv.nyx_mode) { afl->fsrv.nyx_bind_cpu_id = i; }
417 #endif
418 /* Success :) */
419 break;
420
421 }
422
423 WARNF("setaffinity failed to CPU %d, trying next CPU", i);
424
425 }
426
427 if (lockfile[0]) unlink(lockfile);
428
429 if (i == afl->cpu_core_count || i == -1) {
430
431 SAYF("\n" cLRD "[-] " cRST
432 "Uh-oh, looks like all %d CPU cores on your system are allocated to\n"
433 " other instances of afl-fuzz (or similar CPU-locked tasks). "
434 "Starting\n"
435 " another fuzzer on this machine is probably a bad plan.\n"
436 "%s",
437 afl->cpu_core_count,
438 afl->afl_env.afl_try_affinity ? ""
439 : " If you are sure, you can set "
440 "AFL_NO_AFFINITY and try again.\n");
441
442 if (!afl->afl_env.afl_try_affinity) { FATAL("No more free CPU cores"); }
443
444 }
445
446 }
447
448 #endif /* HAVE_AFFINITY */
449
450 /* Shuffle an array of pointers. Might be slightly biased. */
451
452 static void shuffle_ptrs(afl_state_t *afl, void **ptrs, u32 cnt) {
453
454 u32 i;
455
456 for (i = 0; i < cnt - 2; ++i) {
457
458 u32 j = i + rand_below(afl, cnt - i);
459 void *s = ptrs[i];
460 ptrs[i] = ptrs[j];
461 ptrs[j] = s;
462
463 }
464
465 }
466
467 /* Read all testcases from foreign input directories, then queue them for
468 testing. Called at startup and at sync intervals.
469 Does not descend into subdirectories! */
470
471 void read_foreign_testcases(afl_state_t *afl, int first) {
472
473 if (!afl->foreign_sync_cnt) return;
474
475 struct dirent **nl;
476 s32 nl_cnt;
477 u32 i, iter;
478
479 u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
480 u8 foreign_name[16];
481
482 for (iter = 0; iter < afl->foreign_sync_cnt; iter++) {
483
484 if (afl->foreign_syncs[iter].dir && afl->foreign_syncs[iter].dir[0]) {
485
486 if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir);
487 time_t mtime_max = 0;
488
489 u8 *name = strrchr(afl->foreign_syncs[iter].dir, '/');
490 if (!name) {
491
492 name = afl->foreign_syncs[iter].dir;
493
494 } else {
495
496 ++name;
497
498 }
499
500 if (!strcmp(name, "queue") || !strcmp(name, "out") ||
501 !strcmp(name, "default")) {
502
503 snprintf(foreign_name, sizeof(foreign_name), "foreign_%u", iter);
504
505 } else {
506
507 snprintf(foreign_name, sizeof(foreign_name), "%s_%u", name, iter);
508
509 }
510
511 /* We do not use sorting yet and do a more expensive mtime check instead.
512 a mtimesort() implementation would be better though. */
513
514 nl_cnt = scandir(afl->foreign_syncs[iter].dir, &nl, NULL, NULL);
515
516 if (nl_cnt < 0) {
517
518 if (first) {
519
520 WARNF("Unable to open directory '%s'", afl->foreign_syncs[iter].dir);
521 sleep(1);
522
523 }
524
525 continue;
526
527 }
528
529 if (nl_cnt == 0) {
530
531 if (first) {
532
533 WARNF("directory %s is currently empty",
534 afl->foreign_syncs[iter].dir);
535
536 }
537
538 continue;
539
540 }
541
542 /* Show stats */
543
544 snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "foreign sync %u", iter);
545
546 afl->stage_name = afl->stage_name_buf;
547 afl->stage_cur = 0;
548 afl->stage_max = 0;
549
550 for (i = 0; i < (u32)nl_cnt; ++i) {
551
552 struct stat st;
553
554 u8 *fn2 =
555 alloc_printf("%s/%s", afl->foreign_syncs[iter].dir, nl[i]->d_name);
556
557 free(nl[i]); /* not tracked */
558
559 if (unlikely(lstat(fn2, &st) || access(fn2, R_OK))) {
560
561 if (first) PFATAL("Unable to access '%s'", fn2);
562 continue;
563
564 }
565
566 /* we detect new files by their mtime */
567 if (likely(st.st_mtime <= afl->foreign_syncs[iter].mtime)) {
568
569 ck_free(fn2);
570 continue;
571
572 }
573
574 /* This also takes care of . and .. */
575
576 if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
577
578 ck_free(fn2);
579 continue;
580
581 }
582
583 if (st.st_size > MAX_FILE) {
584
585 if (first) {
586
587 WARNF(
588 "Test case '%s' is too big (%s, limit is %s), skipping", fn2,
589 stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
590 stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
591
592 }
593
594 ck_free(fn2);
595 continue;
596
597 }
598
599 // lets do not use add_to_queue(afl, fn2, st.st_size, 0);
600 // as this could add duplicates of the startup input corpus
601
602 int fd = open(fn2, O_RDONLY);
603 if (fd < 0) {
604
605 ck_free(fn2);
606 continue;
607
608 }
609
610 u8 fault;
611 u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
612
613 if (mem == MAP_FAILED) {
614
615 ck_free(fn2);
616 continue;
617
618 }
619
620 u32 len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
621 fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
622 afl->syncing_party = foreign_name;
623 afl->queued_imported += save_if_interesting(afl, mem, len, fault);
624 afl->syncing_party = 0;
625 munmap(mem, st.st_size);
626 close(fd);
627
628 if (st.st_mtime > mtime_max) mtime_max = st.st_mtime;
629
630 }
631
632 afl->foreign_syncs[iter].mtime = mtime_max;
633 free(nl); /* not tracked */
634
635 }
636
637 }
638
639 if (first) {
640
641 afl->last_find_time = 0;
642 afl->queued_at_start = afl->queued_items;
643
644 }
645
646 }
647
648 /* Read all testcases from the input directory, then queue them for testing.
649 Called at startup. */
650
651 void read_testcases(afl_state_t *afl, u8 *directory) {
652
653 struct dirent **nl;
654 s32 nl_cnt, subdirs = 1;
655 u32 i;
656 u8 * fn1, *dir = directory;
657 u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
658
659 /* Auto-detect non-in-place resumption attempts. */
660
661 if (dir == NULL) {
662
663 fn1 = alloc_printf("%s/queue", afl->in_dir);
664 if (!access(fn1, F_OK)) {
665
666 afl->in_dir = fn1;
667 subdirs = 0;
668
669 } else {
670
671 ck_free(fn1);
672
673 }
674
675 dir = afl->in_dir;
676
677 }
678
679 ACTF("Scanning '%s'...", dir);
680
681 /* We use scandir() + alphasort() rather than readdir() because otherwise,
682 the ordering of test cases would vary somewhat randomly and would be
683 difficult to control. */
684
685 nl_cnt = scandir(dir, &nl, NULL, alphasort);
686
687 if (nl_cnt < 0 && directory == NULL) {
688
689 if (errno == ENOENT || errno == ENOTDIR) {
690
691 SAYF("\n" cLRD "[-] " cRST
692 "The input directory does not seem to be valid - try again. The "
693 "fuzzer needs\n"
694 " one or more test case to start with - ideally, a small file "
695 "under 1 kB\n"
696 " or so. The cases must be stored as regular files directly in "
697 "the input\n"
698 " directory.\n");
699
700 }
701
702 PFATAL("Unable to open '%s'", dir);
703
704 }
705
706 if (unlikely(afl->old_seed_selection && afl->shuffle_queue && nl_cnt > 1)) {
707
708 ACTF("Shuffling queue...");
709 shuffle_ptrs(afl, (void **)nl, nl_cnt);
710
711 }
712
713 if (nl_cnt) {
714
715 i = nl_cnt;
716 do {
717
718 --i;
719
720 struct stat st;
721 u8 dfn[PATH_MAX];
722 snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir,
723 nl[i]->d_name);
724 u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name);
725
726 u8 passed_det = 0;
727
728 if (lstat(fn2, &st) || access(fn2, R_OK)) {
729
730 PFATAL("Unable to access '%s'", fn2);
731
732 }
733
734 /* obviously we want to skip "descending" into . and .. directories,
735 however it is a good idea to skip also directories that start with
736 a dot */
737 if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') {
738
739 free(nl[i]); /* not tracked */
740 read_testcases(afl, fn2);
741 ck_free(fn2);
742 continue;
743
744 }
745
746 free(nl[i]);
747
748 if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
749
750 ck_free(fn2);
751 continue;
752
753 }
754
755 if (st.st_size > MAX_FILE) {
756
757 WARNF("Test case '%s' is too big (%s, limit is %s), partial reading",
758 fn2,
759 stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
760 stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
761
762 }
763
764 /* Check for metadata that indicates that deterministic fuzzing
765 is complete for this entry. We don't want to repeat deterministic
766 fuzzing when resuming aborted scans, because it would be pointless
767 and probably very time-consuming. */
768
769 if (!access(dfn, F_OK)) { passed_det = 1; }
770
771 add_to_queue(afl, fn2, st.st_size >= MAX_FILE ? MAX_FILE : st.st_size,
772 passed_det);
773
774 if (unlikely(afl->shm.cmplog_mode)) {
775
776 if (afl->cmplog_lvl == 1) {
777
778 if (!afl->cmplog_max_filesize ||
779 afl->cmplog_max_filesize < st.st_size) {
780
781 afl->cmplog_max_filesize = st.st_size;
782
783 }
784
785 } else if (afl->cmplog_lvl == 2) {
786
787 if (!afl->cmplog_max_filesize ||
788 afl->cmplog_max_filesize > st.st_size) {
789
790 afl->cmplog_max_filesize = st.st_size;
791
792 }
793
794 }
795
796 }
797
798 /*
799 if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
800
801 u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size,
802 HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
803 afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
804
805 }
806
807 */
808
809 } while (i > 0);
810
811 }
812
813 free(nl); /* not tracked */
814
815 if (!afl->queued_items && directory == NULL) {
816
817 SAYF("\n" cLRD "[-] " cRST
818 "Looks like there are no valid test cases in the input directory! The "
819 "fuzzer\n"
820 " needs one or more test case to start with - ideally, a small "
821 "file under\n"
822 " 1 kB or so. The cases must be stored as regular files directly "
823 "in the\n"
824 " input directory.\n");
825
826 FATAL("No usable test cases in '%s'", afl->in_dir);
827
828 }
829
830 if (unlikely(afl->shm.cmplog_mode)) {
831
832 if (afl->cmplog_max_filesize < 1024) {
833
834 afl->cmplog_max_filesize = 1024;
835
836 } else {
837
838 afl->cmplog_max_filesize = (((afl->cmplog_max_filesize >> 10) + 1) << 10);
839
840 }
841
842 }
843
844 afl->last_find_time = 0;
845 afl->queued_at_start = afl->queued_items;
846
847 }
848
849 /* Perform dry run of all test cases to confirm that the app is working as
850 expected. This is done only for the initial inputs, and only once. */
851
852 void perform_dry_run(afl_state_t *afl) {
853
854 struct queue_entry *q;
855 u32 cal_failures = 0, idx;
856 u8 * use_mem;
857
858 for (idx = 0; idx < afl->queued_items; idx++) {
859
860 q = afl->queue_buf[idx];
861 if (unlikely(!q || q->disabled)) { continue; }
862
863 u8 res;
864 s32 fd;
865
866 if (unlikely(!q->len)) {
867
868 WARNF("Skipping 0-sized entry in queue (%s)", q->fname);
869 continue;
870
871 }
872
873 if (afl->afl_env.afl_cmplog_only_new) { q->colorized = CMPLOG_LVL_MAX; }
874
875 u8 *fn = strrchr(q->fname, '/') + 1;
876
877 ACTF("Attempting dry run with '%s'...", fn);
878
879 fd = open(q->fname, O_RDONLY);
880 if (fd < 0) { PFATAL("Unable to open '%s'", q->fname); }
881
882 u32 read_len = MIN(q->len, (u32)MAX_FILE);
883 use_mem = afl_realloc(AFL_BUF_PARAM(in), read_len);
884 ck_read(fd, use_mem, read_len, q->fname);
885
886 close(fd);
887
888 res = calibrate_case(afl, q, use_mem, 0, 1);
889
890 if (afl->stop_soon) { return; }
891
892 if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) {
893
894 SAYF(cGRA " len = %u, map size = %u, exec speed = %llu us\n" cRST,
895 q->len, q->bitmap_size, q->exec_us);
896
897 }
898
899 switch (res) {
900
901 case FSRV_RUN_OK:
902
903 if (afl->crash_mode) { FATAL("Test case '%s' does *NOT* crash", fn); }
904
905 break;
906
907 case FSRV_RUN_TMOUT:
908
909 if (afl->timeout_given && !afl->afl_env.afl_exit_on_seed_issues) {
910
911 /* if we have a timeout but a timeout value was given then always
912 skip. The '+' meaning has been changed! */
913 WARNF("Test case results in a timeout (skipping)");
914 ++cal_failures;
915 q->cal_failed = CAL_CHANCES;
916 q->disabled = 1;
917 q->perf_score = 0;
918
919 if (!q->was_fuzzed) {
920
921 q->was_fuzzed = 1;
922 --afl->pending_not_fuzzed;
923 --afl->active_items;
924
925 }
926
927 break;
928
929 } else {
930
931 SAYF("\n" cLRD "[-] " cRST
932 "The program took more than %u ms to process one of the initial "
933 "test cases.\n"
934 " This is bad news; raising the limit with the -t option is "
935 "possible, but\n"
936 " will probably make the fuzzing process extremely slow.\n\n"
937
938 " If this test case is just a fluke, the other option is to "
939 "just avoid it\n"
940 " altogether, and find one that is less of a CPU hog.\n",
941 afl->fsrv.exec_tmout);
942
943 FATAL("Test case '%s' results in a timeout", fn);
944
945 }
946
947 case FSRV_RUN_CRASH:
948
949 if (afl->crash_mode) { break; }
950
951 if (afl->fsrv.mem_limit) {
952
953 u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
954
955 SAYF("\n" cLRD "[-] " cRST
956 "Oops, the program crashed with one of the test cases provided. "
957 "There are\n"
958 " several possible explanations:\n\n"
959
960 " - The test case causes known crashes under normal working "
961 "conditions. If\n"
962 " so, please remove it. The fuzzer should be seeded with "
963 "interesting\n"
964 " inputs - but not ones that cause an outright crash.\n\n"
965
966 " - The current memory limit (%s) is too low for this "
967 "program, causing\n"
968 " it to die due to OOM when parsing valid files. To fix "
969 "this, try\n"
970 " bumping it up with the -m setting in the command line. "
971 "If in doubt,\n"
972 " try something along the lines of:\n\n"
973
974 MSG_ULIMIT_USAGE
975 " /path/to/binary [...] <testcase )\n\n"
976
977 " Tip: you can use https://jwilk.net/software/recidivm to\n"
978 " estimate the required amount of virtual memory for the "
979 "binary. Also,\n"
980 " if you are using ASAN, set '-m 0'.\n\n"
981
982 " - In QEMU persistent mode the selected address(es) for the "
983 "loop are not\n"
984 " properly cleaning up variables and memory. Try adding\n"
985 " AFL_QEMU_PERSISTENT_GPR=1 or select better addresses in "
986 "the binary.\n\n"
987
988 MSG_FORK_ON_APPLE
989
990 " - Least likely, there is a horrible bug in the fuzzer. If "
991 "other options\n"
992 " fail, poke <afl-users@googlegroups.com> for "
993 "troubleshooting tips.\n",
994 stringify_mem_size(val_buf, sizeof(val_buf),
995 afl->fsrv.mem_limit << 20),
996 afl->fsrv.mem_limit - 1);
997
998 } else {
999
1000 SAYF("\n" cLRD "[-] " cRST
1001 "Oops, the program crashed with one of the test cases provided. "
1002 "There are\n"
1003 " several possible explanations:\n\n"
1004
1005 " - The test case causes known crashes under normal working "
1006 "conditions. If\n"
1007 " so, please remove it. The fuzzer should be seeded with "
1008 "interesting\n"
1009 " inputs - but not ones that cause an outright crash.\n\n"
1010
1011 " - In QEMU persistent mode the selected address(es) for the "
1012 "loop are not\n"
1013 " properly cleaning up variables and memory. Try adding\n"
1014 " AFL_QEMU_PERSISTENT_GPR=1 or select better addresses in "
1015 "the binary.\n\n"
1016
1017 MSG_FORK_ON_APPLE
1018
1019 " - Least likely, there is a horrible bug in the fuzzer. If "
1020 "other options\n"
1021 " fail, poke <afl-users@googlegroups.com> for "
1022 "troubleshooting tips.\n");
1023
1024 }
1025
1026 #undef MSG_ULIMIT_USAGE
1027 #undef MSG_FORK_ON_APPLE
1028
1029 if (afl->fsrv.uses_crash_exitcode) {
1030
1031 WARNF(
1032 "Test case '%s' results in a crash or AFL_CRASH_EXITCODE %d, "
1033 "skipping",
1034 fn, (int)(s8)afl->fsrv.crash_exitcode);
1035
1036 } else {
1037
1038 WARNF("Test case '%s' results in a crash, skipping", fn);
1039
1040 }
1041
1042 if (afl->afl_env.afl_exit_on_seed_issues) {
1043
1044 FATAL("As AFL_EXIT_ON_SEED_ISSUES is set, afl-fuzz exits.");
1045
1046 }
1047
1048 /* Remove from fuzzing queue but keep for splicing */
1049
1050 if (!q->was_fuzzed) {
1051
1052 q->was_fuzzed = 1;
1053 --afl->pending_not_fuzzed;
1054 --afl->active_items;
1055
1056 }
1057
1058 q->disabled = 1;
1059 q->perf_score = 0;
1060
1061 u32 i = 0;
1062 while (unlikely(i < afl->queued_items && afl->queue_buf[i] &&
1063 afl->queue_buf[i]->disabled)) {
1064
1065 ++i;
1066
1067 }
1068
1069 if (i < afl->queued_items && afl->queue_buf[i]) {
1070
1071 afl->queue = afl->queue_buf[i];
1072
1073 } else {
1074
1075 afl->queue = afl->queue_buf[0];
1076
1077 }
1078
1079 afl->max_depth = 0;
1080 for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) {
1081
1082 if (!afl->queue_buf[i]->disabled &&
1083 afl->queue_buf[i]->depth > afl->max_depth)
1084 afl->max_depth = afl->queue_buf[i]->depth;
1085
1086 }
1087
1088 break;
1089
1090 case FSRV_RUN_ERROR:
1091
1092 FATAL("Unable to execute target application ('%s')", afl->argv[0]);
1093
1094 case FSRV_RUN_NOINST:
1095 #ifdef __linux__
1096 if (afl->fsrv.nyx_mode && afl->fsrv.nyx_runner != NULL) {
1097
1098 afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner);
1099
1100 }
1101
1102 #endif
1103 FATAL("No instrumentation detected");
1104
1105 case FSRV_RUN_NOBITS:
1106
1107 ++afl->useless_at_start;
1108
1109 if (!afl->in_bitmap && !afl->shuffle_queue) {
1110
1111 WARNF("No new instrumentation output, test case may be useless.");
1112
1113 }
1114
1115 break;
1116
1117 }
1118
1119 if (q->var_behavior) {
1120
1121 WARNF("Instrumentation output varies across runs.");
1122
1123 }
1124
1125 }
1126
1127 if (cal_failures) {
1128
1129 if (cal_failures == afl->queued_items) {
1130
1131 FATAL("All test cases time out or crash, giving up!");
1132
1133 }
1134
1135 WARNF("Skipped %u test cases (%0.02f%%) due to timeouts or crashes.",
1136 cal_failures, ((double)cal_failures) * 100 / afl->queued_items);
1137
1138 if (cal_failures * 5 > afl->queued_items) {
1139
1140 WARNF(cLRD "High percentage of rejected test cases, check settings!");
1141
1142 }
1143
1144 }
1145
1146 /* Now we remove all entries from the queue that have a duplicate trace map */
1147
1148 u32 duplicates = 0, i;
1149
1150 for (idx = 0; idx < afl->queued_items; idx++) {
1151
1152 q = afl->queue_buf[idx];
1153 if (!q || q->disabled || q->cal_failed || !q->exec_cksum) { continue; }
1154
1155 u32 done = 0;
1156 for (i = idx + 1;
1157 i < afl->queued_items && !done && likely(afl->queue_buf[i]); i++) {
1158
1159 struct queue_entry *p = afl->queue_buf[i];
1160 if (p->disabled || p->cal_failed || !p->exec_cksum) { continue; }
1161
1162 if (p->exec_cksum == q->exec_cksum) {
1163
1164 duplicates = 1;
1165
1166 // we keep the shorter file
1167 if (p->len >= q->len) {
1168
1169 if (!p->was_fuzzed) {
1170
1171 p->was_fuzzed = 1;
1172 --afl->pending_not_fuzzed;
1173 --afl->active_items;
1174
1175 }
1176
1177 p->disabled = 1;
1178 p->perf_score = 0;
1179
1180 } else {
1181
1182 if (!q->was_fuzzed) {
1183
1184 q->was_fuzzed = 1;
1185 --afl->pending_not_fuzzed;
1186 --afl->active_items;
1187
1188 }
1189
1190 q->disabled = 1;
1191 q->perf_score = 0;
1192
1193 done = 1;
1194
1195 }
1196
1197 }
1198
1199 }
1200
1201 }
1202
1203 if (duplicates) {
1204
1205 afl->max_depth = 0;
1206
1207 for (idx = 0; idx < afl->queued_items; idx++) {
1208
1209 if (afl->queue_buf[idx] && !afl->queue_buf[idx]->disabled &&
1210 afl->queue_buf[idx]->depth > afl->max_depth)
1211 afl->max_depth = afl->queue_buf[idx]->depth;
1212
1213 }
1214
1215 afl->queue_top = afl->queue;
1216
1217 }
1218
1219 OKF("All test cases processed.");
1220
1221 }
1222
1223 /* Helper function: link() if possible, copy otherwise. */
1224
1225 static void link_or_copy(u8 *old_path, u8 *new_path) {
1226
1227 s32 i = link(old_path, new_path);
1228 s32 sfd, dfd;
1229 u8 *tmp;
1230
1231 if (!i) { return; }
1232
1233 sfd = open(old_path, O_RDONLY);
1234 if (sfd < 0) { PFATAL("Unable to open '%s'", old_path); }
1235
1236 dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
1237 if (dfd < 0) { PFATAL("Unable to create '%s'", new_path); }
1238
1239 tmp = ck_alloc(64 * 1024);
1240
1241 while ((i = read(sfd, tmp, 64 * 1024)) > 0) {
1242
1243 ck_write(dfd, tmp, i, new_path);
1244
1245 }
1246
1247 if (i < 0) { PFATAL("read() failed"); }
1248
1249 ck_free(tmp);
1250 close(sfd);
1251 close(dfd);
1252
1253 }
1254
1255 /* Create hard links for input test cases in the output directory, choosing
1256 good names and pivoting accordingly. */
1257
1258 void pivot_inputs(afl_state_t *afl) {
1259
1260 struct queue_entry *q;
1261 u32 id = 0, i;
1262
1263 ACTF("Creating hard links for all input files...");
1264
1265 for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) {
1266
1267 q = afl->queue_buf[i];
1268
1269 if (unlikely(q->disabled)) { continue; }
1270
1271 u8 *nfn, *rsl = strrchr(q->fname, '/');
1272 u32 orig_id;
1273
1274 if (!rsl) {
1275
1276 rsl = q->fname;
1277
1278 } else {
1279
1280 ++rsl;
1281
1282 }
1283
1284 /* If the original file name conforms to the syntax and the recorded
1285 ID matches the one we'd assign, just use the original file name.
1286 This is valuable for resuming fuzzing runs. */
1287
1288 if (!strncmp(rsl, CASE_PREFIX, 3) &&
1289 sscanf(rsl + 3, "%06u", &orig_id) == 1 && orig_id == id) {
1290
1291 u8 *src_str;
1292 u32 src_id;
1293
1294 afl->resuming_fuzz = 1;
1295 nfn = alloc_printf("%s/queue/%s", afl->out_dir, rsl);
1296
1297 /* Since we're at it, let's also get the parent and figure out the
1298 appropriate depth for this entry. */
1299
1300 src_str = strchr(rsl + 3, ':');
1301
1302 if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) {
1303
1304 if (src_id < afl->queued_items) {
1305
1306 struct queue_entry *s = afl->queue_buf[src_id];
1307
1308 if (s) { q->depth = s->depth + 1; }
1309
1310 }
1311
1312 if (afl->max_depth < q->depth) { afl->max_depth = q->depth; }
1313
1314 }
1315
1316 } else {
1317
1318 /* No dice - invent a new name, capturing the original one as a
1319 substring. */
1320
1321 #ifndef SIMPLE_FILES
1322
1323 u8 *use_name = strstr(rsl, ",orig:");
1324
1325 if (use_name) {
1326
1327 use_name += 6;
1328
1329 } else {
1330
1331 use_name = rsl;
1332
1333 }
1334
1335 nfn = alloc_printf("%s/queue/id:%06u,time:0,execs:%llu,orig:%s",
1336 afl->out_dir, id, afl->fsrv.total_execs, use_name);
1337
1338 #else
1339
1340 nfn = alloc_printf("%s/queue/id_%06u", afl->out_dir, id);
1341
1342 #endif /* ^!SIMPLE_FILES */
1343
1344 }
1345
1346 /* Pivot to the new queue entry. */
1347
1348 link_or_copy(q->fname, nfn);
1349 ck_free(q->fname);
1350 q->fname = nfn;
1351
1352 /* Make sure that the passed_det value carries over, too. */
1353
1354 if (q->passed_det) { mark_as_det_done(afl, q); }
1355
1356 if (afl->custom_mutators_count) {
1357
1358 run_afl_custom_queue_new_entry(afl, q, q->fname, NULL);
1359
1360 }
1361
1362 ++id;
1363
1364 }
1365
1366 if (afl->in_place_resume) { nuke_resume_dir(afl); }
1367
1368 }
1369
1370 /* When resuming, try to find the queue position to start from. This makes sense
1371 only when resuming, and when we can find the original fuzzer_stats. */
1372
1373 u32 find_start_position(afl_state_t *afl) {
1374
1375 u8 tmp[4096] = {0}; /* Ought to be enough for anybody. */
1376
1377 u8 *fn, *off;
1378 s32 fd, i;
1379 u32 ret;
1380
1381 if (!afl->resuming_fuzz) { return 0; }
1382
1383 if (afl->in_place_resume) {
1384
1385 fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
1386
1387 } else {
1388
1389 fn = alloc_printf("%s/../fuzzer_stats", afl->in_dir);
1390
1391 }
1392
1393 fd = open(fn, O_RDONLY);
1394 ck_free(fn);
1395
1396 if (fd < 0) { return 0; }
1397
1398 i = read(fd, tmp, sizeof(tmp) - 1);
1399 (void)i; /* Ignore errors */
1400 close(fd);
1401
1402 off = strstr(tmp, "cur_item : ");
1403 if (!off) { return 0; }
1404
1405 ret = atoi(off + 20);
1406 if (ret >= afl->queued_items) { ret = 0; }
1407 return ret;
1408
1409 }
1410
1411 /* The same, but for timeouts. The idea is that when resuming sessions without
1412 -t given, we don't want to keep auto-scaling the timeout over and over
1413 again to prevent it from growing due to random flukes. */
1414
1415 void find_timeout(afl_state_t *afl) {
1416
1417 u8 tmp[4096] = {0}; /* Ought to be enough for anybody. */
1418
1419 u8 *fn, *off;
1420 s32 fd, i;
1421 u32 ret;
1422
1423 if (!afl->resuming_fuzz) { return; }
1424
1425 if (afl->in_place_resume) {
1426
1427 fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
1428
1429 } else {
1430
1431 fn = alloc_printf("%s/../fuzzer_stats", afl->in_dir);
1432
1433 }
1434
1435 fd = open(fn, O_RDONLY);
1436 ck_free(fn);
1437
1438 if (fd < 0) { return; }
1439
1440 i = read(fd, tmp, sizeof(tmp) - 1);
1441 (void)i; /* Ignore errors */
1442 close(fd);
1443
1444 off = strstr(tmp, "exec_timeout : ");
1445 if (!off) { return; }
1446
1447 ret = atoi(off + 20);
1448 if (ret <= 4) { return; }
1449
1450 afl->fsrv.exec_tmout = ret;
1451 afl->timeout_given = 3;
1452
1453 }
1454
1455 /* A helper function for handle_existing_out_dir(), deleting all prefixed
1456 files in a directory. */
1457
1458 static u8 delete_files(u8 *path, u8 *prefix) {
1459
1460 DIR * d;
1461 struct dirent *d_ent;
1462
1463 d = opendir(path);
1464
1465 if (!d) { return 0; }
1466
1467 while ((d_ent = readdir(d))) {
1468
1469 if (d_ent->d_name[0] != '.' &&
1470 (!prefix || !strncmp(d_ent->d_name, prefix, strlen(prefix)))) {
1471
1472 u8 *fname = alloc_printf("%s/%s", path, d_ent->d_name);
1473 if (unlink(fname)) { PFATAL("Unable to delete '%s'", fname); }
1474 ck_free(fname);
1475
1476 }
1477
1478 }
1479
1480 closedir(d);
1481
1482 return !!rmdir(path);
1483
1484 }
1485
1486 /* Get the number of runnable processes, with some simple smoothing. */
1487
1488 double get_runnable_processes(void) {
1489
1490 double res = 0;
1491
1492 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
1493 defined(__NetBSD__) || defined(__DragonFly__)
1494
1495 /* I don't see any portable sysctl or so that would quickly give us the
1496 number of runnable processes; the 1-minute load average can be a
1497 semi-decent approximation, though. */
1498
1499 if (getloadavg(&res, 1) != 1) return 0;
1500
1501 #else
1502
1503 /* On Linux, /proc/stat is probably the best way; load averages are
1504 computed in funny ways and sometimes don't reflect extremely short-lived
1505 processes well. */
1506
1507 FILE *f = fopen("/proc/stat", "r");
1508 u8 tmp[1024];
1509 u32 val = 0;
1510
1511 if (!f) { return 0; }
1512
1513 while (fgets(tmp, sizeof(tmp), f)) {
1514
1515 if (!strncmp(tmp, "procs_running ", 14) ||
1516 !strncmp(tmp, "procs_blocked ", 14)) {
1517
1518 val += atoi(tmp + 14);
1519
1520 }
1521
1522 }
1523
1524 fclose(f);
1525
1526 if (!res) {
1527
1528 res = val;
1529
1530 } else {
1531
1532 res = res * (1.0 - 1.0 / AVG_SMOOTHING) +
1533 ((double)val) * (1.0 / AVG_SMOOTHING);
1534
1535 }
1536
1537 #endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__) */
1538
1539 return res;
1540
1541 }
1542
1543 /* Delete the temporary directory used for in-place session resume. */
1544
1545 void nuke_resume_dir(afl_state_t *afl) {
1546
1547 u8 *fn;
1548
1549 fn = alloc_printf("%s/_resume/.state/deterministic_done", afl->out_dir);
1550 if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
1551 ck_free(fn);
1552
1553 fn = alloc_printf("%s/_resume/.state/auto_extras", afl->out_dir);
1554 if (delete_files(fn, "auto_")) { goto dir_cleanup_failed; }
1555 ck_free(fn);
1556
1557 fn = alloc_printf("%s/_resume/.state/redundant_edges", afl->out_dir);
1558 if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
1559 ck_free(fn);
1560
1561 fn = alloc_printf("%s/_resume/.state/variable_behavior", afl->out_dir);
1562 if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
1563 ck_free(fn);
1564
1565 fn = alloc_printf("%s/_resume/.state", afl->out_dir);
1566 if (rmdir(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
1567 ck_free(fn);
1568
1569 fn = alloc_printf("%s/_resume", afl->out_dir);
1570 if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
1571 ck_free(fn);
1572
1573 return;
1574
1575 dir_cleanup_failed:
1576
1577 FATAL("_resume directory cleanup failed");
1578
1579 }
1580
1581 /* Delete fuzzer output directory if we recognize it as ours, if the fuzzer
1582 is not currently running, and if the last run time isn't too great.
1583 Resume fuzzing if `-` is set as in_dir or if AFL_AUTORESUME is set */
1584
1585 static void handle_existing_out_dir(afl_state_t *afl) {
1586
1587 FILE *f;
1588 u8 * fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
1589
1590 /* See if the output directory is locked. If yes, bail out. If not,
1591 create a lock that will persist for the lifetime of the process
1592 (this requires leaving the descriptor open).*/
1593
1594 afl->fsrv.out_dir_fd = open(afl->out_dir, O_RDONLY);
1595 if (afl->fsrv.out_dir_fd < 0) { PFATAL("Unable to open '%s'", afl->out_dir); }
1596
1597 #ifndef __sun
1598
1599 if (flock(afl->fsrv.out_dir_fd, LOCK_EX | LOCK_NB) && errno == EWOULDBLOCK) {
1600
1601 SAYF("\n" cLRD "[-] " cRST
1602 "Looks like the job output directory is being actively used by "
1603 "another\n"
1604 " instance of afl-fuzz. You will need to choose a different %s\n"
1605 " or stop the other process first.\n",
1606 afl->sync_id ? "fuzzer ID" : "output location");
1607
1608 FATAL("Directory '%s' is in use", afl->out_dir);
1609
1610 }
1611
1612 #endif /* !__sun */
1613
1614 f = fopen(fn, "r");
1615
1616 if (f) {
1617
1618 u64 start_time2, last_update;
1619
1620 if (fscanf(f,
1621 "start_time : %llu\n"
1622 "last_update : %llu\n",
1623 &start_time2, &last_update) != 2) {
1624
1625 FATAL("Malformed data in '%s'", fn);
1626
1627 }
1628
1629 fclose(f);
1630
1631 /* Autoresume treats a normal run as in_place_resume if a valid out dir
1632 * already exists */
1633
1634 if (!afl->in_place_resume && afl->autoresume) {
1635
1636 OKF("Detected prior run with AFL_AUTORESUME set. Resuming.");
1637 afl->in_place_resume = 1;
1638
1639 }
1640
1641 /* Let's see how much work is at stake. */
1642
1643 if (!afl->in_place_resume && last_update > start_time2 &&
1644 last_update - start_time2 > OUTPUT_GRACE * 60) {
1645
1646 SAYF("\n" cLRD "[-] " cRST
1647 "The job output directory already exists and contains the results "
1648 "of more\n"
1649 " than %d minutes worth of fuzzing. To avoid data loss, afl-fuzz "
1650 "will *NOT*\n"
1651 " automatically delete this data for you.\n\n"
1652
1653 " If you wish to start a new session, remove or rename the "
1654 "directory manually,\n"
1655 " or specify a different output location for this job. To resume "
1656 "the old\n"
1657 " session, pass '-' as input directory in the command line ('-i "
1658 "-')\n"
1659 " or set the 'AFL_AUTORESUME=1' env variable and try again.\n",
1660 OUTPUT_GRACE);
1661
1662 FATAL("At-risk data found in '%s'", afl->out_dir);
1663
1664 }
1665
1666 }
1667
1668 ck_free(fn);
1669
1670 /* The idea for in-place resume is pretty simple: we temporarily move the old
1671 queue/ to a new location that gets deleted once import to the new queue/
1672 is finished. If _resume/ already exists, the current queue/ may be
1673 incomplete due to an earlier abort, so we want to use the old _resume/
1674 dir instead, and we let rename() fail silently. */
1675
1676 if (afl->in_place_resume) {
1677
1678 u8 *orig_q = alloc_printf("%s/queue", afl->out_dir);
1679
1680 afl->in_dir = alloc_printf("%s/_resume", afl->out_dir);
1681
1682 rename(orig_q, afl->in_dir); /* Ignore errors */
1683
1684 OKF("Output directory exists, will attempt session resume.");
1685
1686 ck_free(orig_q);
1687
1688 } else {
1689
1690 OKF("Output directory exists but deemed OK to reuse.");
1691
1692 }
1693
1694 ACTF("Deleting old session data...");
1695
1696 /* Okay, let's get the ball rolling! First, we need to get rid of the entries
1697 in <afl->out_dir>/.synced/.../id:*, if any are present. */
1698
1699 if (!afl->in_place_resume) {
1700
1701 fn = alloc_printf("%s/.synced", afl->out_dir);
1702 if (delete_files(fn, NULL)) { goto dir_cleanup_failed; }
1703 ck_free(fn);
1704
1705 }
1706
1707 /* Next, we need to clean up <afl->out_dir>/queue/.state/ subdirectories: */
1708
1709 fn = alloc_printf("%s/queue/.state/deterministic_done", afl->out_dir);
1710 if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
1711 ck_free(fn);
1712
1713 fn = alloc_printf("%s/queue/.state/auto_extras", afl->out_dir);
1714 if (delete_files(fn, "auto_")) { goto dir_cleanup_failed; }
1715 ck_free(fn);
1716
1717 fn = alloc_printf("%s/queue/.state/redundant_edges", afl->out_dir);
1718 if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
1719 ck_free(fn);
1720
1721 fn = alloc_printf("%s/queue/.state/variable_behavior", afl->out_dir);
1722 if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
1723 ck_free(fn);
1724
1725 /* Then, get rid of the .state subdirectory itself (should be empty by now)
1726 and everything matching <afl->out_dir>/queue/id:*. */
1727
1728 fn = alloc_printf("%s/queue/.state", afl->out_dir);
1729 if (rmdir(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
1730 ck_free(fn);
1731
1732 fn = alloc_printf("%s/queue", afl->out_dir);
1733 if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
1734 ck_free(fn);
1735
1736 /* All right, let's do <afl->out_dir>/crashes/id:* and
1737 * <afl->out_dir>/hangs/id:*. */
1738
1739 if (!afl->in_place_resume) {
1740
1741 fn = alloc_printf("%s/crashes/README.txt", afl->out_dir);
1742 unlink(fn); /* Ignore errors */
1743 ck_free(fn);
1744
1745 }
1746
1747 fn = alloc_printf("%s/crashes", afl->out_dir);
1748
1749 /* Make backup of the crashes directory if it's not empty and if we're
1750 doing in-place resume. */
1751
1752 if (afl->in_place_resume && rmdir(fn)) {
1753
1754 time_t cur_t = time(0);
1755 struct tm t;
1756 localtime_r(&cur_t, &t);
1757
1758 #ifndef SIMPLE_FILES
1759
1760 u8 *nfn =
1761 alloc_printf("%s.%04d-%02d-%02d-%02d:%02d:%02d", fn, t.tm_year + 1900,
1762 t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
1763
1764 #else
1765
1766 u8 *nfn =
1767 alloc_printf("%s_%04d%02d%02d%02d%02d%02d", fn, t.tm_year + 1900,
1768 t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
1769
1770 #endif /* ^!SIMPLE_FILES */
1771
1772 rename(fn, nfn); /* Ignore errors. */
1773 ck_free(nfn);
1774
1775 }
1776
1777 if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
1778 ck_free(fn);
1779
1780 fn = alloc_printf("%s/hangs", afl->out_dir);
1781
1782 /* Backup hangs, too. */
1783
1784 if (afl->in_place_resume && rmdir(fn)) {
1785
1786 time_t cur_t = time(0);
1787 struct tm t;
1788 localtime_r(&cur_t, &t);
1789
1790 #ifndef SIMPLE_FILES
1791
1792 u8 *nfn =
1793 alloc_printf("%s.%04d-%02d-%02d-%02d:%02d:%02d", fn, t.tm_year + 1900,
1794 t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
1795
1796 #else
1797
1798 u8 *nfn =
1799 alloc_printf("%s_%04d%02d%02d%02d%02d%02d", fn, t.tm_year + 1900,
1800 t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
1801
1802 #endif /* ^!SIMPLE_FILES */
1803
1804 rename(fn, nfn); /* Ignore errors. */
1805 ck_free(nfn);
1806
1807 }
1808
1809 if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
1810 ck_free(fn);
1811
1812 /* And now, for some finishing touches. */
1813
1814 if (afl->file_extension) {
1815
1816 fn = alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension);
1817
1818 } else {
1819
1820 fn = alloc_printf("%s/.cur_input", afl->tmp_dir);
1821
1822 }
1823
1824 if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
1825 ck_free(fn);
1826
1827 fn = alloc_printf("%s/fuzz_bitmap", afl->out_dir);
1828 if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
1829 ck_free(fn);
1830
1831 if (!afl->in_place_resume) {
1832
1833 fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
1834 if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
1835 ck_free(fn);
1836
1837 }
1838
1839 if (!afl->in_place_resume) {
1840
1841 fn = alloc_printf("%s/plot_data", afl->out_dir);
1842 if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
1843 ck_free(fn);
1844
1845 }
1846
1847 fn = alloc_printf("%s/cmdline", afl->out_dir);
1848 if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
1849 ck_free(fn);
1850
1851 OKF("Output dir cleanup successful.");
1852
1853 /* Wow... is that all? If yes, celebrate! */
1854
1855 return;
1856
1857 dir_cleanup_failed:
1858
1859 SAYF("\n" cLRD "[-] " cRST
1860 "Whoops, the fuzzer tried to reuse your output directory, but bumped "
1861 "into\n"
1862 " some files that shouldn't be there or that couldn't be removed - "
1863 "so it\n"
1864 " decided to abort! This happened while processing this path:\n\n"
1865
1866 " %s\n\n"
1867 " Please examine and manually delete the files, or specify a "
1868 "different\n"
1869 " output location for the tool.\n",
1870 fn);
1871
1872 FATAL("Output directory cleanup failed");
1873
1874 }
1875
1876 /* If this is a -S secondary node, ensure a -M main node is running,
1877 if a main node is running when another main is started, then warn */
1878
1879 int check_main_node_exists(afl_state_t *afl) {
1880
1881 DIR * sd;
1882 struct dirent *sd_ent;
1883 u8 * fn;
1884
1885 sd = opendir(afl->sync_dir);
1886 if (!sd) { return 0; }
1887
1888 while ((sd_ent = readdir(sd))) {
1889
1890 /* Skip dot files and our own output directory. */
1891
1892 if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
1893
1894 continue;
1895
1896 }
1897
1898 fn = alloc_printf("%s/%s/is_main_node", afl->sync_dir, sd_ent->d_name);
1899 int res = access(fn, F_OK);
1900 free(fn);
1901 if (res == 0) return 1;
1902
1903 }
1904
1905 return 0;
1906
1907 }
1908
1909 /* Prepare output directories and fds. */
1910
1911 void setup_dirs_fds(afl_state_t *afl) {
1912
1913 u8 *tmp;
1914
1915 ACTF("Setting up output directories...");
1916
1917 if (afl->sync_id && mkdir(afl->sync_dir, 0700) && errno != EEXIST) {
1918
1919 PFATAL("Unable to create '%s'", afl->sync_dir);
1920
1921 }
1922
1923 if (mkdir(afl->out_dir, 0700)) {
1924
1925 if (errno != EEXIST) { PFATAL("Unable to create '%s'", afl->out_dir); }
1926
1927 handle_existing_out_dir(afl);
1928
1929 } else {
1930
1931 if (afl->in_place_resume) {
1932
1933 FATAL("Resume attempted but old output directory not found");
1934
1935 }
1936
1937 afl->fsrv.out_dir_fd = open(afl->out_dir, O_RDONLY);
1938
1939 #ifndef __sun
1940
1941 if (afl->fsrv.out_dir_fd < 0 ||
1942 flock(afl->fsrv.out_dir_fd, LOCK_EX | LOCK_NB)) {
1943
1944 PFATAL("Unable to flock() output directory.");
1945
1946 }
1947
1948 #endif /* !__sun */
1949
1950 }
1951
1952 if (afl->is_main_node) {
1953
1954 u8 *x = alloc_printf("%s/is_main_node", afl->out_dir);
1955 int fd = open(x, O_CREAT | O_RDWR, 0644);
1956 if (fd < 0) FATAL("cannot create %s", x);
1957 free(x);
1958 close(fd);
1959
1960 }
1961
1962 /* Queue directory for any starting & discovered paths. */
1963
1964 tmp = alloc_printf("%s/queue", afl->out_dir);
1965 if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
1966 ck_free(tmp);
1967
1968 /* Top-level directory for queue metadata used for session
1969 resume and related tasks. */
1970
1971 tmp = alloc_printf("%s/queue/.state/", afl->out_dir);
1972 if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
1973 ck_free(tmp);
1974
1975 /* Directory for flagging queue entries that went through
1976 deterministic fuzzing in the past. */
1977
1978 tmp = alloc_printf("%s/queue/.state/deterministic_done/", afl->out_dir);
1979 if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
1980 ck_free(tmp);
1981
1982 /* Directory with the auto-selected dictionary entries. */
1983
1984 tmp = alloc_printf("%s/queue/.state/auto_extras/", afl->out_dir);
1985 if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
1986 ck_free(tmp);
1987
1988 /* The set of paths currently deemed redundant. */
1989
1990 tmp = alloc_printf("%s/queue/.state/redundant_edges/", afl->out_dir);
1991 if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
1992 ck_free(tmp);
1993
1994 /* The set of paths showing variable behavior. */
1995
1996 tmp = alloc_printf("%s/queue/.state/variable_behavior/", afl->out_dir);
1997 if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
1998 ck_free(tmp);
1999
2000 /* Sync directory for keeping track of cooperating fuzzers. */
2001
2002 if (afl->sync_id) {
2003
2004 tmp = alloc_printf("%s/.synced/", afl->out_dir);
2005
2006 if (mkdir(tmp, 0700) && (!afl->in_place_resume || errno != EEXIST)) {
2007
2008 PFATAL("Unable to create '%s'", tmp);
2009
2010 }
2011
2012 ck_free(tmp);
2013
2014 }
2015
2016 /* All recorded crashes. */
2017
2018 tmp = alloc_printf("%s/crashes", afl->out_dir);
2019 if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
2020 ck_free(tmp);
2021
2022 /* All recorded hangs. */
2023
2024 tmp = alloc_printf("%s/hangs", afl->out_dir);
2025 if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); }
2026 ck_free(tmp);
2027
2028 /* Generally useful file descriptors. */
2029
2030 afl->fsrv.dev_null_fd = open("/dev/null", O_RDWR);
2031 if (afl->fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
2032
2033 afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
2034 if (afl->fsrv.dev_urandom_fd < 0) { PFATAL("Unable to open /dev/urandom"); }
2035
2036 /* Gnuplot output file. */
2037
2038 tmp = alloc_printf("%s/plot_data", afl->out_dir);
2039
2040 if (!afl->in_place_resume) {
2041
2042 int fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
2043 if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
2044 ck_free(tmp);
2045
2046 afl->fsrv.plot_file = fdopen(fd, "w");
2047 if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); }
2048
2049 fprintf(
2050 afl->fsrv.plot_file,
2051 "# relative_time, cycles_done, cur_item, corpus_count, "
2052 "pending_total, pending_favs, map_size, saved_crashes, "
2053 "saved_hangs, max_depth, execs_per_sec, total_execs, edges_found\n");
2054
2055 } else {
2056
2057 int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION);
2058 if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
2059 ck_free(tmp);
2060
2061 afl->fsrv.plot_file = fdopen(fd, "w");
2062 if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); }
2063
2064 fseek(afl->fsrv.plot_file, 0, SEEK_END);
2065
2066 }
2067
2068 fflush(afl->fsrv.plot_file);
2069
2070 /* ignore errors */
2071
2072 }
2073
2074 void setup_cmdline_file(afl_state_t *afl, char **argv) {
2075
2076 u8 *tmp;
2077 s32 fd;
2078 u32 i = 0;
2079
2080 FILE *cmdline_file = NULL;
2081
2082 /* Store the command line to reproduce our findings */
2083 tmp = alloc_printf("%s/cmdline", afl->out_dir);
2084 fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
2085 if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
2086 ck_free(tmp);
2087
2088 cmdline_file = fdopen(fd, "w");
2089 if (!cmdline_file) { PFATAL("fdopen() failed"); }
2090
2091 while (argv[i]) {
2092
2093 fprintf(cmdline_file, "%s\n", argv[i]);
2094 ++i;
2095
2096 }
2097
2098 fclose(cmdline_file);
2099
2100 }
2101
2102 /* Setup the output file for fuzzed data, if not using -f. */
2103
2104 void setup_stdio_file(afl_state_t *afl) {
2105
2106 if (afl->file_extension) {
2107
2108 afl->fsrv.out_file =
2109 alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension);
2110
2111 } else {
2112
2113 afl->fsrv.out_file = alloc_printf("%s/.cur_input", afl->tmp_dir);
2114
2115 }
2116
2117 unlink(afl->fsrv.out_file); /* Ignore errors */
2118
2119 afl->fsrv.out_fd =
2120 open(afl->fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
2121
2122 if (afl->fsrv.out_fd < 0) {
2123
2124 PFATAL("Unable to create '%s'", afl->fsrv.out_file);
2125
2126 }
2127
2128 }
2129
2130 /* Make sure that core dumps don't go to a program. */
2131
2132 void check_crash_handling(void) {
2133
2134 #ifdef __APPLE__
2135
2136 /* Yuck! There appears to be no simple C API to query for the state of
2137 loaded daemons on MacOS X, and I'm a bit hesitant to do something
2138 more sophisticated, such as disabling crash reporting via Mach ports,
2139 until I get a box to test the code. So, for now, we check for crash
2140 reporting the awful way. */
2141
2142 #if !TARGET_OS_IPHONE
2143 if (system("launchctl list 2>/dev/null | grep -q '\\.ReportCrash$'")) return;
2144
2145 SAYF(
2146 "\n" cLRD "[-] " cRST
2147 "Whoops, your system is configured to forward crash notifications to an\n"
2148 " external crash reporting utility. This will cause issues due to "
2149 "the\n"
2150 " extended delay between the fuzzed binary malfunctioning and this "
2151 "fact\n"
2152 " being relayed to the fuzzer via the standard waitpid() API.\n\n"
2153 " To avoid having crashes misinterpreted as timeouts, please run the\n"
2154 " following commands:\n\n"
2155
2156 " SL=/System/Library; PL=com.apple.ReportCrash\n"
2157 " launchctl unload -w ${SL}/LaunchAgents/${PL}.plist\n"
2158 " sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist\n");
2159
2160 #endif
2161 if (!get_afl_env("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES"))
2162 FATAL("Crash reporter detected");
2163
2164 #else
2165
2166 /* This is Linux specific, but I don't think there's anything equivalent on
2167 *BSD, so we can just let it slide for now. */
2168
2169 s32 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY);
2170 u8 fchar;
2171
2172 if (fd < 0) { return; }
2173
2174 ACTF("Checking core_pattern...");
2175
2176 if (read(fd, &fchar, 1) == 1 && fchar == '|') {
2177
2178 SAYF(
2179 "\n" cLRD "[-] " cRST
2180 "Hmm, your system is configured to send core dump notifications to an\n"
2181 " external utility. This will cause issues: there will be an "
2182 "extended delay\n"
2183 " between stumbling upon a crash and having this information "
2184 "relayed to the\n"
2185 " fuzzer via the standard waitpid() API.\n"
2186 " If you're just testing, set "
2187 "'AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1'.\n\n"
2188
2189 " To avoid having crashes misinterpreted as timeouts, please log in "
2190 "as root\n"
2191 " and temporarily modify /proc/sys/kernel/core_pattern, like so:\n\n"
2192
2193 " echo core >/proc/sys/kernel/core_pattern\n");
2194
2195 if (!getenv("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES")) {
2196
2197 FATAL("Pipe at the beginning of 'core_pattern'");
2198
2199 }
2200
2201 }
2202
2203 close(fd);
2204
2205 #endif /* ^__APPLE__ */
2206
2207 }
2208
2209 /* Check CPU governor. */
2210
2211 void check_cpu_governor(afl_state_t *afl) {
2212
2213 #ifdef __linux__
2214 FILE *f;
2215 u8 tmp[128];
2216 u64 min = 0, max = 0;
2217
2218 if (afl->afl_env.afl_skip_cpufreq) { return; }
2219
2220 if (afl->cpu_aff > 0) {
2221
2222 snprintf(tmp, sizeof(tmp), "%s%d%s", "/sys/devices/system/cpu/cpu",
2223 afl->cpu_aff, "/cpufreq/scaling_governor");
2224
2225 } else {
2226
2227 snprintf(tmp, sizeof(tmp), "%s",
2228 "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
2229
2230 }
2231
2232 f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "r");
2233 if (!f) {
2234
2235 if (afl->cpu_aff > 0) {
2236
2237 snprintf(tmp, sizeof(tmp), "%s%d%s",
2238 "/sys/devices/system/cpu/cpufreq/policy", afl->cpu_aff,
2239 "/scaling_governor");
2240
2241 } else {
2242
2243 snprintf(tmp, sizeof(tmp), "%s",
2244 "/sys/devices/system/cpu/cpufreq/policy0/scaling_governor");
2245
2246 }
2247
2248 f = fopen(tmp, "r");
2249
2250 }
2251
2252 if (!f) {
2253
2254 WARNF("Could not check CPU scaling governor");
2255 return;
2256
2257 }
2258
2259 ACTF("Checking CPU scaling governor...");
2260
2261 if (!fgets(tmp, 128, f)) { PFATAL("fgets() failed"); }
2262
2263 fclose(f);
2264
2265 if (!strncmp(tmp, "perf", 4)) { return; }
2266
2267 f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", "r");
2268
2269 if (f) {
2270
2271 if (fscanf(f, "%llu", &min) != 1) { min = 0; }
2272 fclose(f);
2273
2274 }
2275
2276 f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", "r");
2277
2278 if (f) {
2279
2280 if (fscanf(f, "%llu", &max) != 1) { max = 0; }
2281 fclose(f);
2282
2283 }
2284
2285 if (min == max) { return; }
2286
2287 SAYF("\n" cLRD "[-] " cRST
2288 "Whoops, your system uses on-demand CPU frequency scaling, adjusted\n"
2289 " between %llu and %llu MHz. Unfortunately, the scaling algorithm in "
2290 "the\n"
2291 " kernel is imperfect and can miss the short-lived processes spawned "
2292 "by\n"
2293 " afl-fuzz. To keep things moving, run these commands as root:\n\n"
2294
2295 " cd /sys/devices/system/cpu\n"
2296 " echo performance | tee cpu*/cpufreq/scaling_governor\n\n"
2297
2298 " You can later go back to the original state by replacing "
2299 "'performance'\n"
2300 " with 'ondemand' or 'powersave'. If you don't want to change the "
2301 "settings,\n"
2302 " set AFL_SKIP_CPUFREQ to make afl-fuzz skip this check - but expect "
2303 "some\n"
2304 " performance drop.\n",
2305 min / 1024, max / 1024);
2306 FATAL("Suboptimal CPU scaling governor");
2307
2308 #elif defined __APPLE__
2309 u64 min = 0, max = 0;
2310 size_t mlen = sizeof(min);
2311 if (afl->afl_env.afl_skip_cpufreq) return;
2312
2313 ACTF("Checking CPU scaling governor...");
2314
2315 if (sysctlbyname("hw.cpufrequency_min", &min, &mlen, NULL, 0) == -1) {
2316
2317 WARNF("Could not check CPU min frequency");
2318 return;
2319
2320 }
2321
2322 if (sysctlbyname("hw.cpufrequency_max", &max, &mlen, NULL, 0) == -1) {
2323
2324 WARNF("Could not check CPU max frequency");
2325 return;
2326
2327 }
2328
2329 if (min == max) return;
2330
2331 SAYF("\n" cLRD "[-] " cRST
2332 "Whoops, your system uses on-demand CPU frequency scaling, adjusted\n"
2333 " between %llu and %llu MHz.\n"
2334 " If you don't want to check those settings, set "
2335 "AFL_SKIP_CPUFREQ\n"
2336 " to make afl-fuzz skip this check - but expect some performance "
2337 "drop.\n",
2338 min / 1024, max / 1024);
2339 FATAL("Suboptimal CPU scaling governor");
2340 #else
2341 (void)afl;
2342 #endif
2343
2344 }
2345
2346 /* Count the number of logical CPU cores. */
2347
2348 void get_core_count(afl_state_t *afl) {
2349
2350 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
2351 defined(__DragonFly__)
2352
2353 size_t s = sizeof(afl->cpu_core_count);
2354
2355 /* On *BSD systems, we can just use a sysctl to get the number of CPUs. */
2356
2357 #ifdef __APPLE__
2358
2359 if (sysctlbyname("hw.logicalcpu", &afl->cpu_core_count, &s, NULL, 0) < 0)
2360 return;
2361
2362 #else
2363
2364 int s_name[2] = {CTL_HW, HW_NCPU};
2365
2366 if (sysctl(s_name, 2, &afl->cpu_core_count, &s, NULL, 0) < 0) return;
2367
2368 #endif /* ^__APPLE__ */
2369
2370 #else
2371
2372 #ifdef HAVE_AFFINITY
2373
2374 afl->cpu_core_count = sysconf(_SC_NPROCESSORS_ONLN);
2375
2376 #else
2377
2378 FILE *f = fopen("/proc/stat", "r");
2379 u8 tmp[1024];
2380
2381 if (!f) return;
2382
2383 while (fgets(tmp, sizeof(tmp), f))
2384 if (!strncmp(tmp, "cpu", 3) && isdigit(tmp[3])) ++afl->cpu_core_count;
2385
2386 fclose(f);
2387
2388 #endif /* ^HAVE_AFFINITY */
2389
2390 #endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__) */
2391
2392 if (afl->cpu_core_count > 0) {
2393
2394 u32 cur_runnable = 0;
2395
2396 cur_runnable = (u32)get_runnable_processes();
2397
2398 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
2399 defined(__DragonFly__)
2400
2401 /* Add ourselves, since the 1-minute average doesn't include that yet. */
2402
2403 ++cur_runnable;
2404
2405 #endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */
2406
2407 OKF("You have %d CPU core%s and %u runnable tasks (utilization: %0.0f%%).",
2408 afl->cpu_core_count, afl->cpu_core_count > 1 ? "s" : "", cur_runnable,
2409 cur_runnable * 100.0 / afl->cpu_core_count);
2410
2411 if (afl->cpu_core_count > 1) {
2412
2413 if (cur_runnable > afl->cpu_core_count * 1.5) {
2414
2415 WARNF("System under apparent load, performance may be spotty.");
2416
2417 } else if ((s64)cur_runnable + 1 <= (s64)afl->cpu_core_count) {
2418
2419 OKF("Try parallel jobs - see %s/parallel_fuzzing.md.", doc_path);
2420
2421 }
2422
2423 }
2424
2425 } else {
2426
2427 afl->cpu_core_count = 0;
2428 WARNF("Unable to figure out the number of CPU cores.");
2429
2430 }
2431
2432 }
2433
2434 /* Validate and fix up afl->out_dir and sync_dir when using -S. */
2435
2436 void fix_up_sync(afl_state_t *afl) {
2437
2438 u8 *x = afl->sync_id;
2439
2440 while (*x) {
2441
2442 if (!isalnum(*x) && *x != '_' && *x != '-') {
2443
2444 FATAL("Non-alphanumeric fuzzer ID specified via -S or -M");
2445
2446 }
2447
2448 ++x;
2449
2450 }
2451
2452 if (strlen(afl->sync_id) > 32) { FATAL("Fuzzer ID too long"); }
2453
2454 x = alloc_printf("%s/%s", afl->out_dir, afl->sync_id);
2455
2456 #ifdef __linux__
2457 if (afl->fsrv.nyx_mode) { afl->fsrv.out_dir_path = afl->out_dir; }
2458 #endif
2459 afl->sync_dir = afl->out_dir;
2460 afl->out_dir = x;
2461
2462 }
2463
2464 /* Handle screen resize (SIGWINCH). */
2465
2466 static void handle_resize(int sig) {
2467
2468 (void)sig;
2469 afl_states_clear_screen();
2470
2471 }
2472
2473 /* Check ASAN options. */
2474
2475 void check_asan_opts(afl_state_t *afl) {
2476
2477 u8 *x = get_afl_env("ASAN_OPTIONS");
2478
2479 (void)(afl);
2480
2481 if (x) {
2482
2483 if (!strstr(x, "abort_on_error=1")) {
2484
2485 FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
2486
2487 }
2488
2489 #ifndef ASAN_BUILD
2490 if (!afl->debug && !strstr(x, "symbolize=0")) {
2491
2492 FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
2493
2494 }
2495
2496 #endif
2497
2498 }
2499
2500 x = get_afl_env("MSAN_OPTIONS");
2501
2502 if (x) {
2503
2504 if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) {
2505
2506 FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY(
2507 MSAN_ERROR) " - please fix!");
2508
2509 }
2510
2511 if (!afl->debug && !strstr(x, "symbolize=0")) {
2512
2513 FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
2514
2515 }
2516
2517 }
2518
2519 x = get_afl_env("LSAN_OPTIONS");
2520
2521 if (x) {
2522
2523 if (!strstr(x, "symbolize=0")) {
2524
2525 FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
2526
2527 }
2528
2529 }
2530
2531 }
2532
2533 /* Handle stop signal (Ctrl-C, etc). */
2534
2535 static void handle_stop_sig(int sig) {
2536
2537 (void)sig;
2538 afl_states_stop();
2539
2540 }
2541
2542 /* Handle skip request (SIGUSR1). */
2543
2544 static void handle_skipreq(int sig) {
2545
2546 (void)sig;
2547 afl_states_request_skip();
2548
2549 }
2550
2551 /* Setup shared map for fuzzing with input via sharedmem */
2552
2553 void setup_testcase_shmem(afl_state_t *afl) {
2554
2555 afl->shm_fuzz = ck_alloc(sizeof(sharedmem_t));
2556
2557 // we need to set the non-instrumented mode to not overwrite the SHM_ENV_VAR
2558 u8 *map = afl_shm_init(afl->shm_fuzz, MAX_FILE + sizeof(u32), 1);
2559 afl->shm_fuzz->shmemfuzz_mode = 1;
2560
2561 if (!map) { FATAL("BUG: Zero return from afl_shm_init."); }
2562
2563 #ifdef USEMMAP
2564 setenv(SHM_FUZZ_ENV_VAR, afl->shm_fuzz->g_shm_file_path, 1);
2565 #else
2566 u8 *shm_str = alloc_printf("%d", afl->shm_fuzz->shm_id);
2567 setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
2568 ck_free(shm_str);
2569 #endif
2570 afl->fsrv.support_shmem_fuzz = 1;
2571 afl->fsrv.shmem_fuzz_len = (u32 *)map;
2572 afl->fsrv.shmem_fuzz = map + sizeof(u32);
2573
2574 }
2575
2576 /* Do a PATH search and find target binary to see that it exists and
2577 isn't a shell script - a common and painful mistake. We also check for
2578 a valid ELF header and for evidence of AFL instrumentation. */
2579
2580 void check_binary(afl_state_t *afl, u8 *fname) {
2581
2582 if (unlikely(!fname)) { FATAL("BUG: Binary name is NULL"); }
2583
2584 u8 * env_path = 0;
2585 struct stat st;
2586
2587 s32 fd;
2588 u8 *f_data;
2589 u32 f_len = 0;
2590
2591 ACTF("Validating target binary...");
2592
2593 if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
2594
2595 afl->fsrv.target_path = ck_strdup(fname);
2596 #ifdef __linux__
2597 if (afl->fsrv.nyx_mode) {
2598
2599 /* check if target_path is a nyx sharedir */
2600 if (stat(afl->fsrv.target_path, &st) || S_ISDIR(st.st_mode)) {
2601
2602 char *tmp = alloc_printf("%s/config.ron", afl->fsrv.target_path);
2603 if (stat(tmp, &st) || S_ISREG(st.st_mode)) {
2604
2605 free(tmp);
2606 return;
2607
2608 }
2609
2610 }
2611
2612 FATAL("Directory '%s' not found or is not a nyx share directory",
2613 afl->fsrv.target_path);
2614
2615 }
2616
2617 #endif
2618 if (stat(afl->fsrv.target_path, &st) || !S_ISREG(st.st_mode) ||
2619 !(st.st_mode & 0111) || (f_len = st.st_size) < 4) {
2620
2621 FATAL("Program '%s' not found or not executable", fname);
2622
2623 }
2624
2625 } else {
2626
2627 while (env_path) {
2628
2629 u8 *cur_elem, *delim = strchr(env_path, ':');
2630
2631 if (delim) {
2632
2633 cur_elem = ck_alloc(delim - env_path + 1);
2634 if (unlikely(!cur_elem)) { FATAL("Unexpected large PATH"); }
2635 memcpy(cur_elem, env_path, delim - env_path);
2636 ++delim;
2637
2638 } else {
2639
2640 cur_elem = ck_strdup(env_path);
2641
2642 }
2643
2644 env_path = delim;
2645
2646 if (cur_elem[0]) {
2647
2648 afl->fsrv.target_path = alloc_printf("%s/%s", cur_elem, fname);
2649
2650 } else {
2651
2652 afl->fsrv.target_path = ck_strdup(fname);
2653
2654 }
2655
2656 ck_free(cur_elem);
2657
2658 if (!stat(afl->fsrv.target_path, &st) && S_ISREG(st.st_mode) &&
2659 (st.st_mode & 0111) && (f_len = st.st_size) >= 4) {
2660
2661 break;
2662
2663 }
2664
2665 ck_free(afl->fsrv.target_path);
2666 afl->fsrv.target_path = 0;
2667
2668 }
2669
2670 if (!afl->fsrv.target_path) {
2671
2672 FATAL("Program '%s' not found or not executable", fname);
2673
2674 }
2675
2676 }
2677
2678 if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode ||
2679 (afl->fsrv.qemu_mode && getenv("AFL_QEMU_CUSTOM_BIN")) ||
2680 (afl->fsrv.cs_mode && getenv("AFL_CS_CUSTOM_BIN")) ||
2681 afl->non_instrumented_mode) {
2682
2683 return;
2684
2685 }
2686
2687 /* Check for blatant user errors. */
2688
2689 /* disabled. not a real-worl scenario where this is a problem.
2690 if ((!strncmp(afl->fsrv.target_path, "/tmp/", 5) &&
2691 !strchr(afl->fsrv.target_path + 5, '/')) ||
2692 (!strncmp(afl->fsrv.target_path, "/var/tmp/", 9) &&
2693 !strchr(afl->fsrv.target_path + 9, '/'))) {
2694
2695 FATAL("Please don't keep binaries in /tmp or /var/tmp");
2696
2697 }
2698
2699 */
2700
2701 fd = open(afl->fsrv.target_path, O_RDONLY);
2702
2703 if (fd < 0) { PFATAL("Unable to open '%s'", afl->fsrv.target_path); }
2704
2705 f_data = mmap(0, f_len, PROT_READ, MAP_PRIVATE, fd, 0);
2706
2707 if (f_data == MAP_FAILED) {
2708
2709 PFATAL("Unable to mmap file '%s'", afl->fsrv.target_path);
2710
2711 }
2712
2713 close(fd);
2714
2715 if (f_data[0] == '#' && f_data[1] == '!') {
2716
2717 SAYF("\n" cLRD "[-] " cRST
2718 "Oops, the target binary looks like a shell script. Some build "
2719 "systems will\n"
2720 " sometimes generate shell stubs for dynamically linked programs; "
2721 "try static\n"
2722 " library mode (./configure --disable-shared) if that's the "
2723 "case.\n\n"
2724
2725 " Another possible cause is that you are actually trying to use a "
2726 "shell\n"
2727 " wrapper around the fuzzed component. Invoking shell can slow "
2728 "down the\n"
2729 " fuzzing process by a factor of 20x or more; it's best to write "
2730 "the wrapper\n"
2731 " in a compiled language instead.\n");
2732
2733 FATAL("Program '%s' is a shell script", afl->fsrv.target_path);
2734
2735 }
2736
2737 #ifndef __APPLE__
2738
2739 if (f_data[0] != 0x7f || memcmp(f_data + 1, "ELF", 3)) {
2740
2741 FATAL("Program '%s' is not an ELF binary", afl->fsrv.target_path);
2742
2743 }
2744
2745 #else
2746
2747 #if !defined(__arm__) && !defined(__arm64__)
2748 if ((f_data[0] != 0xCF || f_data[1] != 0xFA || f_data[2] != 0xED) &&
2749 (f_data[0] != 0xCA || f_data[1] != 0xFE || f_data[2] != 0xBA))
2750 FATAL("Program '%s' is not a 64-bit or universal Mach-O binary",
2751 afl->fsrv.target_path);
2752 #endif
2753
2754 #endif /* ^!__APPLE__ */
2755
2756 if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode &&
2757 #ifdef __linux__
2758 !afl->fsrv.nyx_mode &&
2759 #endif
2760 !afl->fsrv.cs_mode && !afl->non_instrumented_mode &&
2761 !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
2762
2763 SAYF("\n" cLRD "[-] " cRST
2764 "Looks like the target binary is not instrumented! The fuzzer depends "
2765 "on\n"
2766 " compile-time instrumentation to isolate interesting test cases "
2767 "while\n"
2768 " mutating the input data. For more information, and for tips on "
2769 "how to\n"
2770 " instrument binaries, please see %s/README.md.\n\n"
2771
2772 " When source code is not available, you may be able to leverage "
2773 "QEMU\n"
2774 " mode support. Consult the README.md for tips on how to enable "
2775 "this.\n\n"
2776
2777 " If your target is an instrumented binary (e.g. with zafl, "
2778 "retrowrite,\n"
2779 " etc.) then set 'AFL_SKIP_BIN_CHECK=1'\n\n"
2780
2781 " (It is also possible to use afl-fuzz as a traditional, "
2782 "non-instrumented\n"
2783 " fuzzer. For that use the -n option - but expect much worse "
2784 "results.)\n",
2785 doc_path);
2786
2787 FATAL("No instrumentation detected");
2788
2789 }
2790
2791 if ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
2792 memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
2793
2794 SAYF("\n" cLRD "[-] " cRST
2795 "This program appears to be instrumented with afl-gcc, but is being "
2796 "run in\n"
2797 " QEMU mode (-Q). This is probably not what you "
2798 "want -\n"
2799 " this setup will be slow and offer no practical benefits.\n");
2800
2801 FATAL("Instrumentation found in -Q mode");
2802
2803 }
2804
2805 if (memmem(f_data, f_len, "__asan_init", 11) ||
2806 memmem(f_data, f_len, "__msan_init", 11) ||
2807 memmem(f_data, f_len, "__lsan_init", 11)) {
2808
2809 afl->fsrv.uses_asan = 1;
2810
2811 }
2812
2813 /* Detect persistent & deferred init signatures in the binary. */
2814
2815 if (memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
2816
2817 OKF(cPIN "Persistent mode binary detected.");
2818 setenv(PERSIST_ENV_VAR, "1", 1);
2819 afl->persistent_mode = 1;
2820 afl->fsrv.persistent_mode = 1;
2821 afl->shmem_testcase_mode = 1;
2822
2823 } else if (getenv("AFL_PERSISTENT")) {
2824
2825 OKF(cPIN "Persistent mode enforced.");
2826 setenv(PERSIST_ENV_VAR, "1", 1);
2827 afl->persistent_mode = 1;
2828 afl->fsrv.persistent_mode = 1;
2829 afl->shmem_testcase_mode = 1;
2830
2831 } else if (getenv("AFL_FRIDA_PERSISTENT_ADDR")) {
2832
2833 OKF("FRIDA Persistent mode configuration options detected.");
2834 setenv(PERSIST_ENV_VAR, "1", 1);
2835 afl->persistent_mode = 1;
2836 afl->fsrv.persistent_mode = 1;
2837 afl->shmem_testcase_mode = 1;
2838
2839 }
2840
2841 if (afl->fsrv.frida_mode ||
2842 memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
2843
2844 OKF(cPIN "Deferred forkserver binary detected.");
2845 setenv(DEFER_ENV_VAR, "1", 1);
2846 afl->deferred_mode = 1;
2847
2848 } else if (getenv("AFL_DEFER_FORKSRV")) {
2849
2850 OKF(cPIN "Deferred forkserver enforced.");
2851 setenv(DEFER_ENV_VAR, "1", 1);
2852 afl->deferred_mode = 1;
2853
2854 }
2855
2856 if (munmap(f_data, f_len)) { PFATAL("unmap() failed"); }
2857
2858 }
2859
2860 /* Check if we're on TTY. */
2861
2862 void check_if_tty(afl_state_t *afl) {
2863
2864 struct winsize ws;
2865
2866 if (afl->afl_env.afl_no_ui) {
2867
2868 OKF("Disabling the UI because AFL_NO_UI is set.");
2869 afl->not_on_tty = 1;
2870 return;
2871
2872 }
2873
2874 if (ioctl(1, TIOCGWINSZ, &ws)) {
2875
2876 if (errno == ENOTTY) {
2877
2878 OKF("Looks like we're not running on a tty, so I'll be a bit less "
2879 "verbose.");
2880 afl->not_on_tty = 1;
2881
2882 }
2883
2884 return;
2885
2886 }
2887
2888 }
2889
2890 /* Set up signal handlers. More complicated that needs to be, because libc on
2891 Solaris doesn't resume interrupted reads(), sets SA_RESETHAND when you call
2892 siginterrupt(), and does other stupid things. */
2893
2894 void setup_signal_handlers(void) {
2895
2896 struct sigaction sa;
2897
2898 sa.sa_handler = NULL;
2899 sa.sa_flags = SA_RESTART;
2900 sa.sa_sigaction = NULL;
2901
2902 sigemptyset(&sa.sa_mask);
2903
2904 /* Various ways of saying "stop". */
2905
2906 sa.sa_handler = handle_stop_sig;
2907 sigaction(SIGHUP, &sa, NULL);
2908 sigaction(SIGINT, &sa, NULL);
2909 sigaction(SIGTERM, &sa, NULL);
2910
2911 /* Window resize */
2912
2913 sa.sa_handler = handle_resize;
2914 sigaction(SIGWINCH, &sa, NULL);
2915
2916 /* SIGUSR1: skip entry */
2917
2918 sa.sa_handler = handle_skipreq;
2919 sigaction(SIGUSR1, &sa, NULL);
2920
2921 /* Things we don't care about. */
2922
2923 sa.sa_handler = SIG_IGN;
2924 sigaction(SIGTSTP, &sa, NULL);
2925 sigaction(SIGPIPE, &sa, NULL);
2926
2927 }
2928
2929 /* Make a copy of the current command line. */
2930
2931 void save_cmdline(afl_state_t *afl, u32 argc, char **argv) {
2932
2933 u32 len = 1, i;
2934 u8 *buf;
2935
2936 for (i = 0; i < argc; ++i) {
2937
2938 len += strlen(argv[i]) + 1;
2939
2940 }
2941
2942 buf = afl->orig_cmdline = ck_alloc(len);
2943
2944 for (i = 0; i < argc; ++i) {
2945
2946 u32 l = strlen(argv[i]);
2947
2948 if (!argv[i] || !buf) { FATAL("null deref detected"); }
2949
2950 memcpy(buf, argv[i], l);
2951 buf += l;
2952
2953 if (i != argc - 1) { *(buf++) = ' '; }
2954
2955 }
2956
2957 *buf = 0;
2958
2959 }
2960
2961