xref: /aosp_15_r20/external/AFLplusplus/src/afl-forkserver.c (revision 08b48e0b10e97b33e7b60c5b6e2243bd915777f2)
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