aboutsummaryrefslogtreecommitdiff
path: root/src/afl-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/afl-common.c')
-rw-r--r--src/afl-common.c226
1 files changed, 195 insertions, 31 deletions
diff --git a/src/afl-common.c b/src/afl-common.c
index eca7d272..84ddefd8 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -25,8 +25,13 @@
#include <stdlib.h>
#include <stdio.h>
-#define _GNU_SOURCE
-#define __USE_GNU
+#include "forkserver.h"
+#ifndef _GNU_SOURCE
+ #define _GNU_SOURCE
+#endif
+#ifndef __USE_GNU
+ #define __USE_GNU
+#endif
#include <string.h>
#include <strings.h>
#include <math.h>
@@ -43,6 +48,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <signal.h>
u8 be_quiet = 0;
u8 *doc_path = "";
@@ -52,6 +58,90 @@ u8 last_intr = 0;
#define AFL_PATH "/usr/local/lib/afl/"
#endif
+void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle,
+ size_t needlelen) {
+
+ if (unlikely(needlelen > haystacklen)) { return NULL; }
+
+ for (u32 i = 0; i <= haystacklen - needlelen; ++i) {
+
+ if (unlikely(memcmp(haystack + i, needle, needlelen) == 0)) {
+
+ return (void *)(haystack + i);
+
+ }
+
+ }
+
+ return (void *)NULL;
+
+}
+
+void set_sanitizer_defaults() {
+
+ /* Set sane defaults for ASAN if nothing else is specified. */
+ u8 *have_asan_options = getenv("ASAN_OPTIONS");
+ u8 *have_ubsan_options = getenv("UBSAN_OPTIONS");
+ u8 *have_msan_options = getenv("MSAN_OPTIONS");
+ u8 *have_lsan_options = getenv("LSAN_OPTIONS");
+ u8 have_san_options = 0;
+ u8 default_options[1024] =
+ "detect_odr_violation=0:abort_on_error=1:symbolize=0:allocator_may_"
+ "return_null=1:handle_segv=0:handle_sigbus=0:handle_abort=0:handle_"
+ "sigfpe=0:handle_sigill=0:";
+
+ if (have_asan_options || have_ubsan_options || have_msan_options ||
+ have_lsan_options) {
+
+ have_san_options = 1;
+
+ }
+
+ /* LSAN does not support abort_on_error=1. (is this still true??) */
+
+ if (!have_lsan_options) {
+
+ u8 buf[2048] = "";
+ if (!have_san_options) { strcpy(buf, default_options); }
+ strcat(buf, "exitcode=" STRINGIFY(LSAN_ERROR) ":fast_unwind_on_malloc=0:print_suppressions=0:detect_leaks=1:malloc_context_size=30:");
+ setenv("LSAN_OPTIONS", buf, 1);
+
+ }
+
+ /* for everything not LSAN we disable detect_leaks */
+
+ if (!have_lsan_options) {
+
+ strcat(default_options, "detect_leaks=0:malloc_context_size=0:");
+
+ }
+
+ /* Set sane defaults for ASAN if nothing else is specified. */
+
+ if (!have_san_options) { setenv("ASAN_OPTIONS", default_options, 1); }
+
+ /* Set sane defaults for UBSAN if nothing else is specified. */
+
+ if (!have_san_options) { setenv("UBSAN_OPTIONS", default_options, 1); }
+
+ /* MSAN is tricky, because it doesn't support abort_on_error=1 at this
+ point. So, we do this in a very hacky way. */
+
+ if (!have_msan_options) {
+
+ u8 buf[2048] = "";
+ if (!have_san_options) { strcpy(buf, default_options); }
+ strcat(buf, "exit_code=" STRINGIFY(MSAN_ERROR) ":msan_track_origins=0:");
+ setenv("MSAN_OPTIONS", buf, 1);
+
+ }
+
+ /* Envs for QASan */
+ setenv("QASAN_MAX_CALL_STACK", "0", 0);
+ setenv("QASAN_SYMBOLIZE", "0", 0);
+
+}
+
u32 check_binary_signatures(u8 *fn) {
int ret = 0, fd = open(fn, O_RDONLY);
@@ -63,7 +153,7 @@ u32 check_binary_signatures(u8 *fn) {
if (f_data == MAP_FAILED) { PFATAL("Unable to mmap file '%s'", fn); }
close(fd);
- if (memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
+ if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
if (!be_quiet) { OKF(cPIN "Persistent mode binary detected."); }
setenv(PERSIST_ENV_VAR, "1", 1);
@@ -88,7 +178,7 @@ u32 check_binary_signatures(u8 *fn) {
}
- if (memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
+ if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
if (!be_quiet) { OKF(cPIN "Deferred forkserver binary detected."); }
setenv(DEFER_ENV_VAR, "1", 1);
@@ -452,38 +542,57 @@ u8 *find_afl_binary(u8 *own_loc, u8 *fname) {
}
-/* Parses the kill signal environment variable, FATALs on error.
- If the env is not set, sets the env to default_signal for the signal handlers
- and returns the default_signal. */
-int parse_afl_kill_signal_env(u8 *afl_kill_signal_env, int default_signal) {
+int parse_afl_kill_signal(u8 *numeric_signal_as_str, int default_signal) {
- if (afl_kill_signal_env && afl_kill_signal_env[0]) {
+ if (numeric_signal_as_str && numeric_signal_as_str[0]) {
char *endptr;
u8 signal_code;
- signal_code = (u8)strtoul(afl_kill_signal_env, &endptr, 10);
+ signal_code = (u8)strtoul(numeric_signal_as_str, &endptr, 10);
/* Did we manage to parse the full string? */
- if (*endptr != '\0' || endptr == (char *)afl_kill_signal_env) {
+ if (*endptr != '\0' || endptr == (char *)numeric_signal_as_str) {
- FATAL("Invalid AFL_KILL_SIGNAL: %s (expected unsigned int)",
- afl_kill_signal_env);
+ FATAL("Invalid signal name: %s", numeric_signal_as_str);
+
+ } else {
+
+ return signal_code;
}
- return signal_code;
+ }
+
+ return default_signal;
- } else {
+}
- char *sigstr = alloc_printf("%d", default_signal);
- if (!sigstr) { FATAL("Failed to alloc mem for signal buf"); }
+void configure_afl_kill_signals(afl_forkserver_t *fsrv,
+ char *afl_kill_signal_env,
+ char *afl_fsrv_kill_signal_env,
+ int default_server_kill_signal) {
- /* Set the env for signal handler */
- setenv("AFL_KILL_SIGNAL", sigstr, 1);
- free(sigstr);
- return default_signal;
+ afl_kill_signal_env =
+ afl_kill_signal_env ? afl_kill_signal_env : getenv("AFL_KILL_SIGNAL");
+ afl_fsrv_kill_signal_env = afl_fsrv_kill_signal_env
+ ? afl_fsrv_kill_signal_env
+ : getenv("AFL_FORK_SERVER_KILL_SIGNAL");
+
+ fsrv->child_kill_signal = parse_afl_kill_signal(afl_kill_signal_env, SIGKILL);
+
+ if (afl_kill_signal_env && !afl_fsrv_kill_signal_env) {
+
+ /*
+ Set AFL_FORK_SERVER_KILL_SIGNAL to the value of AFL_KILL_SIGNAL for
+ backwards compatibility. However, if AFL_FORK_SERVER_KILL_SIGNAL is set, is
+ takes precedence.
+ */
+ afl_fsrv_kill_signal_env = afl_kill_signal_env;
}
+ fsrv->fsrv_kill_signal = parse_afl_kill_signal(afl_fsrv_kill_signal_env,
+ default_server_kill_signal);
+
}
static inline unsigned int helper_min3(unsigned int a, unsigned int b,
@@ -554,9 +663,9 @@ void print_suggested_envs(char *mispelled_env) {
for (j = 0; afl_environment_variables[j] != NULL; ++j) {
- char * afl_env = afl_environment_variables[j] + 4;
+ char *afl_env = afl_environment_variables[j] + 4;
size_t afl_env_len = strlen(afl_env);
- char * reduced = ck_alloc(afl_env_len + 1);
+ char *reduced = ck_alloc(afl_env_len + 1);
size_t start = 0;
while (start < afl_env_len) {
@@ -594,7 +703,7 @@ void print_suggested_envs(char *mispelled_env) {
if (found) goto cleanup;
- char * reduced = ck_alloc(env_name_len + 1);
+ char *reduced = ck_alloc(env_name_len + 1);
size_t start = 0;
while (start < env_name_len) {
@@ -715,17 +824,23 @@ char *get_afl_env(char *env) {
char *val;
- if ((val = getenv(env)) != NULL) {
+ if ((val = getenv(env))) {
- if (!be_quiet) {
+ if (*val) {
- OKF("Loaded environment variable %s with value %s", env, val);
+ if (!be_quiet) {
+
+ OKF("Enabled environment variable %s with value %s", env, val);
+
+ }
+
+ return val;
}
}
- return val;
+ return NULL;
}
@@ -834,7 +949,7 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) {
/* Get unix time in milliseconds */
-u64 get_cur_time(void) {
+inline u64 get_cur_time(void) {
struct timeval tv;
struct timezone tz;
@@ -1187,7 +1302,7 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
u32 get_map_size(void) {
uint32_t map_size = DEFAULT_SHMEM_SIZE;
- char * ptr;
+ char *ptr;
if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
@@ -1244,3 +1359,52 @@ s32 create_file(u8 *fn) {
}
+#ifdef __linux__
+
+/* Nyx requires a tmp workdir to access specific files (such as mmapped files,
+ * etc.). This helper function basically creates both a path to a tmp workdir
+ * and the workdir itself. If the environment variable TMPDIR is set, we use
+ * that as the base directory, otherwise we use /tmp. */
+char *create_nyx_tmp_workdir(void) {
+
+ char *tmpdir = getenv("TMPDIR");
+
+ if (!tmpdir) { tmpdir = "/tmp"; }
+
+ char *nyx_out_dir_path =
+ alloc_printf("%s/.nyx_tmp_%d/", tmpdir, (u32)getpid());
+
+ if (mkdir(nyx_out_dir_path, 0700)) { PFATAL("Unable to create nyx workdir"); }
+
+ return nyx_out_dir_path;
+
+}
+
+/* Vice versa, we remove the tmp workdir for nyx with this helper function. */
+void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char *nyx_out_dir_path) {
+
+ char *workdir_path = alloc_printf("%s/workdir", nyx_out_dir_path);
+
+ if (access(workdir_path, R_OK) == 0) {
+
+ if (fsrv->nyx_handlers->nyx_remove_work_dir(workdir_path) != true) {
+
+ WARNF("Unable to remove nyx workdir (%s)", workdir_path);
+
+ }
+
+ }
+
+ if (rmdir(nyx_out_dir_path)) {
+
+ WARNF("Unable to remove nyx workdir (%s)", nyx_out_dir_path);
+
+ }
+
+ ck_free(workdir_path);
+ ck_free(nyx_out_dir_path);
+
+}
+
+#endif
+