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