1 /*
2 american fuzzy lop++ - forkserver code
3 --------------------------------------
4
5 Originally written by Michal Zalewski
6
7 Forkserver design by Jann Horn <[email protected]>
8
9 Now maintained by Marc Heuse <[email protected]>,
10 Heiko Eißfeldt <[email protected]> and
11 Andrea Fioraldi <[email protected]> and
12 Dominik Maier <[email protected]>
13
14
15 Copyright 2016, 2017 Google Inc. All rights reserved.
16 Copyright 2019-2024 AFLplusplus Project. All rights reserved.
17
18 Licensed under the Apache License, Version 2.0 (the "License");
19 you may not use this file except in compliance with the License.
20 You may obtain a copy of the License at:
21
22 https://www.apache.org/licenses/LICENSE-2.0
23
24 Shared code that implements a forkserver. This is used by the fuzzer
25 as well the other components like afl-tmin.
26
27 */
28
29 #include "config.h"
30 #include "types.h"
31 #include "debug.h"
32 #include "common.h"
33 #include "list.h"
34 #include "forkserver.h"
35 #include "hash.h"
36
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42 #include <errno.h>
43 #include <signal.h>
44 #include <fcntl.h>
45 #include <limits.h>
46 #include <sys/time.h>
47 #include <sys/wait.h>
48 #include <sys/resource.h>
49 #include <sys/select.h>
50 #include <sys/stat.h>
51
52 #ifdef __linux__
53 #include <dlfcn.h>
54
55 /* function to load nyx_helper function from libnyx.so */
56
afl_load_libnyx_plugin(u8 * libnyx_binary)57 nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
58
59 void *handle;
60 nyx_plugin_handler_t *plugin = calloc(1, sizeof(nyx_plugin_handler_t));
61
62 ACTF("Trying to load libnyx.so plugin...");
63 handle = dlopen((char *)libnyx_binary, RTLD_NOW);
64 if (!handle) { goto fail; }
65
66 plugin->nyx_config_load = dlsym(handle, "nyx_config_load");
67 if (plugin->nyx_config_load == NULL) { goto fail; }
68
69 plugin->nyx_config_set_workdir_path =
70 dlsym(handle, "nyx_config_set_workdir_path");
71 if (plugin->nyx_config_set_workdir_path == NULL) { goto fail; }
72
73 plugin->nyx_config_set_input_buffer_size =
74 dlsym(handle, "nyx_config_set_input_buffer_size");
75 if (plugin->nyx_config_set_input_buffer_size == NULL) { goto fail; }
76
77 plugin->nyx_config_set_input_buffer_write_protection =
78 dlsym(handle, "nyx_config_set_input_buffer_write_protection");
79 if (plugin->nyx_config_set_input_buffer_write_protection == NULL) {
80
81 goto fail;
82
83 }
84
85 plugin->nyx_config_set_hprintf_fd =
86 dlsym(handle, "nyx_config_set_hprintf_fd");
87 if (plugin->nyx_config_set_hprintf_fd == NULL) { goto fail; }
88
89 plugin->nyx_config_set_process_role =
90 dlsym(handle, "nyx_config_set_process_role");
91 if (plugin->nyx_config_set_process_role == NULL) { goto fail; }
92
93 plugin->nyx_config_set_reuse_snapshot_path =
94 dlsym(handle, "nyx_config_set_reuse_snapshot_path");
95 if (plugin->nyx_config_set_reuse_snapshot_path == NULL) { goto fail; }
96
97 plugin->nyx_new = dlsym(handle, "nyx_new");
98 if (plugin->nyx_new == NULL) { goto fail; }
99
100 plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown");
101 if (plugin->nyx_shutdown == NULL) { goto fail; }
102
103 plugin->nyx_option_set_reload_mode =
104 dlsym(handle, "nyx_option_set_reload_mode");
105 if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; }
106
107 plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout");
108 if (plugin->nyx_option_set_timeout == NULL) { goto fail; }
109
110 plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply");
111 if (plugin->nyx_option_apply == NULL) { goto fail; }
112
113 plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input");
114 if (plugin->nyx_set_afl_input == NULL) { goto fail; }
115
116 plugin->nyx_exec = dlsym(handle, "nyx_exec");
117 if (plugin->nyx_exec == NULL) { goto fail; }
118
119 plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer");
120 if (plugin->nyx_get_bitmap_buffer == NULL) { goto fail; }
121
122 plugin->nyx_get_bitmap_buffer_size =
123 dlsym(handle, "nyx_get_bitmap_buffer_size");
124 if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; }
125
126 plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string");
127 if (plugin->nyx_get_aux_string == NULL) { goto fail; }
128
129 plugin->nyx_remove_work_dir = dlsym(handle, "nyx_remove_work_dir");
130 if (plugin->nyx_remove_work_dir == NULL) { goto fail; }
131
132 plugin->nyx_config_set_aux_buffer_size =
133 dlsym(handle, "nyx_config_set_aux_buffer_size");
134 if (plugin->nyx_config_set_aux_buffer_size == NULL) { goto fail; }
135
136 OKF("libnyx plugin is ready!");
137 return plugin;
138
139 fail:
140
141 FATAL("failed to load libnyx: %s\n", dlerror());
142 ck_free(plugin);
143 return NULL;
144
145 }
146
afl_nyx_runner_kill(afl_forkserver_t * fsrv)147 void afl_nyx_runner_kill(afl_forkserver_t *fsrv) {
148
149 if (fsrv->nyx_mode) {
150
151 if (fsrv->nyx_aux_string) { ck_free(fsrv->nyx_aux_string); }
152
153 /* check if we actually got a valid nyx runner */
154 if (fsrv->nyx_runner) {
155
156 fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
157
158 }
159
160 /* if we have use a tmp work dir we need to remove it */
161 if (fsrv->nyx_use_tmp_workdir && fsrv->nyx_tmp_workdir_path) {
162
163 remove_nyx_tmp_workdir(fsrv, fsrv->nyx_tmp_workdir_path);
164
165 }
166
167 if (fsrv->nyx_log_fd >= 0) { close(fsrv->nyx_log_fd); }
168
169 }
170
171 }
172
173 /* Wrapper for FATAL() that kills the nyx runner (and removes all created tmp
174 * files) before exiting. Used before "afl_fsrv_killall()" is registered as
175 * an atexit() handler. */
176 #define NYX_PRE_FATAL(fsrv, x...) \
177 do { \
178 \
179 afl_nyx_runner_kill(fsrv); \
180 FATAL(x); \
181 \
182 } while (0)
183
184 #endif
185
186 /**
187 * The correct fds for reading and writing pipes
188 */
189
190 /* Describe integer as memory size. */
191
192 static list_t fsrv_list = {.element_prealloc_count = 0};
193
fsrv_exec_child(afl_forkserver_t * fsrv,char ** argv)194 static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
195
196 if (fsrv->qemu_mode || fsrv->cs_mode) {
197
198 setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0);
199
200 }
201
202 execv(fsrv->target_path, argv);
203
204 WARNF("Execv failed in forkserver.");
205
206 }
207
208 /* Initializes the struct */
209
afl_fsrv_init(afl_forkserver_t * fsrv)210 void afl_fsrv_init(afl_forkserver_t *fsrv) {
211
212 #ifdef __linux__
213 fsrv->nyx_handlers = NULL;
214 fsrv->out_dir_path = NULL;
215 fsrv->nyx_mode = 0;
216 fsrv->nyx_parent = false;
217 fsrv->nyx_standalone = false;
218 fsrv->nyx_runner = NULL;
219 fsrv->nyx_id = 0xFFFFFFFF;
220 fsrv->nyx_bind_cpu_id = 0xFFFFFFFF;
221 fsrv->nyx_use_tmp_workdir = false;
222 fsrv->nyx_tmp_workdir_path = NULL;
223 fsrv->nyx_log_fd = -1;
224 #endif
225
226 // this structure needs default so we initialize it if this was not done
227 // already
228 fsrv->out_fd = -1;
229 fsrv->out_dir_fd = -1;
230 fsrv->dev_null_fd = -1;
231 fsrv->dev_urandom_fd = -1;
232
233 /* Settings */
234 fsrv->use_stdin = true;
235 fsrv->no_unlink = false;
236 fsrv->exec_tmout = EXEC_TIMEOUT;
237 fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT;
238 fsrv->mem_limit = MEM_LIMIT;
239 fsrv->out_file = NULL;
240 fsrv->child_kill_signal = SIGKILL;
241
242 /* exec related stuff */
243 fsrv->child_pid = -1;
244 fsrv->map_size = get_map_size();
245 fsrv->real_map_size = fsrv->map_size;
246 fsrv->use_fauxsrv = false;
247 fsrv->last_run_timed_out = false;
248 fsrv->debug = false;
249 fsrv->uses_crash_exitcode = false;
250 fsrv->uses_asan = false;
251
252 fsrv->init_child_func = fsrv_exec_child;
253 list_append(&fsrv_list, fsrv);
254
255 }
256
257 /* Initialize a new forkserver instance, duplicating "global" settings */
afl_fsrv_init_dup(afl_forkserver_t * fsrv_to,afl_forkserver_t * from)258 void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
259
260 fsrv_to->use_stdin = from->use_stdin;
261 fsrv_to->dev_null_fd = from->dev_null_fd;
262 fsrv_to->exec_tmout = from->exec_tmout;
263 fsrv_to->init_tmout = from->init_tmout;
264 fsrv_to->mem_limit = from->mem_limit;
265 fsrv_to->map_size = from->map_size;
266 fsrv_to->real_map_size = from->real_map_size;
267 fsrv_to->support_shmem_fuzz = from->support_shmem_fuzz;
268 fsrv_to->out_file = from->out_file;
269 fsrv_to->dev_urandom_fd = from->dev_urandom_fd;
270 fsrv_to->out_fd = from->out_fd; // not sure this is a good idea
271 fsrv_to->no_unlink = from->no_unlink;
272 fsrv_to->uses_crash_exitcode = from->uses_crash_exitcode;
273 fsrv_to->crash_exitcode = from->crash_exitcode;
274 fsrv_to->child_kill_signal = from->child_kill_signal;
275 fsrv_to->fsrv_kill_signal = from->fsrv_kill_signal;
276 fsrv_to->debug = from->debug;
277
278 // These are forkserver specific.
279 fsrv_to->out_dir_fd = -1;
280 fsrv_to->child_pid = -1;
281 fsrv_to->use_fauxsrv = 0;
282 fsrv_to->last_run_timed_out = 0;
283
284 fsrv_to->init_child_func = from->init_child_func;
285 // Note: do not copy ->add_extra_func or ->persistent_record*
286
287 list_append(&fsrv_list, fsrv_to);
288
289 }
290
291 /* Wrapper for select() and read(), reading a 32 bit var.
292 Returns the time passed to read.
293 If the wait times out, returns timeout_ms + 1;
294 Returns 0 if an error occurred (fd closed, signal, ...); */
295 static u32 __attribute__((hot))
read_s32_timed(s32 fd,s32 * buf,u32 timeout_ms,volatile u8 * stop_soon_p)296 read_s32_timed(s32 fd, s32 *buf, u32 timeout_ms, volatile u8 *stop_soon_p) {
297
298 fd_set readfds;
299 FD_ZERO(&readfds);
300 FD_SET(fd, &readfds);
301 struct timeval timeout;
302 int sret;
303 ssize_t len_read;
304
305 timeout.tv_sec = (timeout_ms / 1000);
306 timeout.tv_usec = (timeout_ms % 1000) * 1000;
307 #if !defined(__linux__)
308 u32 read_start = get_cur_time_us();
309 #endif
310
311 /* set exceptfds as well to return when a child exited/closed the pipe. */
312 restart_select:
313 sret = select(fd + 1, &readfds, NULL, NULL, &timeout);
314
315 if (likely(sret > 0)) {
316
317 restart_read:
318 if (*stop_soon_p) {
319
320 // Early return - the user wants to quit.
321 return 0;
322
323 }
324
325 len_read = read(fd, (u8 *)buf, 4);
326
327 if (likely(len_read == 4)) { // for speed we put this first
328
329 #if defined(__linux__)
330 u32 exec_ms = MIN(
331 timeout_ms,
332 ((u64)timeout_ms - (timeout.tv_sec * 1000 + timeout.tv_usec / 1000)));
333 #else
334 u32 exec_ms = MIN(timeout_ms, (get_cur_time_us() - read_start) / 1000);
335 #endif
336
337 // ensure to report 1 ms has passed (0 is an error)
338 return exec_ms > 0 ? exec_ms : 1;
339
340 } else if (unlikely(len_read == -1 && errno == EINTR)) {
341
342 goto restart_read;
343
344 } else if (unlikely(len_read < 4)) {
345
346 return 0;
347
348 }
349
350 } else if (unlikely(!sret)) {
351
352 *buf = -1;
353 return timeout_ms + 1;
354
355 } else if (unlikely(sret < 0)) {
356
357 if (likely(errno == EINTR)) goto restart_select;
358
359 *buf = -1;
360 return 0;
361
362 }
363
364 return 0; // not reached
365
366 }
367
368 /* Internal forkserver for non_instrumented_mode=1 and non-forkserver mode runs.
369 It execvs for each fork, forwarding exit codes and child pids to afl. */
370
afl_fauxsrv_execv(afl_forkserver_t * fsrv,char ** argv)371 static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
372
373 unsigned char tmp[4] = {0, 0, 0, 0};
374 pid_t child_pid;
375
376 if (!be_quiet) { ACTF("Using Fauxserver:"); }
377
378 /* Phone home and tell the parent that we're OK. If parent isn't there,
379 assume we're not running in forkserver mode and just execute program. */
380
381 if (write(FORKSRV_FD + 1, tmp, 4) != 4) {
382
383 abort(); // TODO: Abort?
384
385 }
386
387 void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
388
389 while (1) {
390
391 uint32_t was_killed;
392 int status;
393
394 /* Wait for parent by reading from the pipe. Exit if read fails. */
395
396 if (read(FORKSRV_FD, &was_killed, 4) != 4) { exit(0); }
397
398 /* Create a clone of our process. */
399
400 child_pid = fork();
401
402 if (child_pid < 0) { PFATAL("Fork failed"); }
403
404 /* In child process: close fds, resume execution. */
405
406 if (!child_pid) { // New child
407
408 close(fsrv->out_dir_fd);
409 close(fsrv->dev_null_fd);
410 close(fsrv->dev_urandom_fd);
411
412 if (fsrv->plot_file != NULL) {
413
414 fclose(fsrv->plot_file);
415 fsrv->plot_file = NULL;
416
417 }
418
419 // enable terminating on sigpipe in the childs
420 struct sigaction sa;
421 memset((char *)&sa, 0, sizeof(sa));
422 sa.sa_handler = SIG_DFL;
423 sigaction(SIGPIPE, &sa, NULL);
424
425 signal(SIGCHLD, old_sigchld_handler);
426
427 // FORKSRV_FD is for communication with AFL, we don't need it in the
428 // child
429 close(FORKSRV_FD);
430 close(FORKSRV_FD + 1);
431
432 // finally: exec...
433 execv(fsrv->target_path, argv);
434
435 /* Use a distinctive bitmap signature to tell the parent about execv()
436 falling through. */
437
438 *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
439
440 WARNF("Execv failed in fauxserver.");
441 break;
442
443 }
444
445 /* In parent process: write PID to AFL. */
446
447 if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) { exit(0); }
448
449 /* after child exited, get and relay exit status to parent through waitpid.
450 */
451
452 if (waitpid(child_pid, &status, 0) < 0) {
453
454 // Zombie Child could not be collected. Scary!
455 WARNF("Fauxserver could not determine child's exit code. ");
456
457 }
458
459 /* Relay wait status to AFL pipe, then loop back. */
460
461 if (write(FORKSRV_FD + 1, &status, 4) != 4) { exit(1); }
462
463 }
464
465 }
466
467 /* Report on the error received via the forkserver controller and exit */
report_error_and_exit(int error)468 static void report_error_and_exit(int error) {
469
470 switch (error) {
471
472 case FS_ERROR_MAP_SIZE:
473 FATAL(
474 "AFL_MAP_SIZE is not set and fuzzing target reports that the "
475 "required size is very large. Solution: Run the fuzzing target "
476 "stand-alone with the environment variable AFL_DEBUG=1 set and set "
477 "the value for __afl_final_loc in the AFL_MAP_SIZE environment "
478 "variable for afl-fuzz.");
479 break;
480 case FS_ERROR_MAP_ADDR:
481 FATAL(
482 "the fuzzing target reports that hardcoded map address might be the "
483 "reason the mmap of the shared memory failed. Solution: recompile "
484 "the target with either afl-clang-lto and do not set "
485 "AFL_LLVM_MAP_ADDR or recompile with afl-clang-fast.");
486 break;
487 case FS_ERROR_SHM_OPEN:
488 FATAL("the fuzzing target reports that the shm_open() call failed.");
489 break;
490 case FS_ERROR_SHMAT:
491 FATAL("the fuzzing target reports that the shmat() call failed.");
492 break;
493 case FS_ERROR_MMAP:
494 FATAL(
495 "the fuzzing target reports that the mmap() call to the shared "
496 "memory failed.");
497 break;
498 case FS_ERROR_OLD_CMPLOG:
499 FATAL(
500 "the -c cmplog target was instrumented with an too old AFL++ "
501 "version, you need to recompile it.");
502 break;
503 case FS_ERROR_OLD_CMPLOG_QEMU:
504 FATAL(
505 "The AFL++ QEMU/FRIDA loaders are from an older version, for -c you "
506 "need to recompile it.\n");
507 break;
508 default:
509 FATAL("unknown error code %d from fuzzing target!", error);
510
511 }
512
513 }
514
515 /* Spins up fork server. The idea is explained here:
516
517 https://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html
518
519 In essence, the instrumentation allows us to skip execve(), and just keep
520 cloning a stopped child. So, we just execute once, and then send commands
521 through a pipe. The other part of this logic is in afl-as.h / llvm_mode */
522
afl_fsrv_start(afl_forkserver_t * fsrv,char ** argv,volatile u8 * stop_soon_p,u8 debug_child_output)523 void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
524 volatile u8 *stop_soon_p, u8 debug_child_output) {
525
526 int st_pipe[2], ctl_pipe[2];
527 s32 status;
528 s32 rlen;
529 char *ignore_autodict = getenv("AFL_NO_AUTODICT");
530
531 #ifdef __linux__
532 if (unlikely(fsrv->nyx_mode)) {
533
534 if (fsrv->nyx_runner != NULL) { return; }
535
536 if (!be_quiet) { ACTF("Spinning up the NYX backend..."); }
537
538 if (fsrv->nyx_use_tmp_workdir) {
539
540 fsrv->nyx_tmp_workdir_path = create_nyx_tmp_workdir();
541 fsrv->out_dir_path = fsrv->nyx_tmp_workdir_path;
542
543 } else {
544
545 if (fsrv->out_dir_path == NULL) {
546
547 NYX_PRE_FATAL(fsrv, "Nyx workdir path not found...");
548
549 }
550
551 }
552
553 /* libnyx expects an absolute path */
554 char *outdir_path_absolute = realpath(fsrv->out_dir_path, NULL);
555 if (outdir_path_absolute == NULL) {
556
557 NYX_PRE_FATAL(fsrv, "Nyx workdir path cannot be resolved ...");
558
559 }
560
561 char *workdir_path = alloc_printf("%s/workdir", outdir_path_absolute);
562
563 if (fsrv->nyx_id == 0xFFFFFFFF) {
564
565 NYX_PRE_FATAL(fsrv, "Nyx ID is not set...");
566
567 }
568
569 if (fsrv->nyx_bind_cpu_id == 0xFFFFFFFF) {
570
571 NYX_PRE_FATAL(fsrv, "Nyx CPU ID is not set...");
572
573 }
574
575 void *nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path);
576
577 fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, workdir_path);
578 fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config, MAX_FILE);
579 fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config,
580 true);
581
582 char *nyx_log_path = getenv("AFL_NYX_LOG");
583 if (nyx_log_path) {
584
585 fsrv->nyx_log_fd =
586 open(nyx_log_path, O_CREAT | O_TRUNC | O_WRONLY, DEFAULT_PERMISSION);
587 if (fsrv->nyx_log_fd < 0) {
588
589 NYX_PRE_FATAL(fsrv, "AFL_NYX_LOG path could not be written");
590
591 }
592
593 fsrv->nyx_handlers->nyx_config_set_hprintf_fd(nyx_config,
594 fsrv->nyx_log_fd);
595
596 }
597
598 if (fsrv->nyx_standalone) {
599
600 fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, StandAlone);
601
602 } else {
603
604 if (fsrv->nyx_parent) {
605
606 fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Parent);
607
608 } else {
609
610 fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Child);
611
612 }
613
614 }
615
616 if (getenv("AFL_NYX_AUX_SIZE") != NULL) {
617
618 fsrv->nyx_aux_string_len = atoi(getenv("AFL_NYX_AUX_SIZE"));
619
620 if (fsrv->nyx_handlers->nyx_config_set_aux_buffer_size(
621 nyx_config, fsrv->nyx_aux_string_len) != 1) {
622
623 NYX_PRE_FATAL(fsrv,
624 "Invalid AFL_NYX_AUX_SIZE value set (must be a multiple "
625 "of 4096) ...");
626
627 }
628
629 } else {
630
631 fsrv->nyx_aux_string_len = 0x1000;
632
633 }
634
635 if (getenv("AFL_NYX_REUSE_SNAPSHOT") != NULL) {
636
637 if (access(getenv("AFL_NYX_REUSE_SNAPSHOT"), F_OK) == -1) {
638
639 NYX_PRE_FATAL(fsrv, "AFL_NYX_REUSE_SNAPSHOT path does not exist");
640
641 }
642
643 /* stupid sanity check to avoid passing an empty or invalid snapshot
644 * directory */
645 char *snapshot_file_path =
646 alloc_printf("%s/global.state", getenv("AFL_NYX_REUSE_SNAPSHOT"));
647 if (access(snapshot_file_path, R_OK) == -1) {
648
649 NYX_PRE_FATAL(fsrv,
650 "AFL_NYX_REUSE_SNAPSHOT path does not contain a valid "
651 "Nyx snapshot");
652
653 }
654
655 ck_free(snapshot_file_path);
656
657 /* another sanity check to avoid passing a snapshot directory that is
658 * located in the current workdir (the workdir will be wiped by libnyx on
659 * startup) */
660 char *workdir_snapshot_path =
661 alloc_printf("%s/workdir/snapshot", outdir_path_absolute);
662 char *reuse_snapshot_path_real =
663 realpath(getenv("AFL_NYX_REUSE_SNAPSHOT"), NULL);
664
665 if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0) {
666
667 NYX_PRE_FATAL(
668 fsrv,
669 "AFL_NYX_REUSE_SNAPSHOT path is located in current workdir "
670 "(use another output directory)");
671
672 }
673
674 ck_free(reuse_snapshot_path_real);
675 ck_free(workdir_snapshot_path);
676
677 fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(
678 nyx_config, getenv("AFL_NYX_REUSE_SNAPSHOT"));
679
680 }
681
682 fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_id);
683
684 ck_free(workdir_path);
685 ck_free(outdir_path_absolute);
686
687 if (fsrv->nyx_runner == NULL) { FATAL("Something went wrong ..."); }
688
689 u32 tmp_map_size =
690 fsrv->nyx_handlers->nyx_get_bitmap_buffer_size(fsrv->nyx_runner);
691 fsrv->real_map_size = tmp_map_size;
692 fsrv->map_size = (((tmp_map_size + 63) >> 6) << 6);
693 if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); }
694
695 fsrv->trace_bits =
696 fsrv->nyx_handlers->nyx_get_bitmap_buffer(fsrv->nyx_runner);
697
698 fsrv->nyx_handlers->nyx_option_set_reload_mode(
699 fsrv->nyx_runner, getenv("AFL_NYX_DISABLE_SNAPSHOT_MODE") == NULL);
700 fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner);
701
702 fsrv->nyx_handlers->nyx_option_set_timeout(fsrv->nyx_runner, 2, 0);
703 fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner);
704
705 fsrv->nyx_aux_string = malloc(fsrv->nyx_aux_string_len);
706 memset(fsrv->nyx_aux_string, 0, fsrv->nyx_aux_string_len);
707
708 /* dry run */
709 fsrv->nyx_handlers->nyx_set_afl_input(fsrv->nyx_runner, "INIT", 4);
710 switch (fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)) {
711
712 case Abort:
713 NYX_PRE_FATAL(fsrv, "Error: Nyx abort occurred...");
714 break;
715 case IoError:
716 NYX_PRE_FATAL(fsrv, "Error: QEMU-Nyx has died...");
717 break;
718 case Error:
719 NYX_PRE_FATAL(fsrv, "Error: Nyx runtime error has occurred...");
720 break;
721 default:
722 break;
723
724 }
725
726 /* autodict in Nyx mode */
727 if (!ignore_autodict) {
728
729 char *x =
730 alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path);
731 int nyx_autodict_fd = open(x, O_RDONLY);
732 ck_free(x);
733
734 if (nyx_autodict_fd >= 0) {
735
736 struct stat st;
737 if (fstat(nyx_autodict_fd, &st) >= 0) {
738
739 u32 f_len = st.st_size;
740 u8 *dict = ck_alloc(f_len);
741 if (dict == NULL) {
742
743 NYX_PRE_FATAL(
744 fsrv, "Could not allocate %u bytes of autodictionary memory",
745 f_len);
746
747 }
748
749 u32 offset = 0, count = 0;
750 u32 len = f_len;
751
752 while (len != 0) {
753
754 rlen = read(nyx_autodict_fd, dict + offset, len);
755 if (rlen > 0) {
756
757 len -= rlen;
758 offset += rlen;
759
760 } else {
761
762 NYX_PRE_FATAL(
763 fsrv,
764 "Reading autodictionary fail at position %u with %u bytes "
765 "left.",
766 offset, len);
767
768 }
769
770 }
771
772 offset = 0;
773 while (offset < (u32)f_len &&
774 (u8)dict[offset] + offset < (u32)f_len) {
775
776 fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
777 (u8)dict[offset]);
778 offset += (1 + dict[offset]);
779 count++;
780
781 }
782
783 if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
784 ck_free(dict);
785
786 }
787
788 close(nyx_autodict_fd);
789
790 }
791
792 }
793
794 return;
795
796 }
797
798 #endif
799
800 if (!be_quiet) { ACTF("Spinning up the fork server..."); }
801
802 #ifdef AFL_PERSISTENT_RECORD
803 if (unlikely(fsrv->persistent_record)) {
804
805 fsrv->persistent_record_data =
806 (u8 **)ck_alloc(fsrv->persistent_record * sizeof(u8 *));
807 fsrv->persistent_record_len =
808 (u32 *)ck_alloc(fsrv->persistent_record * sizeof(u32));
809
810 if (!fsrv->persistent_record_data || !fsrv->persistent_record_len) {
811
812 FATAL("Unable to allocate memory for persistent replay.");
813
814 }
815
816 }
817
818 #endif
819
820 if (fsrv->use_fauxsrv) {
821
822 /* TODO: Come up with some nice way to initialize this all */
823
824 if (fsrv->init_child_func != fsrv_exec_child) {
825
826 FATAL("Different forkserver not compatible with fauxserver");
827
828 }
829
830 if (!be_quiet) { ACTF("Using AFL++ faux forkserver..."); }
831 fsrv->init_child_func = afl_fauxsrv_execv;
832
833 }
834
835 if (pipe(st_pipe) || pipe(ctl_pipe)) { PFATAL("pipe() failed"); }
836
837 fsrv->last_run_timed_out = 0;
838 fsrv->fsrv_pid = fork();
839
840 if (fsrv->fsrv_pid < 0) { PFATAL("fork() failed"); }
841
842 if (!fsrv->fsrv_pid) {
843
844 /* CHILD PROCESS */
845
846 // enable terminating on sigpipe in the childs
847 struct sigaction sa;
848 memset((char *)&sa, 0, sizeof(sa));
849 sa.sa_handler = SIG_DFL;
850 sigaction(SIGPIPE, &sa, NULL);
851
852 struct rlimit r;
853
854 if (!fsrv->cmplog_binary) {
855
856 unsetenv(CMPLOG_SHM_ENV_VAR); // we do not want that in non-cmplog fsrv
857
858 }
859
860 /* Umpf. On OpenBSD, the default fd limit for root users is set to
861 soft 128. Let's try to fix that... */
862 if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) {
863
864 r.rlim_cur = FORKSRV_FD + 2;
865 setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */
866
867 }
868
869 if (fsrv->mem_limit) {
870
871 r.rlim_max = r.rlim_cur = ((rlim_t)fsrv->mem_limit) << 20;
872
873 #ifdef RLIMIT_AS
874 setrlimit(RLIMIT_AS, &r); /* Ignore errors */
875 #else
876 /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but
877 according to reliable sources, RLIMIT_DATA covers anonymous
878 maps - so we should be getting good protection against OOM bugs. */
879
880 setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
881 #endif /* ^RLIMIT_AS */
882
883 }
884
885 /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered
886 before the dump is complete. */
887
888 if (!fsrv->debug) {
889
890 r.rlim_max = r.rlim_cur = 0;
891 setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
892
893 }
894
895 /* Isolate the process and configure standard descriptors. If out_file is
896 specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */
897
898 setsid();
899
900 if (!(debug_child_output)) {
901
902 dup2(fsrv->dev_null_fd, 1);
903 dup2(fsrv->dev_null_fd, 2);
904
905 }
906
907 if (!fsrv->use_stdin) {
908
909 dup2(fsrv->dev_null_fd, 0);
910
911 } else {
912
913 dup2(fsrv->out_fd, 0);
914 close(fsrv->out_fd);
915
916 }
917
918 /* Set up control and status pipes, close the unneeded original fds. */
919
920 if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) { PFATAL("dup2() failed"); }
921 if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) { PFATAL("dup2() failed"); }
922
923 close(ctl_pipe[0]);
924 close(ctl_pipe[1]);
925 close(st_pipe[0]);
926 close(st_pipe[1]);
927
928 close(fsrv->out_dir_fd);
929 close(fsrv->dev_null_fd);
930 close(fsrv->dev_urandom_fd);
931
932 if (fsrv->plot_file != NULL) {
933
934 fclose(fsrv->plot_file);
935 fsrv->plot_file = NULL;
936
937 }
938
939 /* This should improve performance a bit, since it stops the linker from
940 doing extra work post-fork(). */
941
942 if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); }
943
944 /* Set sane defaults for sanitizers */
945 set_sanitizer_defaults();
946
947 fsrv->init_child_func(fsrv, argv);
948
949 /* Use a distinctive bitmap signature to tell the parent about execv()
950 falling through. */
951
952 *(u32 *)fsrv->trace_bits = EXEC_FAIL_SIG;
953 FATAL("Error: execv to target failed\n");
954
955 }
956
957 /* PARENT PROCESS */
958
959 char pid_buf[16];
960 sprintf(pid_buf, "%d", fsrv->fsrv_pid);
961 if (fsrv->cmplog_binary)
962 setenv("__AFL_TARGET_PID2", pid_buf, 1);
963 else
964 setenv("__AFL_TARGET_PID1", pid_buf, 1);
965
966 /* Close the unneeded endpoints. */
967
968 close(ctl_pipe[0]);
969 close(st_pipe[1]);
970
971 fsrv->fsrv_ctl_fd = ctl_pipe[1];
972 fsrv->fsrv_st_fd = st_pipe[0];
973
974 /* Wait for the fork server to come up, but don't wait too long. */
975
976 rlen = 0;
977 if (fsrv->init_tmout) {
978
979 u32 time_ms = read_s32_timed(fsrv->fsrv_st_fd, &status, fsrv->init_tmout,
980 stop_soon_p);
981
982 if (!time_ms) {
983
984 s32 tmp_pid = fsrv->fsrv_pid;
985 if (tmp_pid > 0) {
986
987 kill(tmp_pid, fsrv->child_kill_signal);
988 fsrv->fsrv_pid = -1;
989
990 }
991
992 } else if (time_ms > fsrv->init_tmout) {
993
994 fsrv->last_run_timed_out = 1;
995 s32 tmp_pid = fsrv->fsrv_pid;
996 if (tmp_pid > 0) {
997
998 kill(tmp_pid, fsrv->child_kill_signal);
999 fsrv->fsrv_pid = -1;
1000
1001 }
1002
1003 } else {
1004
1005 rlen = 4;
1006
1007 }
1008
1009 } else {
1010
1011 rlen = read(fsrv->fsrv_st_fd, &status, 4);
1012
1013 }
1014
1015 /* If we have a four-byte "hello" message from the server, we're all set.
1016 Otherwise, try to figure out what went wrong. */
1017
1018 if (rlen == 4) {
1019
1020 if (status >= 0x41464c00 && status <= 0x41464cff) {
1021
1022 FATAL(
1023 "Target uses the new forkserver model, you need to switch to a newer "
1024 "afl-fuzz too!");
1025
1026 }
1027
1028 if (!be_quiet) { OKF("All right - fork server is up."); }
1029
1030 if (getenv("AFL_DEBUG")) {
1031
1032 ACTF("Extended forkserver functions received (%08x).", status);
1033
1034 }
1035
1036 if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
1037 report_error_and_exit(FS_OPT_GET_ERROR(status));
1038
1039 if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
1040
1041 // workaround for recent AFL++ versions
1042 if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND)
1043 status = (status & 0xf0ffffff);
1044
1045 if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) {
1046
1047 if (fsrv->qemu_mode || fsrv->frida_mode) {
1048
1049 report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU);
1050
1051 } else {
1052
1053 report_error_and_exit(FS_ERROR_OLD_CMPLOG);
1054
1055 }
1056
1057 }
1058
1059 if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
1060
1061 fsrv->snapshot = 1;
1062 if (!be_quiet) { ACTF("Using SNAPSHOT feature."); }
1063
1064 }
1065
1066 if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) {
1067
1068 if (fsrv->support_shmem_fuzz) {
1069
1070 fsrv->use_shmem_fuzz = 1;
1071 if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
1072
1073 if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) {
1074
1075 u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
1076 if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
1077
1078 FATAL("Writing to forkserver failed.");
1079
1080 }
1081
1082 }
1083
1084 } else {
1085
1086 FATAL(
1087 "Target requested sharedmem fuzzing, but we failed to enable "
1088 "it.");
1089
1090 }
1091
1092 }
1093
1094 if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) {
1095
1096 u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
1097
1098 if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; }
1099
1100 fsrv->real_map_size = tmp_map_size;
1101
1102 if (tmp_map_size % 64) {
1103
1104 tmp_map_size = (((tmp_map_size + 63) >> 6) << 6);
1105
1106 }
1107
1108 if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); }
1109 if (tmp_map_size > fsrv->map_size) {
1110
1111 FATAL(
1112 "Target's coverage map size of %u is larger than the one this "
1113 "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
1114 " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
1115 "afl-fuzz",
1116 tmp_map_size, fsrv->map_size, tmp_map_size);
1117
1118 }
1119
1120 fsrv->map_size = tmp_map_size;
1121
1122 }
1123
1124 if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
1125
1126 if (!ignore_autodict) {
1127
1128 if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
1129
1130 // this is not afl-fuzz - or it is cmplog - we deny and return
1131 if (fsrv->use_shmem_fuzz) {
1132
1133 status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
1134
1135 } else {
1136
1137 status = (FS_OPT_ENABLED);
1138
1139 }
1140
1141 if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
1142
1143 FATAL("Writing to forkserver failed.");
1144
1145 }
1146
1147 return;
1148
1149 }
1150
1151 if (!be_quiet) { ACTF("Using AUTODICT feature."); }
1152
1153 if (fsrv->use_shmem_fuzz) {
1154
1155 status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
1156
1157 } else {
1158
1159 status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
1160
1161 }
1162
1163 if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
1164
1165 FATAL("Writing to forkserver failed.");
1166
1167 }
1168
1169 if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
1170
1171 FATAL("Reading from forkserver failed.");
1172
1173 }
1174
1175 if (status < 2 || (u32)status > 0xffffff) {
1176
1177 FATAL("Dictionary has an illegal size: %d", status);
1178
1179 }
1180
1181 u32 offset = 0, count = 0;
1182 u32 len = status;
1183 u8 *dict = ck_alloc(len);
1184 if (dict == NULL) {
1185
1186 FATAL("Could not allocate %u bytes of autodictionary memory", len);
1187
1188 }
1189
1190 while (len != 0) {
1191
1192 rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
1193 if (rlen > 0) {
1194
1195 len -= rlen;
1196 offset += rlen;
1197
1198 } else {
1199
1200 FATAL(
1201 "Reading autodictionary fail at position %u with %u bytes "
1202 "left.",
1203 offset, len);
1204
1205 }
1206
1207 }
1208
1209 offset = 0;
1210 while (offset < (u32)status &&
1211 (u8)dict[offset] + offset < (u32)status) {
1212
1213 fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
1214 (u8)dict[offset]);
1215 offset += (1 + dict[offset]);
1216 count++;
1217
1218 }
1219
1220 if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
1221 ck_free(dict);
1222
1223 }
1224
1225 }
1226
1227 }
1228
1229 return;
1230
1231 }
1232
1233 if (fsrv->last_run_timed_out) {
1234
1235 FATAL(
1236 "Timeout while initializing fork server (setting "
1237 "AFL_FORKSRV_INIT_TMOUT may help)");
1238
1239 }
1240
1241 if (waitpid(fsrv->fsrv_pid, &status, 0) <= 0) { PFATAL("waitpid() failed"); }
1242
1243 if (WIFSIGNALED(status)) {
1244
1245 if (fsrv->mem_limit && fsrv->mem_limit < 500 && fsrv->uses_asan) {
1246
1247 SAYF("\n" cLRD "[-] " cRST
1248 "Whoops, the target binary crashed suddenly, "
1249 "before receiving any input\n"
1250 " from the fuzzer! Since it seems to be built with ASAN and you "
1251 "have a\n"
1252 " restrictive memory limit configured, this is expected; please "
1253 "run with '-m 0'.\n");
1254
1255 } else if (!fsrv->mem_limit) {
1256
1257 SAYF("\n" cLRD "[-] " cRST
1258 "Whoops, the target binary crashed suddenly, "
1259 "before receiving any input\n"
1260 " from the fuzzer! You can try the following:\n\n"
1261
1262 " - The target binary crashes because necessary runtime "
1263 "conditions it needs\n"
1264 " are not met. Try to:\n"
1265 " 1. Run again with AFL_DEBUG=1 set and check the output of "
1266 "the target\n"
1267 " binary for clues.\n"
1268 " 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
1269 "analyze the\n"
1270 " generated core dump.\n\n"
1271
1272 " - Possibly the target requires a huge coverage map and has "
1273 "CTORS.\n"
1274 " Retry with setting AFL_MAP_SIZE=10000000.\n\n"
1275
1276 MSG_FORK_ON_APPLE
1277
1278 " - Less likely, there is a horrible bug in the fuzzer. If other "
1279 "options\n"
1280 " fail, poke the Awesome Fuzzing Discord for troubleshooting "
1281 "tips.\n");
1282
1283 } else {
1284
1285 u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
1286
1287 SAYF("\n" cLRD "[-] " cRST
1288 "Whoops, the target binary crashed suddenly, "
1289 "before receiving any input\n"
1290 " from the fuzzer! You can try the following:\n\n"
1291
1292 " - The target binary crashes because necessary runtime "
1293 "conditions it needs\n"
1294 " are not met. Try to:\n"
1295 " 1. Run again with AFL_DEBUG=1 set and check the output of "
1296 "the target\n"
1297 " binary for clues.\n"
1298 " 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
1299 "analyze the\n"
1300 " generated core dump.\n\n"
1301
1302 " - The current memory limit (%s) is too restrictive, causing "
1303 "the\n"
1304 " target to hit an OOM condition in the dynamic linker. Try "
1305 "bumping up\n"
1306 " the limit with the -m setting in the command line. A simple "
1307 "way confirm\n"
1308 " this diagnosis would be:\n\n"
1309
1310 MSG_ULIMIT_USAGE
1311 " /path/to/fuzzed_app )\n\n"
1312
1313 " Tip: you can use https://jwilk.net/software/recidivm to\n"
1314 " estimate the required amount of virtual memory for the "
1315 "binary.\n\n"
1316
1317 MSG_FORK_ON_APPLE
1318
1319 " - Possibly the target requires a huge coverage map and has "
1320 "CTORS.\n"
1321 " Retry with setting AFL_MAP_SIZE=10000000.\n\n"
1322
1323 " - Less likely, there is a horrible bug in the fuzzer. If other "
1324 "options\n"
1325 " fail, poke the Awesome Fuzzing Discord for troubleshooting "
1326 "tips.\n",
1327 stringify_mem_size(val_buf, sizeof(val_buf), fsrv->mem_limit << 20),
1328 fsrv->mem_limit - 1);
1329
1330 }
1331
1332 FATAL("Fork server crashed with signal %d", WTERMSIG(status));
1333
1334 }
1335
1336 if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) {
1337
1338 FATAL("Unable to execute target application ('%s')", argv[0]);
1339
1340 }
1341
1342 if (fsrv->mem_limit && fsrv->mem_limit < 500 && fsrv->uses_asan) {
1343
1344 SAYF("\n" cLRD "[-] " cRST
1345 "Hmm, looks like the target binary terminated "
1346 "before we could complete a\n"
1347 " handshake with the injected code. Since it seems to be built "
1348 "with ASAN and\n"
1349 " you have a restrictive memory limit configured, this is "
1350 "expected; please\n"
1351 " run with '-m 0'.\n");
1352
1353 } else if (!fsrv->mem_limit) {
1354
1355 SAYF("\n" cLRD "[-] " cRST
1356 "Hmm, looks like the target binary terminated before we could complete"
1357 " a\n"
1358 "handshake with the injected code. You can try the following:\n\n"
1359
1360 " - The target binary crashes because necessary runtime conditions "
1361 "it needs\n"
1362 " are not met. Try to:\n"
1363 " 1. Run again with AFL_DEBUG=1 set and check the output of the "
1364 "target\n"
1365 " binary for clues.\n"
1366 " 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
1367 "analyze the\n"
1368 " generated core dump.\n\n"
1369
1370 " - Possibly the target requires a huge coverage map and has "
1371 "CTORS.\n"
1372 " Retry with setting AFL_MAP_SIZE=10000000.\n\n"
1373
1374 "Otherwise there is a horrible bug in the fuzzer.\n"
1375 "Poke the Awesome Fuzzing Discord for troubleshooting tips.\n");
1376
1377 } else {
1378
1379 u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
1380
1381 SAYF(
1382 "\n" cLRD "[-] " cRST
1383 "Hmm, looks like the target binary terminated "
1384 "before we could complete a\n"
1385 " handshake with the injected code. You can try the following:\n\n"
1386
1387 "%s"
1388
1389 " - The target binary crashes because necessary runtime conditions "
1390 "it needs\n"
1391 " are not met. Try to:\n"
1392 " 1. Run again with AFL_DEBUG=1 set and check the output of the "
1393 "target\n"
1394 " binary for clues.\n"
1395 " 2. Run again with AFL_DEBUG=1 and 'ulimit -c unlimited' and "
1396 "analyze the\n"
1397 " generated core dump.\n\n"
1398
1399 " - Possibly the target requires a huge coverage map and has "
1400 "CTORS.\n"
1401 " Retry with setting AFL_MAP_SIZE=10000000.\n\n"
1402
1403 " - The current memory limit (%s) is too restrictive, causing an "
1404 "OOM\n"
1405 " fault in the dynamic linker. This can be fixed with the -m "
1406 "option. A\n"
1407 " simple way to confirm the diagnosis may be:\n\n"
1408
1409 MSG_ULIMIT_USAGE
1410 " /path/to/fuzzed_app )\n\n"
1411
1412 " Tip: you can use https://jwilk.net/software/recidivm to\n"
1413 " estimate the required amount of virtual memory for the "
1414 "binary.\n\n"
1415
1416 " - The target was compiled with afl-clang-lto and a constructor "
1417 "was\n"
1418 " instrumented, recompiling without AFL_LLVM_MAP_ADDR might solve "
1419 "your \n"
1420 " problem\n\n"
1421
1422 " - Less likely, there is a horrible bug in the fuzzer. If other "
1423 "options\n"
1424 " fail, poke the Awesome Fuzzing Discord for troubleshooting "
1425 "tips.\n",
1426 getenv(DEFER_ENV_VAR)
1427 ? " - You are using deferred forkserver, but __AFL_INIT() is "
1428 "never\n"
1429 " reached before the program terminates.\n\n"
1430 : "",
1431 stringify_int(val_buf, sizeof(val_buf), fsrv->mem_limit << 20),
1432 fsrv->mem_limit - 1);
1433
1434 }
1435
1436 FATAL("Fork server handshake failed");
1437
1438 }
1439
1440 /* Stop the forkserver and child */
1441
afl_fsrv_kill(afl_forkserver_t * fsrv)1442 void afl_fsrv_kill(afl_forkserver_t *fsrv) {
1443
1444 if (fsrv->child_pid > 0) { kill(fsrv->child_pid, fsrv->child_kill_signal); }
1445 if (fsrv->fsrv_pid > 0) {
1446
1447 kill(fsrv->fsrv_pid, fsrv->fsrv_kill_signal);
1448 waitpid(fsrv->fsrv_pid, NULL, 0);
1449
1450 }
1451
1452 close(fsrv->fsrv_ctl_fd);
1453 close(fsrv->fsrv_st_fd);
1454 fsrv->fsrv_pid = -1;
1455 fsrv->child_pid = -1;
1456
1457 #ifdef __linux__
1458 afl_nyx_runner_kill(fsrv);
1459 #endif
1460
1461 }
1462
1463 /* Get the map size from the target forkserver */
1464
afl_fsrv_get_mapsize(afl_forkserver_t * fsrv,char ** argv,volatile u8 * stop_soon_p,u8 debug_child_output)1465 u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
1466 volatile u8 *stop_soon_p, u8 debug_child_output) {
1467
1468 afl_fsrv_start(fsrv, argv, stop_soon_p, debug_child_output);
1469 return fsrv->map_size;
1470
1471 }
1472
1473 /* Delete the current testcase and write the buf to the testcase file */
1474
1475 void __attribute__((hot))
afl_fsrv_write_to_testcase(afl_forkserver_t * fsrv,u8 * buf,size_t len)1476 afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
1477
1478 #ifdef __linux__
1479 if (unlikely(fsrv->nyx_mode)) {
1480
1481 fsrv->nyx_handlers->nyx_set_afl_input(fsrv->nyx_runner, buf, len);
1482 return;
1483
1484 }
1485
1486 #endif
1487
1488 #ifdef AFL_PERSISTENT_RECORD
1489 if (unlikely(fsrv->persistent_record)) {
1490
1491 fsrv->persistent_record_len[fsrv->persistent_record_idx] = len;
1492 fsrv->persistent_record_data[fsrv->persistent_record_idx] = afl_realloc(
1493 (void **)&fsrv->persistent_record_data[fsrv->persistent_record_idx],
1494 len);
1495
1496 if (unlikely(!fsrv->persistent_record_data[fsrv->persistent_record_idx])) {
1497
1498 FATAL("allocating replay memory failed.");
1499
1500 }
1501
1502 memcpy(fsrv->persistent_record_data[fsrv->persistent_record_idx], buf, len);
1503
1504 if (unlikely(++fsrv->persistent_record_idx >= fsrv->persistent_record)) {
1505
1506 fsrv->persistent_record_idx = 0;
1507
1508 }
1509
1510 }
1511
1512 #endif
1513
1514 if (likely(fsrv->use_shmem_fuzz)) {
1515
1516 if (unlikely(len > MAX_FILE)) len = MAX_FILE;
1517
1518 *fsrv->shmem_fuzz_len = len;
1519 memcpy(fsrv->shmem_fuzz, buf, len);
1520 #ifdef _DEBUG
1521 if (getenv("AFL_DEBUG")) {
1522
1523 fprintf(stderr, "FS crc: %016llx len: %u\n",
1524 hash64(fsrv->shmem_fuzz, *fsrv->shmem_fuzz_len, HASH_CONST),
1525 *fsrv->shmem_fuzz_len);
1526 fprintf(stderr, "SHM :");
1527 for (u32 i = 0; i < *fsrv->shmem_fuzz_len; i++)
1528 fprintf(stderr, "%02x", fsrv->shmem_fuzz[i]);
1529 fprintf(stderr, "\nORIG:");
1530 for (u32 i = 0; i < *fsrv->shmem_fuzz_len; i++)
1531 fprintf(stderr, "%02x", buf[i]);
1532 fprintf(stderr, "\n");
1533
1534 }
1535
1536 #endif
1537
1538 } else {
1539
1540 s32 fd = fsrv->out_fd;
1541
1542 if (!fsrv->use_stdin && fsrv->out_file) {
1543
1544 if (unlikely(fsrv->no_unlink)) {
1545
1546 fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC,
1547 DEFAULT_PERMISSION);
1548
1549 } else {
1550
1551 unlink(fsrv->out_file); /* Ignore errors. */
1552 fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL,
1553 DEFAULT_PERMISSION);
1554
1555 }
1556
1557 if (fd < 0) { PFATAL("Unable to create '%s'", fsrv->out_file); }
1558
1559 } else if (unlikely(fd <= 0)) {
1560
1561 // We should have a (non-stdin) fd at this point, else we got a problem.
1562 FATAL(
1563 "Nowhere to write output to (neither out_fd nor out_file set (fd is "
1564 "%d))",
1565 fd);
1566
1567 } else {
1568
1569 lseek(fd, 0, SEEK_SET);
1570
1571 }
1572
1573 // fprintf(stderr, "WRITE %d %u\n", fd, len);
1574 ck_write(fd, buf, len, fsrv->out_file);
1575
1576 if (fsrv->use_stdin) {
1577
1578 if (ftruncate(fd, len)) { PFATAL("ftruncate() failed"); }
1579 lseek(fd, 0, SEEK_SET);
1580
1581 } else {
1582
1583 close(fd);
1584
1585 }
1586
1587 }
1588
1589 }
1590
1591 /* Execute target application, monitoring for timeouts. Return status
1592 information. The called program will update afl->fsrv->trace_bits. */
1593
1594 fsrv_run_result_t __attribute__((hot))
afl_fsrv_run_target(afl_forkserver_t * fsrv,u32 timeout,volatile u8 * stop_soon_p)1595 afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
1596 volatile u8 *stop_soon_p) {
1597
1598 s32 res;
1599 u32 exec_ms;
1600 u32 write_value = fsrv->last_run_timed_out;
1601
1602 #ifdef __linux__
1603 if (fsrv->nyx_mode) {
1604
1605 static uint32_t last_timeout_value = 0;
1606
1607 if (last_timeout_value != timeout) {
1608
1609 fsrv->nyx_handlers->nyx_option_set_timeout(
1610 fsrv->nyx_runner, timeout / 1000, (timeout % 1000) * 1000);
1611 fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner);
1612 last_timeout_value = timeout;
1613
1614 }
1615
1616 enum NyxReturnValue ret_val =
1617 fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner);
1618
1619 fsrv->total_execs++;
1620
1621 switch (ret_val) {
1622
1623 case Normal:
1624 return FSRV_RUN_OK;
1625 case Crash:
1626 case Asan:
1627 return FSRV_RUN_CRASH;
1628 case Timeout:
1629 return FSRV_RUN_TMOUT;
1630 case InvalidWriteToPayload:
1631 /* ??? */
1632 FATAL("FixMe: Nyx InvalidWriteToPayload handler is missing");
1633 break;
1634 case Abort:
1635 FATAL("Error: Nyx abort occurred...");
1636 case IoError:
1637 if (*stop_soon_p) {
1638
1639 return 0;
1640
1641 } else {
1642
1643 FATAL("Error: QEMU-Nyx has died...");
1644
1645 }
1646
1647 break;
1648 case Error:
1649 FATAL("Error: Nyx runtime error has occurred...");
1650 break;
1651
1652 }
1653
1654 return FSRV_RUN_OK;
1655
1656 }
1657
1658 #endif
1659 /* After this memset, fsrv->trace_bits[] are effectively volatile, so we
1660 must prevent any earlier operations from venturing into that
1661 territory. */
1662
1663 #ifdef __linux__
1664 if (!fsrv->nyx_mode) {
1665
1666 memset(fsrv->trace_bits, 0, fsrv->map_size);
1667 MEM_BARRIER();
1668
1669 }
1670
1671 #else
1672 memset(fsrv->trace_bits, 0, fsrv->map_size);
1673 MEM_BARRIER();
1674 #endif
1675
1676 /* we have the fork server (or faux server) up and running
1677 First, tell it if the previous run timed out. */
1678
1679 if ((res = write(fsrv->fsrv_ctl_fd, &write_value, 4)) != 4) {
1680
1681 if (*stop_soon_p) { return 0; }
1682 RPFATAL(res, "Unable to request new process from fork server (OOM?)");
1683
1684 }
1685
1686 fsrv->last_run_timed_out = 0;
1687
1688 if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) {
1689
1690 if (*stop_soon_p) { return 0; }
1691 RPFATAL(res, "Unable to request new process from fork server (OOM?)");
1692
1693 }
1694
1695 #ifdef AFL_PERSISTENT_RECORD
1696 // end of persistent loop?
1697 if (unlikely(fsrv->persistent_record &&
1698 fsrv->persistent_record_pid != fsrv->child_pid)) {
1699
1700 fsrv->persistent_record_pid = fsrv->child_pid;
1701 u32 idx, val;
1702 if (unlikely(!fsrv->persistent_record_idx))
1703 idx = fsrv->persistent_record - 1;
1704 else
1705 idx = fsrv->persistent_record_idx - 1;
1706 val = fsrv->persistent_record_len[idx];
1707 memset((void *)fsrv->persistent_record_len, 0,
1708 fsrv->persistent_record * sizeof(u32));
1709 fsrv->persistent_record_len[idx] = val;
1710
1711 }
1712
1713 #endif
1714
1715 if (fsrv->child_pid <= 0) {
1716
1717 if (*stop_soon_p) { return 0; }
1718
1719 if ((fsrv->child_pid & FS_OPT_ERROR) &&
1720 FS_OPT_GET_ERROR(fsrv->child_pid) == FS_ERROR_SHM_OPEN)
1721 FATAL(
1722 "Target reported shared memory access failed (perhaps increase "
1723 "shared memory available).");
1724
1725 FATAL("Fork server is misbehaving (OOM?)");
1726
1727 }
1728
1729 exec_ms = read_s32_timed(fsrv->fsrv_st_fd, &fsrv->child_status, timeout,
1730 stop_soon_p);
1731
1732 if (exec_ms > timeout) {
1733
1734 /* If there was no response from forkserver after timeout seconds,
1735 we kill the child. The forkserver should inform us afterwards */
1736
1737 s32 tmp_pid = fsrv->child_pid;
1738 if (tmp_pid > 0) {
1739
1740 kill(tmp_pid, fsrv->child_kill_signal);
1741 fsrv->child_pid = -1;
1742
1743 }
1744
1745 fsrv->last_run_timed_out = 1;
1746 if (read(fsrv->fsrv_st_fd, &fsrv->child_status, 4) < 4) { exec_ms = 0; }
1747
1748 }
1749
1750 if (!exec_ms) {
1751
1752 if (*stop_soon_p) { return 0; }
1753 SAYF("\n" cLRD "[-] " cRST
1754 "Unable to communicate with fork server. Some possible reasons:\n\n"
1755 " - You've run out of memory. Use -m to increase the the memory "
1756 "limit\n"
1757 " to something higher than %llu.\n"
1758 " - The binary or one of the libraries it uses manages to "
1759 "create\n"
1760 " threads before the forkserver initializes.\n"
1761 " - The binary, at least in some circumstances, exits in a way "
1762 "that\n"
1763 " also kills the parent process - raise() could be the "
1764 "culprit.\n"
1765 " - If using persistent mode with QEMU, "
1766 "AFL_QEMU_PERSISTENT_ADDR "
1767 "is\n"
1768 " probably not valid (hint: add the base address in case of "
1769 "PIE)"
1770 "\n\n"
1771 "If all else fails you can disable the fork server via "
1772 "AFL_NO_FORKSRV=1.\n",
1773 fsrv->mem_limit);
1774 RPFATAL(res, "Unable to communicate with fork server");
1775
1776 }
1777
1778 if (!WIFSTOPPED(fsrv->child_status)) { fsrv->child_pid = -1; }
1779
1780 fsrv->total_execs++;
1781
1782 /* Any subsequent operations on fsrv->trace_bits must not be moved by the
1783 compiler below this point. Past this location, fsrv->trace_bits[]
1784 behave very normally and do not have to be treated as volatile. */
1785
1786 MEM_BARRIER();
1787
1788 /* Report outcome to caller. */
1789
1790 /* Was the run unsuccessful? */
1791 if (unlikely(*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG)) {
1792
1793 return FSRV_RUN_ERROR;
1794
1795 }
1796
1797 /* Did we timeout? */
1798 if (unlikely(fsrv->last_run_timed_out)) {
1799
1800 fsrv->last_kill_signal = fsrv->child_kill_signal;
1801 return FSRV_RUN_TMOUT;
1802
1803 }
1804
1805 /* Did we crash?
1806 In a normal case, (abort) WIFSIGNALED(child_status) will be set.
1807 MSAN in uses_asan mode uses a special exit code as it doesn't support
1808 abort_on_error. On top, a user may specify a custom AFL_CRASH_EXITCODE.
1809 Handle all three cases here. */
1810
1811 if (unlikely(
1812 /* A normal crash/abort */
1813 (WIFSIGNALED(fsrv->child_status)) ||
1814 /* special handling for msan and lsan */
1815 (fsrv->uses_asan &&
1816 (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR ||
1817 WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) ||
1818 /* the custom crash_exitcode was returned by the target */
1819 (fsrv->uses_crash_exitcode &&
1820 WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) {
1821
1822 #ifdef AFL_PERSISTENT_RECORD
1823 if (unlikely(fsrv->persistent_record)) {
1824
1825 char fn[PATH_MAX];
1826 u32 i, writecnt = 0;
1827 for (i = 0; i < fsrv->persistent_record; ++i) {
1828
1829 u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record;
1830 u8 *data = fsrv->persistent_record_data[entry];
1831 u32 len = fsrv->persistent_record_len[entry];
1832 if (likely(len && data)) {
1833
1834 snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u",
1835 fsrv->persistent_record_dir, fsrv->persistent_record_cnt,
1836 writecnt++);
1837 int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
1838 if (fd >= 0) {
1839
1840 ck_write(fd, data, len, fn);
1841 close(fd);
1842
1843 }
1844
1845 }
1846
1847 }
1848
1849 ++fsrv->persistent_record_cnt;
1850
1851 }
1852
1853 #endif
1854
1855 /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
1856 fsrv->last_kill_signal =
1857 WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
1858 return FSRV_RUN_CRASH;
1859
1860 }
1861
1862 /* success :) */
1863 return FSRV_RUN_OK;
1864
1865 }
1866
afl_fsrv_killall()1867 void afl_fsrv_killall() {
1868
1869 LIST_FOREACH(&fsrv_list, afl_forkserver_t, {
1870
1871 afl_fsrv_kill(el);
1872
1873 });
1874
1875 }
1876
afl_fsrv_deinit(afl_forkserver_t * fsrv)1877 void afl_fsrv_deinit(afl_forkserver_t *fsrv) {
1878
1879 afl_fsrv_kill(fsrv);
1880 list_remove(&fsrv_list, fsrv);
1881
1882 }
1883
1884